Chromium Code Reviews| 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 |
| 11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
| 12 * | 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 19 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 20 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 20 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "core/html/ImageDocument.h" | 25 #include "core/html/ImageDocument.h" |
| 26 | 26 |
| 27 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 27 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| 28 #include "core/HTMLNames.h" | 28 #include "core/HTMLNames.h" |
| 29 #include "core/dom/ExecutionContextTask.h" | |
| 29 #include "core/dom/RawDataDocumentParser.h" | 30 #include "core/dom/RawDataDocumentParser.h" |
| 30 #include "core/events/EventListener.h" | 31 #include "core/events/EventListener.h" |
| 31 #include "core/events/MouseEvent.h" | 32 #include "core/events/MouseEvent.h" |
| 32 #include "core/fetch/ImageResource.h" | 33 #include "core/fetch/ImageResource.h" |
| 33 #include "core/frame/FrameHost.h" | 34 #include "core/frame/FrameHost.h" |
| 34 #include "core/frame/FrameView.h" | 35 #include "core/frame/FrameView.h" |
| 35 #include "core/frame/LocalDOMWindow.h" | 36 #include "core/frame/LocalDOMWindow.h" |
| 36 #include "core/frame/LocalFrame.h" | 37 #include "core/frame/LocalFrame.h" |
| 37 #include "core/frame/Settings.h" | 38 #include "core/frame/Settings.h" |
| 38 #include "core/frame/UseCounter.h" | 39 #include "core/frame/UseCounter.h" |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 String fileName = | 166 String fileName = |
| 166 decodeURLEscapeSequences(document()->url().lastPathComponent()); | 167 decodeURLEscapeSequences(document()->url().lastPathComponent()); |
| 167 if (fileName.isEmpty()) | 168 if (fileName.isEmpty()) |
| 168 fileName = document()->url().host(); | 169 fileName = document()->url().host(); |
| 169 document()->setTitle(imageTitle(fileName, size)); | 170 document()->setTitle(imageTitle(fileName, size)); |
| 170 if (isDetached()) | 171 if (isDetached()) |
| 171 return; | 172 return; |
| 172 } | 173 } |
| 173 | 174 |
| 174 document()->imageUpdated(); | 175 document()->imageUpdated(); |
| 176 document()->imageLoaded(); | |
| 175 } | 177 } |
| 176 | 178 |
| 177 if (!isDetached()) | 179 if (!isDetached()) |
| 178 document()->finishedParsing(); | 180 document()->finishedParsing(); |
| 179 } | 181 } |
| 180 | 182 |
| 181 // -------- | 183 // -------- |
| 182 | 184 |
| 183 ImageDocument::ImageDocument(const DocumentInit& initializer) | 185 ImageDocument::ImageDocument(const DocumentInit& initializer) |
| 184 : HTMLDocument(initializer, ImageDocumentClass), | 186 : HTMLDocument(initializer, ImageDocumentClass), |
| 185 m_divElement(nullptr), | 187 m_divElement(nullptr), |
| 186 m_imageElement(nullptr), | 188 m_imageElement(nullptr), |
| 187 m_imageSizeIsKnown(false), | 189 m_imageSizeIsKnown(false), |
| 188 m_didShrinkImage(false), | 190 m_didShrinkImage(false), |
| 189 m_shouldShrinkImage(shouldShrinkToFit()), | 191 m_shouldShrinkImage(shouldShrinkToFit()), |
| 192 m_imageIsLoaded(false), | |
| 190 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport | 193 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport |
| 191 : Desktop) { | 194 : Desktop) { |
| 192 setCompatibilityMode(QuirksMode); | 195 setCompatibilityMode(QuirksMode); |
| 193 lockCompatibilityMode(); | 196 lockCompatibilityMode(); |
| 194 UseCounter::count(*this, UseCounter::ImageDocument); | 197 UseCounter::count(*this, UseCounter::ImageDocument); |
| 195 if (!isInMainFrame()) | 198 if (!isInMainFrame()) |
| 196 UseCounter::count(*this, UseCounter::ImageDocumentInFrame); | 199 UseCounter::count(*this, UseCounter::ImageDocumentInFrame); |
| 197 } | 200 } |
| 198 | 201 |
| 199 DocumentParser* ImageDocument::createParser() { | 202 DocumentParser* ImageDocument::createParser() { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 211 HTMLHeadElement* head = HTMLHeadElement::create(*this); | 214 HTMLHeadElement* head = HTMLHeadElement::create(*this); |
| 212 HTMLMetaElement* meta = HTMLMetaElement::create(*this); | 215 HTMLMetaElement* meta = HTMLMetaElement::create(*this); |
| 213 meta->setAttribute(nameAttr, "viewport"); | 216 meta->setAttribute(nameAttr, "viewport"); |
| 214 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); | 217 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); |
| 215 head->appendChild(meta); | 218 head->appendChild(meta); |
| 216 | 219 |
| 217 HTMLBodyElement* body = HTMLBodyElement::create(*this); | 220 HTMLBodyElement* body = HTMLBodyElement::create(*this); |
| 218 | 221 |
| 219 if (shouldShrinkToFit()) { | 222 if (shouldShrinkToFit()) { |
| 220 // Display the image prominently centered in the frame. | 223 // Display the image prominently centered in the frame. |
| 221 body->setAttribute(styleAttr, "margin: 0px;"); | 224 body->setAttribute(styleAttr, "margin: 0px; background: #0e0e0e;"); |
| 222 | 225 |
| 223 // See w3c example on how to centering an element: | 226 // See w3c example on how to center an element: |
| 224 // https://www.w3.org/Style/Examples/007/center.en.html | 227 // https://www.w3.org/Style/Examples/007/center.en.html |
| 225 m_divElement = HTMLDivElement::create(*this); | 228 m_divElement = HTMLDivElement::create(*this); |
| 226 m_divElement->setAttribute(styleAttr, | 229 m_divElement->setAttribute(styleAttr, |
| 227 "display: flex;" | 230 "display: flex;" |
| 228 "flex-direction: column;" | 231 "flex-direction: column;" |
| 229 "justify-content: center;" | 232 "justify-content: center;" |
| 230 "align-items: center;" | 233 "align-items: center;" |
| 231 "min-height: min-content;" | 234 "min-height: min-content;" |
| 232 "min-width: min-content;" | 235 "min-width: min-content;" |
| 233 "height: 100%;" | 236 "height: 100%;" |
| 234 "width: 100%;"); | 237 "width: 100%;"); |
| 235 HTMLContentElement* content = HTMLContentElement::create(*this); | 238 HTMLContentElement* content = HTMLContentElement::create(*this); |
| 236 m_divElement->appendChild(content); | 239 m_divElement->appendChild(content); |
| 237 | 240 |
| 238 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); | 241 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); |
| 239 shadowRoot.appendChild(m_divElement); | 242 shadowRoot.appendChild(m_divElement); |
| 240 } else { | 243 } else { |
| 241 body->setAttribute(styleAttr, "margin: 0px;"); | 244 body->setAttribute(styleAttr, "margin: 0px;"); |
| 242 } | 245 } |
| 243 | 246 |
| 244 willInsertBody(); | 247 willInsertBody(); |
| 245 | 248 |
| 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); | 249 m_imageElement = HTMLImageElement::create(*this); |
| 251 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); | 250 updateImageStyle(); |
| 252 m_imageElement->setLoadingImageDocument(); | 251 m_imageElement->setLoadingImageDocument(); |
| 253 m_imageElement->setSrc(url().getString()); | 252 m_imageElement->setSrc(url().getString()); |
| 254 body->appendChild(m_imageElement.get()); | 253 body->appendChild(m_imageElement.get()); |
| 255 if (loader() && m_imageElement->cachedImage()) | 254 if (loader() && m_imageElement->cachedImage()) |
| 256 m_imageElement->cachedImage()->responseReceived(loader()->response(), | 255 m_imageElement->cachedImage()->responseReceived(loader()->response(), |
| 257 nullptr); | 256 nullptr); |
| 258 | 257 |
| 259 if (shouldShrinkToFit()) { | 258 if (shouldShrinkToFit()) { |
| 260 // Add event listeners | 259 // Add event listeners |
| 261 EventListener* listener = ImageEventListener::create(this); | 260 EventListener* listener = ImageEventListener::create(this); |
| 262 if (LocalDOMWindow* domWindow = this->domWindow()) | 261 if (LocalDOMWindow* domWindow = this->domWindow()) |
| 263 domWindow->addEventListener("resize", listener, false); | 262 domWindow->addEventListener(EventTypeNames::resize, listener, false); |
| 264 if (m_shrinkToFitMode == Desktop) | 263 |
| 265 m_imageElement->addEventListener("click", listener, false); | 264 if (m_shrinkToFitMode == Desktop) { |
| 265 m_imageElement->addEventListener(EventTypeNames::click, listener, false); | |
| 266 } else if (m_shrinkToFitMode == Viewport) { | |
| 267 m_imageElement->addEventListener(EventTypeNames::touchend, listener, | |
| 268 false); | |
| 269 m_imageElement->addEventListener(EventTypeNames::touchcancel, listener, | |
| 270 false); | |
| 271 } | |
| 266 } | 272 } |
| 267 | 273 |
| 268 rootElement->appendChild(head); | 274 rootElement->appendChild(head); |
| 269 rootElement->appendChild(body); | 275 rootElement->appendChild(body); |
| 270 } | 276 } |
| 271 | 277 |
| 272 float ImageDocument::scale() const { | 278 float ImageDocument::scale() const { |
| 273 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 279 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
| 274 if (!m_imageElement || m_imageElement->document() != this) | 280 if (!m_imageElement || m_imageElement->document() != this) |
| 275 return 1.0f; | 281 return 1.0f; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 float scrollX = | 345 float scrollX = |
| 340 imageX / scale - static_cast<float>(frame()->view()->width()) / 2; | 346 imageX / scale - static_cast<float>(frame()->view()->width()) / 2; |
| 341 float scrollY = | 347 float scrollY = |
| 342 imageY / scale - static_cast<float>(frame()->view()->height()) / 2; | 348 imageY / scale - static_cast<float>(frame()->view()->height()) / 2; |
| 343 | 349 |
| 344 frame()->view()->layoutViewportScrollableArea()->setScrollOffset( | 350 frame()->view()->layoutViewportScrollableArea()->setScrollOffset( |
| 345 ScrollOffset(scrollX, scrollY), ProgrammaticScroll); | 351 ScrollOffset(scrollX, scrollY), ProgrammaticScroll); |
| 346 } | 352 } |
| 347 } | 353 } |
| 348 | 354 |
| 355 static void updateDocumentImageStyle(ExecutionContext* context) { | |
| 356 // Shouldn't be anything except an ImageDocument if |context| is a Document. | |
| 357 ImageDocument* document = static_cast<ImageDocument*>(toDocument(context)); | |
| 358 document->updateImageStyle(); | |
| 359 } | |
| 360 | |
| 361 void ImageDocument::imageLoaded() { | |
| 362 m_imageIsLoaded = true; | |
| 363 postTask(BLINK_FROM_HERE, createSameThreadTask(&updateDocumentImageStyle), | |
|
pdr.
2016/11/01 06:54:56
This seems reasonable to me if we don't have anoth
gone
2016/11/02 18:42:20
Got rid of the task and tried looking at more flag
| |
| 364 "updateImageStyle"); | |
| 365 } | |
| 366 | |
| 367 void ImageDocument::updateImageStyle() { | |
| 368 StringBuilder imageStyle; | |
|
pdr.
2016/11/01 06:54:56
Because this is called on every touch end/cancel e
gone
2016/11/02 18:42:20
WDYT about this version, where I compare the two s
| |
| 369 imageStyle.append("-webkit-user-select: none;"); | |
| 370 if (shouldShrinkToFit()) { | |
| 371 if (m_shrinkToFitMode == Viewport) { | |
| 372 imageStyle.append("max-width: 100%;"); | |
| 373 } | |
| 374 | |
| 375 // Once the image has fully loaded, it is displayed atop a checkerboard to | |
| 376 // show transparency more faithfully. The pattern is generated via CSS. | |
| 377 if (m_imageIsLoaded) { | |
| 378 // The base square size is set to 10 because it rounds nicely for both the | |
| 379 // minimum scale (0.1) and maximum scale (5.0). | |
| 380 double checkerSize = 10.0; | |
| 381 | |
| 382 if (m_shrinkToFitMode == Viewport) { | |
| 383 // To ensure the checker pattern is visible for large images in | |
| 384 // viewports, the checker size must be dynamically adjusted to account | |
| 385 // for how much the page is currently being scaled. | |
| 386 double scale = frame()->host()->visualViewport().scale(); | |
| 387 checkerSize = std::max(1.0, checkerSize / scale); | |
| 388 } | |
| 389 | |
| 390 int roundedSize = static_cast<int>(round(checkerSize)); | |
| 391 int tileSize = roundedSize * 2; | |
| 392 | |
| 393 imageStyle.append("background-position: 0px 0px, "); | |
| 394 imageStyle.append(AtomicString::number(roundedSize)); | |
| 395 imageStyle.append("px "); | |
| 396 imageStyle.append(AtomicString::number(roundedSize)); | |
| 397 imageStyle.append("px;"); | |
| 398 | |
| 399 imageStyle.append("background-size: "); | |
| 400 imageStyle.append(AtomicString::number(tileSize)); | |
| 401 imageStyle.append("px "); | |
| 402 imageStyle.append(AtomicString::number(tileSize)); | |
| 403 imageStyle.append("px;"); | |
| 404 | |
| 405 imageStyle.append( | |
| 406 "background-color: white;" | |
| 407 "background-image:" | |
| 408 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, " | |
| 409 "#eee 75%, #eee 100%)," | |
| 410 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, " | |
| 411 "#eee 75%, #eee 100%);"); | |
| 412 } | |
| 413 } | |
| 414 | |
| 415 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); | |
| 416 } | |
| 417 | |
| 349 void ImageDocument::imageUpdated() { | 418 void ImageDocument::imageUpdated() { |
| 350 DCHECK(m_imageElement); | 419 DCHECK(m_imageElement); |
| 351 | 420 |
| 352 if (m_imageSizeIsKnown) | 421 if (m_imageSizeIsKnown) |
| 353 return; | 422 return; |
| 354 | 423 |
| 355 updateStyleAndLayoutTree(); | 424 updateStyleAndLayoutTree(); |
| 356 if (!m_imageElement->cachedImage() || | 425 if (!m_imageElement->cachedImage() || |
| 357 m_imageElement->cachedImage() | 426 m_imageElement->cachedImage() |
| 358 ->imageSize(LayoutObject::shouldRespectImageOrientation( | 427 ->imageSize(LayoutObject::shouldRespectImageOrientation( |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 // screen when the scale is minimum. | 492 // screen when the scale is minimum. |
| 424 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); | 493 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); |
| 425 int divWidth = std::max(viewportWidth, maxWidth); | 494 int divWidth = std::max(viewportWidth, maxWidth); |
| 426 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, | 495 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, |
| 427 CSSPrimitiveValue::UnitType::Pixels); | 496 CSSPrimitiveValue::UnitType::Pixels); |
| 428 | 497 |
| 429 // Explicitly set the height of the <div> containing the <img> so that it | 498 // 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 | 499 // can display the full image without shrinking it, allowing a full-width |
| 431 // reading mode for normal-width-huge-height images. | 500 // reading mode for normal-width-huge-height images. |
| 432 int divHeight = std::max(imageSize.height().toInt(), | 501 int divHeight = std::max(imageSize.height().toInt(), |
| 433 (int)(divWidth / viewportAspectRatio)); | 502 static_cast<int>(divWidth / viewportAspectRatio)); |
| 434 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, | 503 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, |
| 435 CSSPrimitiveValue::UnitType::Pixels); | 504 CSSPrimitiveValue::UnitType::Pixels); |
| 505 updateImageStyle(); | |
| 436 return; | 506 return; |
| 437 } | 507 } |
| 438 | 508 |
| 439 bool fitsInWindow = imageFitsInWindow(); | 509 bool fitsInWindow = imageFitsInWindow(); |
| 440 | 510 |
| 441 // If the image has been explicitly zoomed in, restore the cursor if the image | 511 // 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 | 512 // fits and set it to a zoom out cursor if the image doesn't fit |
| 443 if (!m_shouldShrinkImage) { | 513 if (!m_shouldShrinkImage) { |
| 444 if (fitsInWindow) | 514 if (fitsInWindow) |
| 445 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor); | 515 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 } | 558 } |
| 489 | 559 |
| 490 // -------- | 560 // -------- |
| 491 | 561 |
| 492 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) { | 562 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) { |
| 493 if (event->type() == EventTypeNames::resize) { | 563 if (event->type() == EventTypeNames::resize) { |
| 494 m_doc->windowSizeChanged(); | 564 m_doc->windowSizeChanged(); |
| 495 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) { | 565 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) { |
| 496 MouseEvent* mouseEvent = toMouseEvent(event); | 566 MouseEvent* mouseEvent = toMouseEvent(event); |
| 497 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y()); | 567 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y()); |
| 568 } else if (event->isTouchEvent()) { | |
| 569 m_doc->updateImageStyle(); | |
| 498 } | 570 } |
| 499 } | 571 } |
| 500 | 572 |
| 501 bool ImageEventListener::operator==(const EventListener& listener) const { | 573 bool ImageEventListener::operator==(const EventListener& listener) const { |
| 502 if (const ImageEventListener* imageEventListener = | 574 if (const ImageEventListener* imageEventListener = |
| 503 ImageEventListener::cast(&listener)) | 575 ImageEventListener::cast(&listener)) |
| 504 return m_doc == imageEventListener->m_doc; | 576 return m_doc == imageEventListener->m_doc; |
| 505 return false; | 577 return false; |
| 506 } | 578 } |
| 507 | 579 |
| 508 } // namespace blink | 580 } // namespace blink |
| OLD | NEW |