|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict"; |
|
5 |
|
6 var ZoomHelper = { |
|
7 zoomInAndSnapToRange: function(aRange) { |
|
8 // aRange is always non-null here, since a check happened previously. |
|
9 let viewport = BrowserApp.selectedTab.getViewport(); |
|
10 let fudge = 15; // Add a bit of fudge. |
|
11 let boundingElement = aRange.offsetNode; |
|
12 while (!boundingElement.getBoundingClientRect && boundingElement.parentNode) { |
|
13 boundingElement = boundingElement.parentNode; |
|
14 } |
|
15 |
|
16 let rect = ElementTouchHelper.getBoundingContentRect(boundingElement); |
|
17 let drRect = aRange.getClientRect(); |
|
18 let scrollTop = |
|
19 BrowserApp.selectedBrowser.contentDocument.documentElement.scrollTop || |
|
20 BrowserApp.selectedBrowser.contentDocument.body.scrollTop; |
|
21 |
|
22 // We subtract half the height of the viewport so that we can (ideally) |
|
23 // center the area of interest on the screen. |
|
24 let topPos = scrollTop + drRect.top - (viewport.cssHeight / 2.0); |
|
25 |
|
26 // Factor in the border and padding |
|
27 let boundingStyle = window.getComputedStyle(boundingElement); |
|
28 let leftAdjustment = parseInt(boundingStyle.paddingLeft) + |
|
29 parseInt(boundingStyle.borderLeftWidth); |
|
30 |
|
31 BrowserApp.selectedTab._mReflozPositioned = true; |
|
32 |
|
33 rect.type = "Browser:ZoomToRect"; |
|
34 rect.x = Math.max(viewport.cssPageLeft, rect.x - fudge + leftAdjustment); |
|
35 rect.y = Math.max(topPos, viewport.cssPageTop); |
|
36 rect.w = viewport.cssWidth; |
|
37 rect.h = viewport.cssHeight; |
|
38 rect.animate = false; |
|
39 |
|
40 sendMessageToJava(rect); |
|
41 BrowserApp.selectedTab._mReflozPoint = null; |
|
42 }, |
|
43 |
|
44 zoomOut: function() { |
|
45 BrowserEventHandler.resetMaxLineBoxWidth(); |
|
46 sendMessageToJava({ type: "Browser:ZoomToPageWidth" }); |
|
47 }, |
|
48 |
|
49 isRectZoomedIn: function(aRect, aViewport) { |
|
50 // This function checks to see if the area of the rect visible in the |
|
51 // viewport (i.e. the "overlapArea" variable below) is approximately |
|
52 // the max area of the rect we can show. It also checks that the rect |
|
53 // is actually on-screen by testing the left and right edges of the rect. |
|
54 // In effect, this tells us whether or not zooming in to this rect |
|
55 // will significantly change what the user is seeing. |
|
56 const minDifference = -20; |
|
57 const maxDifference = 20; |
|
58 const maxZoomAllowed = 4; // keep this in sync with mobile/android/base/ui/PanZoomController.MAX_ZOOM |
|
59 |
|
60 let vRect = new Rect(aViewport.cssX, aViewport.cssY, aViewport.cssWidth, aViewport.cssHeight); |
|
61 let overlap = vRect.intersect(aRect); |
|
62 let overlapArea = overlap.width * overlap.height; |
|
63 let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height); |
|
64 let showing = overlapArea / (aRect.width * availHeight); |
|
65 let dw = (aRect.width - vRect.width); |
|
66 let dx = (aRect.x - vRect.x); |
|
67 |
|
68 if (fuzzyEquals(aViewport.zoom, maxZoomAllowed) && overlap.width / aRect.width > 0.9) { |
|
69 // we're already at the max zoom and the block is not spilling off the side of the screen so that even |
|
70 // if the block isn't taking up most of the viewport we can't pan/zoom in any more. return true so that we zoom out |
|
71 return true; |
|
72 } |
|
73 |
|
74 return (showing > 0.9 && |
|
75 dx > minDifference && dx < maxDifference && |
|
76 dw > minDifference && dw < maxDifference); |
|
77 }, |
|
78 |
|
79 /* Zoom to an element, optionally keeping a particular part of it |
|
80 * in view if it is really tall. |
|
81 */ |
|
82 zoomToElement: function(aElement, aClickY = -1, aCanZoomOut = true, aCanScrollHorizontally = true) { |
|
83 let rect = ElementTouchHelper.getBoundingContentRect(aElement); |
|
84 ZoomHelper.zoomToRect(rect, aClickY, aCanZoomOut, aCanScrollHorizontally, aElement); |
|
85 }, |
|
86 |
|
87 zoomToRect: function(aRect, aClickY = -1, aCanZoomOut = true, aCanScrollHorizontally = true, aElement) { |
|
88 const margin = 15; |
|
89 |
|
90 if(!aRect.h || !aRect.w) { |
|
91 aRect.h = aRect.height; |
|
92 aRect.w = aRect.width; |
|
93 } |
|
94 |
|
95 let viewport = BrowserApp.selectedTab.getViewport(); |
|
96 let bRect = new Rect(aCanScrollHorizontally ? Math.max(viewport.cssPageLeft, aRect.x - margin) : viewport.cssX, |
|
97 aRect.y, |
|
98 aCanScrollHorizontally ? aRect.w + 2 * margin : viewport.cssWidth, |
|
99 aRect.h); |
|
100 // constrict the rect to the screen's right edge |
|
101 bRect.width = Math.min(bRect.width, viewport.cssPageRight - bRect.x); |
|
102 |
|
103 // if the rect is already taking up most of the visible area and is stretching the |
|
104 // width of the page, then we want to zoom out instead. |
|
105 if (aElement) { |
|
106 if (BrowserEventHandler.mReflozPref) { |
|
107 let zoomFactor = BrowserApp.selectedTab.getZoomToMinFontSize(aElement); |
|
108 |
|
109 bRect.width = zoomFactor <= 1.0 ? bRect.width : gScreenWidth / zoomFactor; |
|
110 bRect.height = zoomFactor <= 1.0 ? bRect.height : bRect.height / zoomFactor; |
|
111 if (zoomFactor == 1.0 || ZoomHelper.isRectZoomedIn(bRect, viewport)) { |
|
112 if (aCanZoomOut) { |
|
113 ZoomHelper.zoomOut(); |
|
114 } |
|
115 return; |
|
116 } |
|
117 } else if (ZoomHelper.isRectZoomedIn(bRect, viewport)) { |
|
118 if (aCanZoomOut) { |
|
119 ZoomHelper.zoomOut(); |
|
120 } |
|
121 return; |
|
122 } |
|
123 } |
|
124 |
|
125 let rect = {}; |
|
126 |
|
127 rect.type = "Browser:ZoomToRect"; |
|
128 rect.x = bRect.x; |
|
129 rect.y = bRect.y; |
|
130 rect.w = bRect.width; |
|
131 rect.h = Math.min(bRect.width * viewport.cssHeight / viewport.cssWidth, bRect.height); |
|
132 |
|
133 if (aClickY >= 0) { |
|
134 // if the block we're zooming to is really tall, and we want to keep a particular |
|
135 // part of it in view, then adjust the y-coordinate of the target rect accordingly. |
|
136 // the 1.2 multiplier is just a little fuzz to compensate for bRect including horizontal |
|
137 // margins but not vertical ones. |
|
138 let cssTapY = viewport.cssY + aClickY; |
|
139 if ((bRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) { |
|
140 rect.y = cssTapY - (rect.h / 2); |
|
141 } |
|
142 } |
|
143 |
|
144 if (rect.w > viewport.cssWidth || rect.h > viewport.cssHeight) { |
|
145 BrowserEventHandler.resetMaxLineBoxWidth(); |
|
146 } |
|
147 |
|
148 sendMessageToJava(rect); |
|
149 }, |
|
150 }; |