OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 #include "core/layout/LayoutObject.h" | 47 #include "core/layout/LayoutObject.h" |
48 #include "core/loader/DocumentLoader.h" | 48 #include "core/loader/DocumentLoader.h" |
49 #include "core/loader/FrameLoader.h" | 49 #include "core/loader/FrameLoader.h" |
50 #include "core/loader/FrameLoaderClient.h" | 50 #include "core/loader/FrameLoaderClient.h" |
51 #include "platform/HostWindow.h" | 51 #include "platform/HostWindow.h" |
52 #include "wtf/text/StringBuilder.h" | 52 #include "wtf/text/StringBuilder.h" |
53 #include <limits> | 53 #include <limits> |
54 | 54 |
55 using namespace std; | 55 using namespace std; |
56 | 56 |
57 namespace { | |
58 | |
59 // The base square size is set to 10 because it rounds nicely for both the | |
60 // minimum scale (0.1) and maximum scale (5.0). | |
61 int gBaseCheckerSize = 10; | |
pdr.
2016/11/02 22:54:49
Nit: since this is a constant, wdyt of:
const int
gone
2016/11/03 01:28:41
Ah forgot what the proper syntax was here. Done.
| |
62 | |
63 } // namespace | |
64 | |
57 namespace blink { | 65 namespace blink { |
58 | 66 |
59 using namespace HTMLNames; | 67 using namespace HTMLNames; |
60 | 68 |
61 class ImageEventListener : public EventListener { | 69 class ImageEventListener : public EventListener { |
62 public: | 70 public: |
63 static ImageEventListener* create(ImageDocument* document) { | 71 static ImageEventListener* create(ImageDocument* document) { |
64 return new ImageEventListener(document); | 72 return new ImageEventListener(document); |
65 } | 73 } |
66 static const ImageEventListener* cast(const EventListener* listener) { | 74 static const ImageEventListener* cast(const EventListener* listener) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
116 result.append(" ("); | 124 result.append(" ("); |
117 // FIXME: Localize numbers. Safari/OSX shows localized numbers with group | 125 // FIXME: Localize numbers. Safari/OSX shows localized numbers with group |
118 // separaters. For example, "1,920x1,080". | 126 // separaters. For example, "1,920x1,080". |
119 result.appendNumber(size.width()); | 127 result.appendNumber(size.width()); |
120 result.append(static_cast<UChar>(0xD7)); // U+00D7 (multiplication sign) | 128 result.append(static_cast<UChar>(0xD7)); // U+00D7 (multiplication sign) |
121 result.appendNumber(size.height()); | 129 result.appendNumber(size.height()); |
122 result.append(')'); | 130 result.append(')'); |
123 return result.toString(); | 131 return result.toString(); |
124 } | 132 } |
125 | 133 |
134 static LayoutSize cachedImageSize(HTMLImageElement* element) { | |
135 DCHECK(element->cachedImage()); | |
136 return element->cachedImage()->imageSize( | |
137 LayoutObject::shouldRespectImageOrientation(element->layoutObject()), | |
138 1.0f); | |
139 } | |
140 | |
126 void ImageDocumentParser::appendBytes(const char* data, size_t length) { | 141 void ImageDocumentParser::appendBytes(const char* data, size_t length) { |
127 if (!length) | 142 if (!length) |
128 return; | 143 return; |
129 | 144 |
130 LocalFrame* frame = document()->frame(); | 145 LocalFrame* frame = document()->frame(); |
131 Settings* settings = frame->settings(); | 146 Settings* settings = frame->settings(); |
132 if (!frame->loader().client()->allowImage( | 147 if (!frame->loader().client()->allowImage( |
133 !settings || settings->imagesEnabled(), document()->url())) | 148 !settings || settings->imagesEnabled(), document()->url())) |
134 return; | 149 return; |
135 | 150 |
(...skipping 12 matching lines...) Expand all Loading... | |
148 void ImageDocumentParser::finish() { | 163 void ImageDocumentParser::finish() { |
149 if (!isStopped() && document()->imageElement() && document()->cachedImage()) { | 164 if (!isStopped() && document()->imageElement() && document()->cachedImage()) { |
150 ImageResource* cachedImage = document()->cachedImage(); | 165 ImageResource* cachedImage = document()->cachedImage(); |
151 DocumentLoader* loader = document()->loader(); | 166 DocumentLoader* loader = document()->loader(); |
152 cachedImage->setResponse(loader->response()); | 167 cachedImage->setResponse(loader->response()); |
153 cachedImage->finish(loader->timing().responseEnd()); | 168 cachedImage->finish(loader->timing().responseEnd()); |
154 | 169 |
155 // Report the natural image size in the page title, regardless of zoom | 170 // Report the natural image size in the page title, regardless of zoom |
156 // level. At a zoom level of 1 the image is guaranteed to have an integer | 171 // level. At a zoom level of 1 the image is guaranteed to have an integer |
157 // size. | 172 // size. |
158 IntSize size = flooredIntSize( | 173 IntSize size = flooredIntSize(cachedImageSize(document()->imageElement())); |
159 cachedImage->imageSize(LayoutObject::shouldRespectImageOrientation( | |
160 document()->imageElement()->layoutObject()), | |
161 1.0f)); | |
162 if (size.width()) { | 174 if (size.width()) { |
163 // Compute the title, we use the decoded filename of the resource, falling | 175 // Compute the title, we use the decoded filename of the resource, falling |
164 // back on the (decoded) hostname if there is no path. | 176 // back on the (decoded) hostname if there is no path. |
165 String fileName = | 177 String fileName = |
166 decodeURLEscapeSequences(document()->url().lastPathComponent()); | 178 decodeURLEscapeSequences(document()->url().lastPathComponent()); |
167 if (fileName.isEmpty()) | 179 if (fileName.isEmpty()) |
168 fileName = document()->url().host(); | 180 fileName = document()->url().host(); |
169 document()->setTitle(imageTitle(fileName, size)); | 181 document()->setTitle(imageTitle(fileName, size)); |
170 if (isDetached()) | 182 if (isDetached()) |
171 return; | 183 return; |
172 } | 184 } |
173 | 185 |
174 document()->imageUpdated(); | 186 document()->imageUpdated(); |
187 document()->imageLoaded(); | |
175 } | 188 } |
176 | 189 |
177 if (!isDetached()) | 190 if (!isDetached()) |
178 document()->finishedParsing(); | 191 document()->finishedParsing(); |
179 } | 192 } |
180 | 193 |
181 // -------- | 194 // -------- |
182 | 195 |
183 ImageDocument::ImageDocument(const DocumentInit& initializer) | 196 ImageDocument::ImageDocument(const DocumentInit& initializer) |
184 : HTMLDocument(initializer, ImageDocumentClass), | 197 : HTMLDocument(initializer, ImageDocumentClass), |
185 m_divElement(nullptr), | 198 m_divElement(nullptr), |
186 m_imageElement(nullptr), | 199 m_imageElement(nullptr), |
187 m_imageSizeIsKnown(false), | 200 m_imageSizeIsKnown(false), |
188 m_didShrinkImage(false), | 201 m_didShrinkImage(false), |
189 m_shouldShrinkImage(shouldShrinkToFit()), | 202 m_shouldShrinkImage(shouldShrinkToFit()), |
203 m_imageIsLoaded(false), | |
204 m_checkerSize(gBaseCheckerSize), | |
190 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport | 205 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport |
191 : Desktop) { | 206 : Desktop) { |
192 setCompatibilityMode(QuirksMode); | 207 setCompatibilityMode(QuirksMode); |
193 lockCompatibilityMode(); | 208 lockCompatibilityMode(); |
194 UseCounter::count(*this, UseCounter::ImageDocument); | 209 UseCounter::count(*this, UseCounter::ImageDocument); |
195 if (!isInMainFrame()) | 210 if (!isInMainFrame()) |
196 UseCounter::count(*this, UseCounter::ImageDocumentInFrame); | 211 UseCounter::count(*this, UseCounter::ImageDocumentInFrame); |
197 } | 212 } |
198 | 213 |
199 DocumentParser* ImageDocument::createParser() { | 214 DocumentParser* ImageDocument::createParser() { |
(...skipping 11 matching lines...) Expand all Loading... | |
211 HTMLHeadElement* head = HTMLHeadElement::create(*this); | 226 HTMLHeadElement* head = HTMLHeadElement::create(*this); |
212 HTMLMetaElement* meta = HTMLMetaElement::create(*this); | 227 HTMLMetaElement* meta = HTMLMetaElement::create(*this); |
213 meta->setAttribute(nameAttr, "viewport"); | 228 meta->setAttribute(nameAttr, "viewport"); |
214 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); | 229 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); |
215 head->appendChild(meta); | 230 head->appendChild(meta); |
216 | 231 |
217 HTMLBodyElement* body = HTMLBodyElement::create(*this); | 232 HTMLBodyElement* body = HTMLBodyElement::create(*this); |
218 | 233 |
219 if (shouldShrinkToFit()) { | 234 if (shouldShrinkToFit()) { |
220 // Display the image prominently centered in the frame. | 235 // Display the image prominently centered in the frame. |
221 body->setAttribute(styleAttr, "margin: 0px;"); | 236 body->setAttribute(styleAttr, "margin: 0px; background: #0e0e0e;"); |
222 | 237 |
223 // See w3c example on how to centering an element: | 238 // See w3c example on how to center an element: |
224 // https://www.w3.org/Style/Examples/007/center.en.html | 239 // https://www.w3.org/Style/Examples/007/center.en.html |
225 m_divElement = HTMLDivElement::create(*this); | 240 m_divElement = HTMLDivElement::create(*this); |
226 m_divElement->setAttribute(styleAttr, | 241 m_divElement->setAttribute(styleAttr, |
227 "display: flex;" | 242 "display: flex;" |
228 "flex-direction: column;" | 243 "flex-direction: column;" |
229 "justify-content: center;" | 244 "justify-content: center;" |
230 "align-items: center;" | 245 "align-items: center;" |
231 "min-height: min-content;" | 246 "min-height: min-content;" |
232 "min-width: min-content;" | 247 "min-width: min-content;" |
233 "height: 100%;" | 248 "height: 100%;" |
234 "width: 100%;"); | 249 "width: 100%;"); |
235 HTMLContentElement* content = HTMLContentElement::create(*this); | 250 HTMLContentElement* content = HTMLContentElement::create(*this); |
236 m_divElement->appendChild(content); | 251 m_divElement->appendChild(content); |
237 | 252 |
238 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); | 253 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); |
239 shadowRoot.appendChild(m_divElement); | 254 shadowRoot.appendChild(m_divElement); |
240 } else { | 255 } else { |
241 body->setAttribute(styleAttr, "margin: 0px;"); | 256 body->setAttribute(styleAttr, "margin: 0px;"); |
242 } | 257 } |
243 | 258 |
244 willInsertBody(); | 259 willInsertBody(); |
245 | 260 |
246 StringBuilder imageStyle; | |
247 imageStyle.append("-webkit-user-select: none;"); | |
248 if (shouldShrinkToFit() && m_shrinkToFitMode == Viewport) | |
249 imageStyle.append("max-width: 100%"); | |
250 m_imageElement = HTMLImageElement::create(*this); | 261 m_imageElement = HTMLImageElement::create(*this); |
251 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); | 262 updateImageStyle(); |
252 m_imageElement->setLoadingImageDocument(); | 263 m_imageElement->setLoadingImageDocument(); |
253 m_imageElement->setSrc(url().getString()); | 264 m_imageElement->setSrc(url().getString()); |
254 body->appendChild(m_imageElement.get()); | 265 body->appendChild(m_imageElement.get()); |
255 if (loader() && m_imageElement->cachedImage()) | 266 if (loader() && m_imageElement->cachedImage()) |
256 m_imageElement->cachedImage()->responseReceived(loader()->response(), | 267 m_imageElement->cachedImage()->responseReceived(loader()->response(), |
257 nullptr); | 268 nullptr); |
258 | 269 |
259 if (shouldShrinkToFit()) { | 270 if (shouldShrinkToFit()) { |
260 // Add event listeners | 271 // Add event listeners |
261 EventListener* listener = ImageEventListener::create(this); | 272 EventListener* listener = ImageEventListener::create(this); |
262 if (LocalDOMWindow* domWindow = this->domWindow()) | 273 if (LocalDOMWindow* domWindow = this->domWindow()) |
263 domWindow->addEventListener("resize", listener, false); | 274 domWindow->addEventListener(EventTypeNames::resize, listener, false); |
264 if (m_shrinkToFitMode == Desktop) | 275 |
265 m_imageElement->addEventListener("click", listener, false); | 276 if (m_shrinkToFitMode == Desktop) { |
277 m_imageElement->addEventListener(EventTypeNames::click, listener, false); | |
278 } else if (m_shrinkToFitMode == Viewport) { | |
279 m_imageElement->addEventListener(EventTypeNames::touchend, listener, | |
280 false); | |
281 m_imageElement->addEventListener(EventTypeNames::touchcancel, listener, | |
282 false); | |
283 } | |
266 } | 284 } |
267 | 285 |
268 rootElement->appendChild(head); | 286 rootElement->appendChild(head); |
269 rootElement->appendChild(body); | 287 rootElement->appendChild(body); |
270 } | 288 } |
271 | 289 |
272 float ImageDocument::scale() const { | 290 float ImageDocument::scale() const { |
273 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 291 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
274 if (!m_imageElement || m_imageElement->document() != this) | 292 if (!m_imageElement || m_imageElement->document() != this) |
275 return 1.0f; | 293 return 1.0f; |
(...skipping 18 matching lines...) Expand all Loading... | |
294 view->height() * manualZoom / imageSize.height().toFloat(); | 312 view->height() * manualZoom / imageSize.height().toFloat(); |
295 | 313 |
296 return min(widthScale, heightScale); | 314 return min(widthScale, heightScale); |
297 } | 315 } |
298 | 316 |
299 void ImageDocument::resizeImageToFit() { | 317 void ImageDocument::resizeImageToFit() { |
300 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 318 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
301 if (!m_imageElement || m_imageElement->document() != this) | 319 if (!m_imageElement || m_imageElement->document() != this) |
302 return; | 320 return; |
303 | 321 |
304 DCHECK(m_imageElement->cachedImage()); | 322 LayoutSize imageSize = cachedImageSize(m_imageElement); |
305 LayoutSize imageSize = m_imageElement->cachedImage()->imageSize( | |
306 LayoutObject::shouldRespectImageOrientation( | |
307 m_imageElement->layoutObject()), | |
308 1.f); | |
309 | 323 |
310 const float scale = this->scale(); | 324 const float scale = this->scale(); |
311 m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale)); | 325 m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale)); |
312 m_imageElement->setHeight(static_cast<int>(imageSize.height() * scale)); | 326 m_imageElement->setHeight(static_cast<int>(imageSize.height() * scale)); |
313 | 327 |
314 m_imageElement->setInlineStyleProperty(CSSPropertyCursor, CSSValueZoomIn); | 328 m_imageElement->setInlineStyleProperty(CSSPropertyCursor, CSSValueZoomIn); |
315 } | 329 } |
316 | 330 |
317 void ImageDocument::imageClicked(int x, int y) { | 331 void ImageDocument::imageClicked(int x, int y) { |
318 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 332 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
(...skipping 20 matching lines...) Expand all Loading... | |
339 float scrollX = | 353 float scrollX = |
340 imageX / scale - static_cast<float>(frame()->view()->width()) / 2; | 354 imageX / scale - static_cast<float>(frame()->view()->width()) / 2; |
341 float scrollY = | 355 float scrollY = |
342 imageY / scale - static_cast<float>(frame()->view()->height()) / 2; | 356 imageY / scale - static_cast<float>(frame()->view()->height()) / 2; |
343 | 357 |
344 frame()->view()->layoutViewportScrollableArea()->setScrollOffset( | 358 frame()->view()->layoutViewportScrollableArea()->setScrollOffset( |
345 ScrollOffset(scrollX, scrollY), ProgrammaticScroll); | 359 ScrollOffset(scrollX, scrollY), ProgrammaticScroll); |
346 } | 360 } |
347 } | 361 } |
348 | 362 |
363 void ImageDocument::imageLoaded() { | |
364 if (!shouldShrinkToFit()) | |
365 return; | |
366 | |
367 int checkerSize = gBaseCheckerSize; | |
368 if (m_shrinkToFitMode == Viewport) { | |
369 int viewportWidth = frame()->host()->visualViewport().size().width(); | |
370 checkerSize = static_cast<int>(gBaseCheckerSize * | |
371 (double)calculateDivWidth() / viewportWidth); | |
372 } | |
373 m_checkerSize = checkerSize; | |
374 | |
375 m_imageIsLoaded = true; | |
376 updateImageStyle(); | |
377 } | |
378 | |
379 void ImageDocument::updateImageStyle() { | |
380 StringBuilder imageStyle; | |
381 imageStyle.append("-webkit-user-select: none;"); | |
382 if (shouldShrinkToFit()) { | |
383 if (m_shrinkToFitMode == Viewport) { | |
384 imageStyle.append("max-width: 100%;"); | |
385 } | |
386 | |
387 // Once the image has fully loaded, it is displayed atop a checkerboard to | |
388 // show transparency more faithfully. The pattern is generated via CSS. | |
389 if (m_imageIsLoaded) { | |
390 if (m_shrinkToFitMode == Viewport && hasFinishedParsing()) { | |
391 double newCheckerSize = gBaseCheckerSize; | |
pdr.
2016/11/02 22:54:49
I think your new approach here is reasonable.
| |
392 if (m_shrinkToFitMode == Viewport) { | |
393 // To ensure the checker pattern is visible for large images in | |
394 // viewports, the checker size is dynamically adjusted to account for | |
395 // how much the page is currently being scaled. | |
396 double scale = frame()->host()->visualViewport().scale(); | |
397 newCheckerSize = std::max(1.0, newCheckerSize / scale); | |
398 } | |
399 | |
400 m_checkerSize = static_cast<int>(round(newCheckerSize)); | |
pdr.
2016/11/02 22:54:49
Nit: just "m_checkerSize = round(newCheckerSize);"
gone
2016/11/03 01:28:41
Done.
| |
401 } | |
402 | |
403 imageStyle.append("background-position: 0px 0px, "); | |
404 imageStyle.append(AtomicString::number(m_checkerSize)); | |
405 imageStyle.append("px "); | |
406 imageStyle.append(AtomicString::number(m_checkerSize)); | |
407 imageStyle.append("px;"); | |
408 | |
409 int tileSize = m_checkerSize * 2; | |
410 imageStyle.append("background-size: "); | |
411 imageStyle.append(AtomicString::number(tileSize)); | |
412 imageStyle.append("px "); | |
413 imageStyle.append(AtomicString::number(tileSize)); | |
414 imageStyle.append("px;"); | |
415 | |
416 imageStyle.append( | |
417 "background-color: white;" | |
418 "background-image:" | |
419 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, " | |
420 "#eee 75%, #eee 100%)," | |
421 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, " | |
422 "#eee 75%, #eee 100%);"); | |
423 } | |
424 } | |
425 | |
426 if (m_imageElement->getAttribute(styleAttr) != imageStyle.toAtomicString()) | |
pdr.
2016/11/02 22:54:49
This large string comparison is kinda unfortunate.
gone
2016/11/03 01:28:41
After figuring out how to avoid the string compari
| |
427 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); | |
428 } | |
429 | |
349 void ImageDocument::imageUpdated() { | 430 void ImageDocument::imageUpdated() { |
350 DCHECK(m_imageElement); | 431 DCHECK(m_imageElement); |
351 | 432 |
352 if (m_imageSizeIsKnown) | 433 if (m_imageSizeIsKnown) |
353 return; | 434 return; |
354 | 435 |
355 updateStyleAndLayoutTree(); | 436 updateStyleAndLayoutTree(); |
356 if (!m_imageElement->cachedImage() || | 437 if (!m_imageElement->cachedImage() || |
357 m_imageElement->cachedImage() | 438 m_imageElement->cachedImage() |
358 ->imageSize(LayoutObject::shouldRespectImageOrientation( | 439 ->imageSize(LayoutObject::shouldRespectImageOrientation( |
(...skipping 11 matching lines...) Expand all Loading... | |
370 } | 451 } |
371 | 452 |
372 void ImageDocument::restoreImageSize() { | 453 void ImageDocument::restoreImageSize() { |
373 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 454 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
374 | 455 |
375 if (!m_imageElement || !m_imageSizeIsKnown || | 456 if (!m_imageElement || !m_imageSizeIsKnown || |
376 m_imageElement->document() != this) | 457 m_imageElement->document() != this) |
377 return; | 458 return; |
378 | 459 |
379 DCHECK(m_imageElement->cachedImage()); | 460 DCHECK(m_imageElement->cachedImage()); |
380 LayoutSize imageSize = m_imageElement->cachedImage()->imageSize( | 461 LayoutSize imageSize = cachedImageSize(m_imageElement); |
381 LayoutObject::shouldRespectImageOrientation( | |
382 m_imageElement->layoutObject()), | |
383 1.0f); | |
384 m_imageElement->setWidth(imageSize.width().toInt()); | 462 m_imageElement->setWidth(imageSize.width().toInt()); |
385 m_imageElement->setHeight(imageSize.height().toInt()); | 463 m_imageElement->setHeight(imageSize.height().toInt()); |
386 | 464 |
387 if (imageFitsInWindow()) | 465 if (imageFitsInWindow()) |
388 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor); | 466 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor); |
389 else | 467 else |
390 m_imageElement->setInlineStyleProperty(CSSPropertyCursor, CSSValueZoomOut); | 468 m_imageElement->setInlineStyleProperty(CSSPropertyCursor, CSSValueZoomOut); |
391 | 469 |
392 m_didShrinkImage = false; | 470 m_didShrinkImage = false; |
393 } | 471 } |
394 | 472 |
395 bool ImageDocument::imageFitsInWindow() const { | 473 bool ImageDocument::imageFitsInWindow() const { |
396 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 474 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
397 return this->scale() >= 1; | 475 return this->scale() >= 1; |
398 } | 476 } |
399 | 477 |
478 int ImageDocument::calculateDivWidth() { | |
479 // Zooming in and out of an image being displayed within a viewport is done | |
480 // by changing the page scale factor of the page instead of changing the | |
481 // size of the image. The size of the image is set so that: | |
482 // * Images wider than the viewport take the full width of the screen. | |
483 // * Images taller than the viewport are initially aligned with the top of | |
484 // of the frame. | |
485 // * Images smaller in either dimension are centered along that axis. | |
486 LayoutSize imageSize = cachedImageSize(m_imageElement); | |
487 int viewportWidth = frame()->host()->visualViewport().size().width(); | |
488 | |
489 // For huge images, minimum-scale=0.1 is still too big on small screens. | |
490 // Set the <div> width so that the image will shrink to fit the width of the | |
491 // screen when the scale is minimum. | |
492 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); | |
493 return std::max(viewportWidth, maxWidth); | |
494 } | |
495 | |
400 void ImageDocument::windowSizeChanged() { | 496 void ImageDocument::windowSizeChanged() { |
401 if (!m_imageElement || !m_imageSizeIsKnown || | 497 if (!m_imageElement || !m_imageSizeIsKnown || |
402 m_imageElement->document() != this) | 498 m_imageElement->document() != this) |
403 return; | 499 return; |
404 | 500 |
405 if (m_shrinkToFitMode == Viewport) { | 501 if (m_shrinkToFitMode == Viewport) { |
406 // Zooming in and out of an image being displayed within a viewport is done | 502 LayoutSize imageSize = cachedImageSize(m_imageElement); |
407 // by changing the page scale factor of the page instead of changing the | 503 int divWidth = calculateDivWidth(); |
408 // size of the image. The size of the image is set so that: | |
409 // * Images wider than the viewport take the full width of the screen. | |
410 // * Images taller than the viewport are initially aligned with the top of | |
411 // of the frame. | |
412 // * Images smaller in either dimension are centered along that axis. | |
413 LayoutSize imageSize = m_imageElement->cachedImage()->imageSize( | |
414 LayoutObject::shouldRespectImageOrientation( | |
415 m_imageElement->layoutObject()), | |
416 1.f); | |
417 int viewportWidth = frame()->host()->visualViewport().size().width(); | |
418 int viewportHeight = frame()->host()->visualViewport().size().height(); | |
419 float viewportAspectRatio = (float)viewportWidth / viewportHeight; | |
420 | |
421 // For huge images, minimum-scale=0.1 is still too big on small screens. | |
422 // Set the <div> width so that the image will shrink to fit the width of the | |
423 // screen when the scale is minimum. | |
424 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); | |
425 int divWidth = std::max(viewportWidth, maxWidth); | |
426 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, | 504 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, |
427 CSSPrimitiveValue::UnitType::Pixels); | 505 CSSPrimitiveValue::UnitType::Pixels); |
428 | 506 |
429 // Explicitly set the height of the <div> containing the <img> so that it | 507 // Explicitly set the height of the <div> containing the <img> so that it |
430 // can display the full image without shrinking it, allowing a full-width | 508 // can display the full image without shrinking it, allowing a full-width |
431 // reading mode for normal-width-huge-height images. | 509 // reading mode for normal-width-huge-height images. |
510 int viewportWidth = frame()->host()->visualViewport().size().width(); | |
511 int viewportHeight = frame()->host()->visualViewport().size().height(); | |
512 float viewportAspectRatio = (float)viewportWidth / viewportHeight; | |
pdr.
2016/11/02 22:54:49
Super nit: float viewportAspectRatio = frame()->ho
gone
2016/11/03 01:28:41
Done.
| |
432 int divHeight = std::max(imageSize.height().toInt(), | 513 int divHeight = std::max(imageSize.height().toInt(), |
433 (int)(divWidth / viewportAspectRatio)); | 514 static_cast<int>(divWidth / viewportAspectRatio)); |
434 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, | 515 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, |
435 CSSPrimitiveValue::UnitType::Pixels); | 516 CSSPrimitiveValue::UnitType::Pixels); |
436 return; | 517 return; |
437 } | 518 } |
438 | 519 |
439 bool fitsInWindow = imageFitsInWindow(); | 520 bool fitsInWindow = imageFitsInWindow(); |
440 | 521 |
441 // If the image has been explicitly zoomed in, restore the cursor if the image | 522 // If the image has been explicitly zoomed in, restore the cursor if the image |
442 // fits and set it to a zoom out cursor if the image doesn't fit | 523 // fits and set it to a zoom out cursor if the image doesn't fit |
443 if (!m_shouldShrinkImage) { | 524 if (!m_shouldShrinkImage) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
488 } | 569 } |
489 | 570 |
490 // -------- | 571 // -------- |
491 | 572 |
492 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) { | 573 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) { |
493 if (event->type() == EventTypeNames::resize) { | 574 if (event->type() == EventTypeNames::resize) { |
494 m_doc->windowSizeChanged(); | 575 m_doc->windowSizeChanged(); |
495 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) { | 576 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) { |
496 MouseEvent* mouseEvent = toMouseEvent(event); | 577 MouseEvent* mouseEvent = toMouseEvent(event); |
497 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y()); | 578 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y()); |
579 } else if ((event->type() == EventTypeNames::touchend || | |
580 event->type() == EventTypeNames::touchcancel) && | |
581 event->isTouchEvent()) { | |
582 m_doc->updateImageStyle(); | |
498 } | 583 } |
499 } | 584 } |
500 | 585 |
501 bool ImageEventListener::operator==(const EventListener& listener) const { | 586 bool ImageEventListener::operator==(const EventListener& listener) const { |
502 if (const ImageEventListener* imageEventListener = | 587 if (const ImageEventListener* imageEventListener = |
503 ImageEventListener::cast(&listener)) | 588 ImageEventListener::cast(&listener)) |
504 return m_doc == imageEventListener->m_doc; | 589 return m_doc == imageEventListener->m_doc; |
505 return false; | 590 return false; |
506 } | 591 } |
507 | 592 |
508 } // namespace blink | 593 } // namespace blink |
OLD | NEW |