Index: third_party/WebKit/Source/core/html/ImageDocument.cpp |
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.cpp b/third_party/WebKit/Source/core/html/ImageDocument.cpp |
index ea2edaa6ddf75ff30f9cfb5449793b3bf229855c..a3d63fca4c7b905591e9d751fec82c526f22ccf4 100644 |
--- a/third_party/WebKit/Source/core/html/ImageDocument.cpp |
+++ b/third_party/WebKit/Source/core/html/ImageDocument.cpp |
@@ -38,6 +38,8 @@ |
#include "core/frame/UseCounter.h" |
#include "core/frame/VisualViewport.h" |
#include "core/html/HTMLBodyElement.h" |
+#include "core/html/HTMLContentElement.h" |
+#include "core/html/HTMLDivElement.h" |
#include "core/html/HTMLHeadElement.h" |
#include "core/html/HTMLHtmlElement.h" |
#include "core/html/HTMLImageElement.h" |
@@ -180,6 +182,7 @@ void ImageDocumentParser::finish() { |
ImageDocument::ImageDocument(const DocumentInit& initializer) |
: HTMLDocument(initializer, ImageDocumentClass), |
+ m_divElement(nullptr), |
m_imageElement(nullptr), |
m_imageSizeIsKnown(false), |
m_didShrinkImage(false), |
@@ -212,12 +215,40 @@ void ImageDocument::createDocumentStructure() { |
head->appendChild(meta); |
HTMLBodyElement* body = HTMLBodyElement::create(*this); |
- body->setAttribute(styleAttr, "margin: 0px;"); |
+ |
+ if (shouldShrinkToFit()) { |
+ // Display the image prominently centered in the frame. |
+ body->setAttribute(styleAttr, "margin: 0px;"); |
+ |
+ // See w3c example on how to centering an element: |
+ // https://www.w3.org/Style/Examples/007/center.en.html |
+ m_divElement = HTMLDivElement::create(*this); |
+ m_divElement->setAttribute(styleAttr, |
+ "display: flex;" |
+ "flex-direction: column;" |
+ "justify-content: center;" |
+ "align-items: center;" |
+ "min-height: min-content;" |
+ "min-width: min-content;" |
+ "height: 100%;" |
+ "width: 100%;"); |
+ HTMLContentElement* content = HTMLContentElement::create(*this); |
+ m_divElement->appendChild(content); |
+ |
+ ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); |
+ shadowRoot.appendChild(m_divElement); |
+ } else { |
+ body->setAttribute(styleAttr, "margin: 0px;"); |
+ } |
willInsertBody(); |
+ StringBuilder imageStyle; |
+ imageStyle.append("-webkit-user-select: none;"); |
+ if (shouldShrinkToFit() && m_shrinkToFitMode == Viewport) |
+ imageStyle.append("max-width: 100%"); |
m_imageElement = HTMLImageElement::create(*this); |
- m_imageElement->setAttribute(styleAttr, "-webkit-user-select: none"); |
+ m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); |
m_imageElement->setLoadingImageDocument(); |
m_imageElement->setSrc(url().getString()); |
body->appendChild(m_imageElement.get()); |
@@ -294,6 +325,11 @@ void ImageDocument::imageClicked(int x, int y) { |
if (m_shouldShrinkImage) { |
windowSizeChanged(); |
} else { |
+ // Adjust the coordinates to account for the fact that the image was |
+ // centered on the screen. |
+ float imageX = x - m_imageElement->offsetLeft(); |
+ float imageY = y - m_imageElement->offsetTop(); |
+ |
restoreImageSize(); |
updateStyleAndLayout(); |
@@ -301,9 +337,9 @@ void ImageDocument::imageClicked(int x, int y) { |
double scale = this->scale(); |
float scrollX = |
- x / scale - static_cast<float>(frame()->view()->width()) / 2; |
+ imageX / scale - static_cast<float>(frame()->view()->width()) / 2; |
float scrollY = |
- y / scale - static_cast<float>(frame()->view()->height()) / 2; |
+ imageY / scale - static_cast<float>(frame()->view()->height()) / 2; |
frame()->view()->layoutViewportScrollableArea()->setScrollOffset( |
ScrollOffset(scrollX, scrollY), ProgrammaticScroll); |
@@ -367,15 +403,36 @@ void ImageDocument::windowSizeChanged() { |
return; |
if (m_shrinkToFitMode == Viewport) { |
+ // Zooming in and out of an image being displayed within a viewport is done |
+ // by changing the page scale factor of the page instead of changing the |
+ // size of the image. The size of the image is set so that: |
+ // * Images wider than the viewport take the full width of the screen. |
+ // * Images taller than the viewport are initially aligned with the top of |
+ // of the frame. |
+ // * Images smaller in either dimension are centered along that axis. |
+ LayoutSize imageSize = m_imageElement->cachedImage()->imageSize( |
+ LayoutObject::shouldRespectImageOrientation( |
+ m_imageElement->layoutObject()), |
+ 1.f); |
+ int viewportWidth = frame()->host()->visualViewport().size().width(); |
+ int viewportHeight = frame()->host()->visualViewport().size().height(); |
+ float viewportAspectRatio = (float)viewportWidth / viewportHeight; |
+ |
// For huge images, minimum-scale=0.1 is still too big on small screens. |
- // Set max-width so that the image will shrink to fit the width of the |
- // screen when the scale is minimum. Don't shrink height to fit because we |
- // use width=device-width in viewport meta tag, and expect a full-width |
+ // Set the <div> width so that the image will shrink to fit the width of the |
+ // screen when the scale is minimum. |
+ int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); |
+ int divWidth = std::max(viewportWidth, maxWidth); |
+ m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, |
+ CSSPrimitiveValue::UnitType::Pixels); |
+ |
+ // Explicitly set the height of the <div> containing the <img> so that it |
+ // can display the full image without shrinking it, allowing a full-width |
// reading mode for normal-width-huge-height images. |
- int viewportWidth = frame()->host()->visualViewport().size().width(); |
- m_imageElement->setInlineStyleProperty(CSSPropertyMaxWidth, |
- viewportWidth * 10, |
- CSSPrimitiveValue::UnitType::Pixels); |
+ int divHeight = std::max(imageSize.height().toInt(), |
+ (int)(divWidth / viewportAspectRatio)); |
+ m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, |
+ CSSPrimitiveValue::UnitType::Pixels); |
return; |
} |
@@ -425,6 +482,7 @@ bool ImageDocument::shouldShrinkToFit() const { |
} |
DEFINE_TRACE(ImageDocument) { |
+ visitor->trace(m_divElement); |
visitor->trace(m_imageElement); |
HTMLDocument::trace(visitor); |
} |