Brandon Goddard | 7ceb501 | 2020-07-09 19:36:57 | [diff] [blame] | 1 | // Copyright 2020 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 | |
| 5 | // Copyright (C) 2012 Google Inc. All rights reserved. |
| 6 | |
| 7 | // Redistribution and use in source and binary forms, with or without |
| 8 | // modification, are permitted provided that the following conditions |
| 9 | // are met: |
| 10 | |
| 11 | // 1. Redistributions of source code must retain the above copyright |
| 12 | // notice, this list of conditions and the following disclaimer. |
| 13 | // 2. Redistributions in binary form must reproduce the above copyright |
| 14 | // notice, this list of conditions and the following disclaimer in the |
| 15 | // documentation and/or other materials provided with the distribution. |
| 16 | // 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| 17 | // its contributors may be used to endorse or promote products derived |
| 18 | // from this software without specific prior written permission. |
| 19 | |
| 20 | // THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 21 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 22 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 23 | // DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 24 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 25 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 26 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 27 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 29 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
Jack Franklin | 3a80260 | 2022-07-13 08:39:42 | [diff] [blame] | 31 | import {Overlay, type ResetData} from './common.js'; |
| 32 | |
| 33 | import {DragResizeHandler, ResizerType, type Delegate} from './drag_resize_handler.js'; |
| 34 | |
| 35 | import {drawContainerQueryHighlight, type ContainerQueryHighlight} from './highlight_container_query.js'; |
| 36 | |
| 37 | import {drawLayoutFlexContainerHighlight, type FlexContainerHighlight} from './highlight_flex_common.js'; |
| 38 | |
| 39 | import {drawLayoutGridHighlight, type GridHighlight} from './highlight_grid_common.js'; |
| 40 | |
| 41 | import {drawIsolatedElementHighlight, type IsolatedElementHighlight} from './highlight_isolated_element.js'; |
| 42 | |
| 43 | import {drawScrollSnapHighlight, type ScrollSnapHighlight} from './highlight_scroll_snap.js'; |
Brandon Goddard | 7ceb501 | 2020-07-09 19:36:57 | [diff] [blame] | 44 | |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 45 | export type PersistentToolMessage = { |
| 46 | highlightType: string, |
| 47 | highlightIndex: number, |
| 48 | newWidth: string, |
| 49 | newHeight: string, |
| 50 | resizerType: ResizerType, |
| 51 | }; |
| 52 | |
| 53 | interface DraggableMetadata { |
| 54 | type: ResizerType; |
| 55 | highlightIndex: number; |
| 56 | initialWidth?: number; |
| 57 | initialHeight?: number; |
| 58 | } |
| 59 | |
| 60 | function makeDraggableDelegate(overlay: PersistentOverlay): Delegate { |
| 61 | return { |
| 62 | getDraggable: (x, y) => { |
| 63 | const result = overlay.isPointInDraggablePath(x, y); |
| 64 | if (!result) { |
| 65 | return; |
| 66 | } |
| 67 | |
| 68 | return { |
| 69 | type: result.type, |
| 70 | initialWidth: result.initialWidth, |
| 71 | initialHeight: result.initialHeight, |
| 72 | id: result.highlightIndex, |
| 73 | update: ({width, height}: {width?: number, height?: number}) => { |
| 74 | window.InspectorOverlayHost.send({ |
| 75 | highlightType: 'isolatedElement', |
| 76 | highlightIndex: result.highlightIndex, |
| 77 | newWidth: `${width}px`, |
| 78 | newHeight: `${height}px`, |
| 79 | resizerType: result.type, |
| 80 | }); |
| 81 | }, |
| 82 | }; |
| 83 | }, |
| 84 | }; |
| 85 | } |
| 86 | |
Alex Rudenko | c72157b | 2020-11-16 06:27:50 | [diff] [blame] | 87 | export class PersistentOverlay extends Overlay { |
Patrick Brosset | 2c4f3b9 | 2020-12-24 11:26:07 | [diff] [blame] | 88 | private gridLabelState = {gridLayerCounter: 0}; |
Alex Rudenko | 0593c96 | 2020-10-01 09:51:47 | [diff] [blame] | 89 | |
Alex Rudenko | c294d47 | 2020-10-02 07:07:49 | [diff] [blame] | 90 | private gridLabels!: HTMLElement; |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 91 | private draggableBorders: Map<number, { |
| 92 | widthPath: Path2D, |
| 93 | heightPath: Path2D, |
| 94 | bidirectionPath: Path2D, |
| 95 | highlightIndex: number, |
| 96 | initialWidth: number, |
| 97 | initialHeight: number, |
| 98 | }> = new Map(); |
| 99 | private dragHandler?: DragResizeHandler; |
Alex Rudenko | c294d47 | 2020-10-02 07:07:49 | [diff] [blame] | 100 | |
Randolf Jung | ffd1424 | 2023-04-19 00:32:25 | [diff] [blame] | 101 | override reset(data: ResetData) { |
Alex Rudenko | 0a2628e | 2020-10-28 10:38:41 | [diff] [blame] | 102 | super.reset(data); |
| 103 | this.gridLabelState.gridLayerCounter = 0; |
Alex Rudenko | f0eaca5 | 2020-11-12 07:19:30 | [diff] [blame] | 104 | this.gridLabels.innerHTML = ''; |
Alex Rudenko | 0a2628e | 2020-10-28 10:38:41 | [diff] [blame] | 105 | } |
| 106 | |
Alex Rudenko | 6dface0 | 2020-10-09 07:26:44 | [diff] [blame] | 107 | renderGridMarkup() { |
| 108 | const gridLabels = this.document.createElement('div'); |
| 109 | gridLabels.id = 'grid-label-container'; |
| 110 | this.document.body.append(gridLabels); |
| 111 | this.gridLabels = gridLabels; |
Alex Rudenko | c294d47 | 2020-10-02 07:07:49 | [diff] [blame] | 112 | } |
| 113 | |
Randolf Jung | ffd1424 | 2023-04-19 00:32:25 | [diff] [blame] | 114 | override install() { |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 115 | this.document.body.classList.add('fill'); |
Brandon Goddard | 7ceb501 | 2020-07-09 19:36:57 | [diff] [blame] | 116 | |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 117 | const canvas = this.document.createElement('canvas'); |
| 118 | canvas.id = 'canvas'; |
| 119 | canvas.classList.add('fill'); |
| 120 | this.document.body.append(canvas); |
Brandon Goddard | 7ceb501 | 2020-07-09 19:36:57 | [diff] [blame] | 121 | |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 122 | this.renderGridMarkup(); |
| 123 | |
| 124 | this.setCanvas(canvas); |
Alex Rudenko | 6dface0 | 2020-10-09 07:26:44 | [diff] [blame] | 125 | |
| 126 | super.install(); |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 127 | this.dragHandler?.install(); |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 128 | } |
| 129 | |
Randolf Jung | ffd1424 | 2023-04-19 00:32:25 | [diff] [blame] | 130 | override uninstall() { |
Alex Rudenko | 6dface0 | 2020-10-09 07:26:44 | [diff] [blame] | 131 | this.document.body.classList.remove('fill'); |
| 132 | this.document.body.innerHTML = ''; |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 133 | this.draggableBorders = new Map(); |
Alex Rudenko | 6dface0 | 2020-10-09 07:26:44 | [diff] [blame] | 134 | super.uninstall(); |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 135 | this.dragHandler?.uninstall(); |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 136 | } |
| 137 | |
Alex Rudenko | c294d47 | 2020-10-02 07:07:49 | [diff] [blame] | 138 | drawGridHighlight(highlight: GridHighlight) { |
| 139 | this.context.save(); |
| 140 | drawLayoutGridHighlight( |
| 141 | highlight, this.context, this.deviceScaleFactor, this.canvasWidth, this.canvasHeight, this.emulationScaleFactor, |
| 142 | this.gridLabelState); |
| 143 | this.context.restore(); |
Alex Rudenko | f4de8bf | 2020-09-28 13:23:06 | [diff] [blame] | 144 | } |
Alex Rudenko | 32ffa0c | 2020-11-18 06:27:18 | [diff] [blame] | 145 | |
| 146 | drawFlexContainerHighlight(highlight: FlexContainerHighlight) { |
| 147 | this.context.save(); |
| 148 | drawLayoutFlexContainerHighlight( |
| 149 | highlight, this.context, this.deviceScaleFactor, this.canvasWidth, this.canvasHeight, |
| 150 | this.emulationScaleFactor); |
| 151 | this.context.restore(); |
| 152 | } |
Alex Rudenko | e633829 | 2021-04-01 07:23:28 | [diff] [blame] | 153 | |
| 154 | drawScrollSnapHighlight(highlight: ScrollSnapHighlight) { |
| 155 | this.context.save(); |
| 156 | drawScrollSnapHighlight(highlight, this.context, this.emulationScaleFactor); |
| 157 | this.context.restore(); |
| 158 | } |
Changhao Han | 6f26329 | 2021-08-09 11:57:38 | [diff] [blame] | 159 | |
| 160 | drawContainerQueryHighlight(highlight: ContainerQueryHighlight) { |
| 161 | this.context.save(); |
| 162 | drawContainerQueryHighlight(highlight, this.context, this.emulationScaleFactor); |
| 163 | this.context.restore(); |
| 164 | } |
Changhao Han | 8709d85 | 2021-09-29 23:15:32 | [diff] [blame] | 165 | |
| 166 | drawIsolatedElementHighlight(highlight: IsolatedElementHighlight) { |
| 167 | if (!this.dragHandler) { |
| 168 | this.dragHandler = new DragResizeHandler(this.document, makeDraggableDelegate(this)); |
| 169 | this.dragHandler.install(); |
| 170 | } |
| 171 | |
| 172 | this.context.save(); |
| 173 | const {widthPath, heightPath, bidirectionPath, currentWidth, currentHeight, highlightIndex} = |
| 174 | drawIsolatedElementHighlight( |
| 175 | highlight, this.context, this.canvasWidth, this.canvasHeight, this.emulationScaleFactor); |
| 176 | |
| 177 | this.draggableBorders.set(highlightIndex, { |
| 178 | widthPath, |
| 179 | heightPath, |
| 180 | bidirectionPath, |
| 181 | highlightIndex, |
| 182 | initialWidth: currentWidth, |
| 183 | initialHeight: currentHeight, |
| 184 | }); |
| 185 | this.context.restore(); |
| 186 | } |
| 187 | |
| 188 | isPointInDraggablePath(x: number, y: number): DraggableMetadata|undefined { |
| 189 | for (const {widthPath, heightPath, bidirectionPath, highlightIndex, initialWidth, initialHeight} of this |
| 190 | .draggableBorders.values()) { |
| 191 | if (this.context.isPointInPath(widthPath, x, y)) { |
| 192 | return { |
| 193 | type: ResizerType.WIDTH, |
| 194 | highlightIndex, |
| 195 | initialWidth, |
| 196 | }; |
| 197 | } |
| 198 | if (this.context.isPointInPath(heightPath, x, y)) { |
| 199 | return { |
| 200 | type: ResizerType.HEIGHT, |
| 201 | highlightIndex, |
| 202 | initialHeight, |
| 203 | }; |
| 204 | } |
| 205 | if (this.context.isPointInPath(bidirectionPath, x, y)) { |
| 206 | return { |
| 207 | type: ResizerType.BIDIRECTION, |
| 208 | highlightIndex, |
| 209 | initialWidth, |
| 210 | initialHeight, |
| 211 | }; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | return; |
| 216 | } |
Brandon Goddard | 7ceb501 | 2020-07-09 19:36:57 | [diff] [blame] | 217 | } |