[go: nahoru, domu]

blob: 1c789b1004cb65077ae8f13c94f0ec01a5d7c6f0 [file] [log] [blame]
Alex Rudenkoc294d472020-10-02 07:07:491// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Patrick Brosset5282f412020-11-13 16:32:095export type PathCommands = Array<string|number>;
6
7export interface Quad {
8 p1: Position;
9 p2: Position;
10 p3: Position;
11 p4: Position;
12}
13
Alex Rudenkoc294d472020-10-02 07:07:4914export interface Position {
15 x: number;
16 y: number;
17}
18
19export interface Bounds {
20 minX: number;
21 maxX: number;
22 minY: number;
23 maxY: number;
24 width?: number;
25 height?: number;
26 allPoints: Position[];
27}
28
29export interface AreaBounds {
30 name: string;
31 bounds: {allPoints: Position[]};
32}
33
34interface ViewportSize {
35 width: number;
36 height: number;
37}
38
39export interface ResetData {
40 viewportSize: ViewportSize;
Alex Rudenkoc30660f2021-09-13 11:45:3041 viewportSizeForMediaQueries?: ViewportSize;
Alex Rudenkoc294d472020-10-02 07:07:4942 deviceScaleFactor: number;
43 pageScaleFactor: number;
44 pageZoomFactor: number;
45 emulationScaleFactor: number;
46 scrollX: number;
47 scrollY: number;
48}
49
50// Overlay class should be used to implement various tools and provide
51// access to globals via the window object it receives in the constructor.
52// Old logic is kept temporarily while the tools are being migrated.
53export class Overlay {
54 protected viewportSize = {width: 800, height: 600};
Alex Rudenkoc30660f2021-09-13 11:45:3055 protected viewportSizeForMediaQueries?: ViewportSize;
Alex Rudenkoc294d472020-10-02 07:07:4956 protected deviceScaleFactor = 1;
57 protected emulationScaleFactor = 1;
58 protected pageScaleFactor = 1;
59 protected pageZoomFactor = 1;
60 protected scrollX = 0;
61 protected scrollY = 0;
62 protected style: CSSStyleSheet[];
63 protected canvas?: HTMLCanvasElement;
64 protected canvasWidth: number = 0;
65 protected canvasHeight: number = 0;
66 protected platform?: string;
Sigurd Schneider4b024d22021-02-15 13:27:0367 // eslint-disable-next-line @typescript-eslint/naming-convention
Alex Rudenkoc294d472020-10-02 07:07:4968 private _window?: Window;
Sigurd Schneider4b024d22021-02-15 13:27:0369 // eslint-disable-next-line @typescript-eslint/naming-convention
Alex Rudenkoc294d472020-10-02 07:07:4970 private _document?: Document;
Sigurd Schneider4b024d22021-02-15 13:27:0371 // eslint-disable-next-line @typescript-eslint/naming-convention
Alex Rudenkoc294d472020-10-02 07:07:4972 private _context?: CanvasRenderingContext2D|null;
Sigurd Schneider4b024d22021-02-15 13:27:0373 // eslint-disable-next-line @typescript-eslint/naming-convention
Alex Rudenko6dface02020-10-09 07:26:4474 private _installed = false;
Alex Rudenkoc294d472020-10-02 07:07:4975
76 constructor(window: Window, style: CSSStyleSheet[] = []) {
77 this._window = window;
78 this._document = window.document;
79 if (!Array.isArray(style)) {
80 style = [style];
81 }
82 this.style = style;
83 }
84
85 setCanvas(canvas: HTMLCanvasElement) {
86 this.canvas = canvas;
87 this._context = canvas.getContext('2d');
88 }
89
Alex Rudenko6dface02020-10-09 07:26:4490 install() {
91 for (const style of this.style) {
92 adoptStyleSheet(style);
93 }
94 this._installed = true;
95 }
96
97 uninstall() {
98 for (const style of this.style) {
99 document.adoptedStyleSheets = document.adoptedStyleSheets.filter(s => s !== style);
100 }
101 this._installed = false;
102 }
103
Alex Rudenkoc294d472020-10-02 07:07:49104 reset(resetData?: ResetData) {
105 if (resetData) {
106 this.viewportSize = resetData.viewportSize;
Alex Rudenkoc30660f2021-09-13 11:45:30107 this.viewportSizeForMediaQueries = resetData.viewportSizeForMediaQueries;
Alex Rudenkoc294d472020-10-02 07:07:49108 this.deviceScaleFactor = resetData.deviceScaleFactor;
109 this.pageScaleFactor = resetData.pageScaleFactor;
110 this.pageZoomFactor = resetData.pageZoomFactor;
111 this.emulationScaleFactor = resetData.emulationScaleFactor;
112 this.scrollX = Math.round(resetData.scrollX);
113 this.scrollY = Math.round(resetData.scrollY);
114 }
115 this.resetCanvas();
116 }
117
118 resetCanvas() {
119 if (!this.canvas || !this._context) {
120 return;
121 }
122
123 this.canvas.width = this.deviceScaleFactor * this.viewportSize.width;
124 this.canvas.height = this.deviceScaleFactor * this.viewportSize.height;
125 this.canvas.style.width = this.viewportSize.width + 'px';
126 this.canvas.style.height = this.viewportSize.height + 'px';
127
128 this._context.scale(this.deviceScaleFactor, this.deviceScaleFactor);
129
130 this.canvasWidth = this.viewportSize.width;
131 this.canvasHeight = this.viewportSize.height;
132 }
133
134 setPlatform(platform: string) {
Alex Rudenkoc294d472020-10-02 07:07:49135 this.platform = platform;
136 this.document.body.classList.add('platform-' + platform);
Alex Rudenko6dface02020-10-09 07:26:44137 if (!this._installed) {
138 this.install();
139 }
Alex Rudenkoc294d472020-10-02 07:07:49140 }
141
142 dispatch(message: unknown[]) {
143 const functionName = message.shift() as string;
144 // eslint-disable-next-line @typescript-eslint/no-explicit-any
145 (this as any)[functionName].apply(this, message);
146 }
147
148 eventHasCtrlOrMeta(event: KeyboardEvent) {
149 return this.platform === 'mac' ? (event.metaKey && !event.ctrlKey) : (event.ctrlKey && !event.metaKey);
150 }
151
152 get context(): CanvasRenderingContext2D {
153 if (!this._context) {
154 throw new Error('Context object is missing');
155 }
156 return this._context;
157 }
158
159 get document(): Document {
160 if (!this._document) {
161 throw new Error('Document object is missing');
162 }
163 return this._document;
164 }
165
166 get window(): Window {
167 if (!this._window) {
168 throw new Error('Window object is missing');
169 }
170 return this._window;
171 }
Alex Rudenko6dface02020-10-09 07:26:44172
173 get installed(): boolean {
174 return this._installed;
175 }
Alex Rudenkoc294d472020-10-02 07:07:49176}
177
178export function log(text: string) {
179 let element = document.getElementById('log');
180 if (!element) {
181 element = createChild(document.body, 'div');
182 element.id = 'log';
183 }
184 createChild(element, 'div').textContent = text;
185}
186
187export function createChild(parent: HTMLElement, tagName: string, className?: string): HTMLElement {
188 const element = createElement(tagName, className);
189 element.addEventListener('click', function(e: Event) {
190 e.stopPropagation();
191 }, false);
192 parent.appendChild(element);
193 return element;
194}
195
196export function createTextChild(parent: HTMLElement, text: string): Text {
197 const element = document.createTextNode(text);
198 parent.appendChild(element);
199 return element;
200}
201
202export function createElement(tagName: string, className?: string) {
203 const element = document.createElement(tagName);
204 if (className) {
205 element.className = className;
206 }
207 return element;
208}
209
210export function ellipsify(str: string, maxLength: number) {
211 if (str.length <= maxLength) {
212 return String(str);
213 }
214 return str.substr(0, maxLength - 1) + '\u2026';
215}
216
217export function constrainNumber(num: number, min: number, max: number): number {
218 if (num < min) {
219 num = min;
220 } else if (num > max) {
221 num = max;
222 }
223 return num;
224}
225
226declare global {
Tim van der Lippe75c2c9c2020-12-01 12:50:53227 // eslint-disable-next-line @typescript-eslint/no-unused-vars
Alex Rudenkoc294d472020-10-02 07:07:49228 interface Document {
229 adoptedStyleSheets: CSSStyleSheet[];
230 }
231}
232
233export function adoptStyleSheet(styleSheet: CSSStyleSheet) {
234 document.adoptedStyleSheets = [...document.adoptedStyleSheets, styleSheet];
235}