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 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 41 #include "core/html/HTMLDivElement.h" | 41 #include "core/html/HTMLDivElement.h" |
| 42 #include "core/html/HTMLHeadElement.h" | 42 #include "core/html/HTMLHeadElement.h" |
| 43 #include "core/html/HTMLHtmlElement.h" | 43 #include "core/html/HTMLHtmlElement.h" |
| 44 #include "core/html/HTMLImageElement.h" | 44 #include "core/html/HTMLImageElement.h" |
| 45 #include "core/html/HTMLMetaElement.h" | 45 #include "core/html/HTMLMetaElement.h" |
| 46 #include "core/layout/LayoutObject.h" | 46 #include "core/layout/LayoutObject.h" |
| 47 #include "core/loader/DocumentLoader.h" | 47 #include "core/loader/DocumentLoader.h" |
| 48 #include "core/loader/FrameLoader.h" | 48 #include "core/loader/FrameLoader.h" |
| 49 #include "core/loader/FrameLoaderClient.h" | 49 #include "core/loader/FrameLoaderClient.h" |
| 50 #include "core/loader/resource/ImageResource.h" | 50 #include "core/loader/resource/ImageResource.h" |
| 51 #include "core/page/Page.h" | |
| 51 #include "platform/HostWindow.h" | 52 #include "platform/HostWindow.h" |
| 52 #include "wtf/text/StringBuilder.h" | 53 #include "wtf/text/StringBuilder.h" |
| 53 #include <limits> | 54 #include <limits> |
| 54 | 55 |
| 55 using namespace std; | 56 using namespace std; |
| 56 | 57 |
| 57 namespace { | 58 namespace { |
| 58 | 59 |
| 59 // The base square size is set to 10 because it rounds nicely for both the | 60 // 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 // minimum scale (0.1) and maximum scale (5.0). |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 return; // runScriptsAtDocumentElementAvailable can detach the frame. | 229 return; // runScriptsAtDocumentElementAvailable can detach the frame. |
| 229 | 230 |
| 230 HTMLHeadElement* head = HTMLHeadElement::create(*this); | 231 HTMLHeadElement* head = HTMLHeadElement::create(*this); |
| 231 HTMLMetaElement* meta = HTMLMetaElement::create(*this); | 232 HTMLMetaElement* meta = HTMLMetaElement::create(*this); |
| 232 meta->setAttribute(nameAttr, "viewport"); | 233 meta->setAttribute(nameAttr, "viewport"); |
| 233 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); | 234 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); |
| 234 head->appendChild(meta); | 235 head->appendChild(meta); |
| 235 | 236 |
| 236 HTMLBodyElement* body = HTMLBodyElement::create(*this); | 237 HTMLBodyElement* body = HTMLBodyElement::create(*this); |
| 237 | 238 |
| 238 if (shouldShrinkToFit()) { | 239 if (shouldCenterImage()) { |
| 239 // Display the image prominently centered in the frame. | 240 // Display the image prominently centered in the frame. |
| 240 body->setAttribute(styleAttr, "margin: 0px; background: #0e0e0e;"); | 241 body->setAttribute(styleAttr, "margin: 0px; background: #0e0e0e;"); |
| 241 | 242 |
| 242 // See w3c example on how to center an element: | 243 // See w3c example on how to center an element: |
| 243 // https://www.w3.org/Style/Examples/007/center.en.html | 244 // https://www.w3.org/Style/Examples/007/center.en.html |
| 244 m_divElement = HTMLDivElement::create(*this); | 245 m_divElement = HTMLDivElement::create(*this); |
| 245 m_divElement->setAttribute(styleAttr, | 246 m_divElement->setAttribute(styleAttr, |
| 246 "display: flex;" | 247 "display: flex;" |
| 247 "flex-direction: column;" | 248 "flex-direction: column;" |
| 248 "justify-content: center;" | 249 "justify-content: center;" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 false); | 286 false); |
| 286 m_imageElement->addEventListener(EventTypeNames::touchcancel, listener, | 287 m_imageElement->addEventListener(EventTypeNames::touchcancel, listener, |
| 287 false); | 288 false); |
| 288 } | 289 } |
| 289 } | 290 } |
| 290 | 291 |
| 291 rootElement->appendChild(head); | 292 rootElement->appendChild(head); |
| 292 rootElement->appendChild(body); | 293 rootElement->appendChild(body); |
| 293 } | 294 } |
| 294 | 295 |
| 296 bool ImageDocument::shouldCenterImage() const { | |
| 297 bool isAndroidWebView = | |
| 298 page() ? page()->settings().getWideViewportQuirkEnabled() : false; | |
| 299 return shouldShrinkToFit() && !isAndroidWebView; | |
| 300 } | |
| 301 | |
| 295 float ImageDocument::scale() const { | 302 float ImageDocument::scale() const { |
| 296 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 303 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
| 297 if (!m_imageElement || m_imageElement->document() != this) | 304 if (!m_imageElement || m_imageElement->document() != this) |
| 298 return 1.0f; | 305 return 1.0f; |
| 299 | 306 |
| 300 FrameView* view = frame()->view(); | 307 FrameView* view = frame()->view(); |
| 301 if (!view) | 308 if (!view) |
| 302 return 1.0f; | 309 return 1.0f; |
| 303 | 310 |
| 304 DCHECK(m_imageElement->cachedImage()); | 311 DCHECK(m_imageElement->cachedImage()); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 // The checkerboard background needs to be inserted. | 379 // The checkerboard background needs to be inserted. |
| 373 updateImageStyle(); | 380 updateImageStyle(); |
| 374 } | 381 } |
| 375 } | 382 } |
| 376 | 383 |
| 377 void ImageDocument::updateImageStyle() { | 384 void ImageDocument::updateImageStyle() { |
| 378 StringBuilder imageStyle; | 385 StringBuilder imageStyle; |
| 379 imageStyle.append("-webkit-user-select: none;"); | 386 imageStyle.append("-webkit-user-select: none;"); |
| 380 | 387 |
| 381 if (shouldShrinkToFit()) { | 388 if (shouldShrinkToFit()) { |
| 382 if (m_shrinkToFitMode == Viewport) | 389 if (shouldCenterImage() && m_shrinkToFitMode == Viewport) { |
| 390 // The image occupies the full width of its parent <div>. | |
| 383 imageStyle.append("max-width: 100%;"); | 391 imageStyle.append("max-width: 100%;"); |
| 392 } | |
| 384 | 393 |
| 385 // Once the image has fully loaded, it is displayed atop a checkerboard to | |
| 386 // show transparency more faithfully. The pattern is generated via CSS. | |
| 387 if (m_imageIsLoaded) { | 394 if (m_imageIsLoaded) { |
| 388 int newCheckerSize = kBaseCheckerSize; | 395 int newCheckerSize = kBaseCheckerSize; |
| 389 MouseCursorMode newCursorMode = Default; | 396 MouseCursorMode newCursorMode = Default; |
| 390 | 397 |
| 398 // Images are displayed atop a checkerboard to show transparency more | |
| 399 // faithfully. The pattern is generated via CSS. | |
| 391 if (m_shrinkToFitMode == Viewport) { | 400 if (m_shrinkToFitMode == Viewport) { |
| 392 double scale; | 401 if (shouldCenterImage()) { |
| 402 double scale; | |
| 393 | 403 |
| 394 if (hasFinishedParsing()) { | 404 if (hasFinishedParsing()) { |
| 395 // To ensure the checker pattern is visible for large images, the | 405 // To ensure the checker pattern is visible for large images, the |
| 396 // checker size is dynamically adjusted to account for how much the | 406 // checker size is dynamically adjusted to account for how much the |
| 397 // page is currently being scaled. | 407 // page is currently being scaled. |
| 398 scale = frame()->host()->visualViewport().scale(); | 408 scale = frame()->host()->visualViewport().scale(); |
| 399 } else { | 409 } else { |
| 400 // The checker pattern is initialized based on how large the image is | 410 // The checker pattern is initialized based on how large the image |
| 401 // relative to the viewport. | 411 // is relative to the viewport. |
| 402 int viewportWidth = frame()->host()->visualViewport().size().width(); | 412 int viewportWidth = |
| 403 scale = viewportWidth / static_cast<double>(calculateDivWidth()); | 413 frame()->host()->visualViewport().size().width(); |
| 414 scale = viewportWidth / static_cast<double>(calculateDivWidth()); | |
| 415 } | |
| 416 | |
| 417 newCheckerSize = std::round(std::max(1.0, newCheckerSize / scale)); | |
| 404 } | 418 } |
| 405 | |
| 406 newCheckerSize = std::round(std::max(1.0, newCheckerSize / scale)); | |
| 407 } else { | 419 } else { |
| 408 // In desktop mode, the user can click on the image to zoom in or out. | 420 // In desktop mode, the user can click on the image to zoom in or out. |
| 409 DCHECK_EQ(m_shrinkToFitMode, Desktop); | 421 DCHECK_EQ(m_shrinkToFitMode, Desktop); |
| 410 if (imageFitsInWindow()) { | 422 if (imageFitsInWindow()) { |
| 411 newCursorMode = Default; | 423 newCursorMode = Default; |
| 412 } else { | 424 } else { |
| 413 newCursorMode = m_shouldShrinkImage ? ZoomIn : ZoomOut; | 425 newCursorMode = m_shouldShrinkImage ? ZoomIn : ZoomOut; |
| 414 } | 426 } |
| 415 } | 427 } |
| 416 | 428 |
| 417 // The only things that can differ between updates are checker size and | 429 // The only things that can differ between updates are checker size and |
| 418 // the type of cursor being displayed. | 430 // the type of cursor being displayed. |
| 419 if (newCheckerSize == m_styleCheckerSize && | 431 if (newCheckerSize == m_styleCheckerSize && |
| 420 newCursorMode == m_styleMouseCursorMode) { | 432 newCursorMode == m_styleMouseCursorMode) { |
| 421 return; | 433 return; |
| 422 } | 434 } |
| 423 m_styleCheckerSize = newCheckerSize; | 435 m_styleCheckerSize = newCheckerSize; |
| 424 m_styleMouseCursorMode = newCursorMode; | 436 m_styleMouseCursorMode = newCursorMode; |
| 425 | 437 |
| 426 imageStyle.append("background-position: 0px 0px, "); | 438 // Generate the new image style string. |
| 427 imageStyle.append(AtomicString::number(m_styleCheckerSize)); | 439 if (shouldCenterImage()) { |
| 428 imageStyle.append("px "); | 440 imageStyle.append("background-position: 0px 0px, "); |
| 429 imageStyle.append(AtomicString::number(m_styleCheckerSize)); | 441 imageStyle.append(AtomicString::number(m_styleCheckerSize)); |
| 430 imageStyle.append("px;"); | 442 imageStyle.append("px "); |
| 443 imageStyle.append(AtomicString::number(m_styleCheckerSize)); | |
| 444 imageStyle.append("px;"); | |
| 431 | 445 |
| 432 int tileSize = m_styleCheckerSize * 2; | 446 int tileSize = m_styleCheckerSize * 2; |
| 433 imageStyle.append("background-size: "); | 447 imageStyle.append("background-size: "); |
| 434 imageStyle.append(AtomicString::number(tileSize)); | 448 imageStyle.append(AtomicString::number(tileSize)); |
| 435 imageStyle.append("px "); | 449 imageStyle.append("px "); |
| 436 imageStyle.append(AtomicString::number(tileSize)); | 450 imageStyle.append(AtomicString::number(tileSize)); |
| 437 imageStyle.append("px;"); | 451 imageStyle.append("px;"); |
| 438 | 452 |
| 439 // Generating the checkerboard pattern this way is not exactly cheap. | 453 // Generating the checkerboard pattern this way is not exactly cheap. |
| 440 // If rasterization performance becomes an issue, we could look at using | 454 // If rasterization performance becomes an issue, we could look at using |
| 441 // a cheaper shader (e.g. pre-generate a scaled tile + base64-encode + | 455 // a cheaper shader (e.g. pre-generate a scaled tile + base64-encode + |
| 442 // inline dataURI => single bitmap shader). | 456 // inline dataURI => single bitmap shader). |
| 443 imageStyle.append( | 457 imageStyle.append( |
| 444 "background-image:" | 458 "background-image:" |
| 445 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, " | 459 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent " |
| 446 "#eee 75%, #eee 100%)," | 460 "75%, " |
| 447 "linear-gradient(45deg, #eee 25%, white 25%, white 75%, " | 461 "#eee 75%, #eee 100%)," |
| 448 "#eee 75%, #eee 100%);"); | 462 "linear-gradient(45deg, #eee 25%, white 25%, white 75%, " |
| 463 "#eee 75%, #eee 100%);"); | |
| 464 } | |
| 449 | 465 |
| 450 if (m_shrinkToFitMode == Desktop) { | 466 if (m_shrinkToFitMode == Desktop) { |
| 451 if (m_styleMouseCursorMode == ZoomIn) | 467 if (m_styleMouseCursorMode == ZoomIn) |
| 452 imageStyle.append("cursor: zoom-in;"); | 468 imageStyle.append("cursor: zoom-in;"); |
| 453 else if (m_styleMouseCursorMode == ZoomOut) | 469 else if (m_styleMouseCursorMode == ZoomOut) |
| 454 imageStyle.append("cursor: zoom-out;"); | 470 imageStyle.append("cursor: zoom-out;"); |
| 455 } | 471 } |
| 456 } | 472 } |
| 457 } | 473 } |
| 458 | 474 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 520 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); | 536 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); |
| 521 return std::max(viewportWidth, maxWidth); | 537 return std::max(viewportWidth, maxWidth); |
| 522 } | 538 } |
| 523 | 539 |
| 524 void ImageDocument::windowSizeChanged() { | 540 void ImageDocument::windowSizeChanged() { |
| 525 if (!m_imageElement || !m_imageSizeIsKnown || | 541 if (!m_imageElement || !m_imageSizeIsKnown || |
| 526 m_imageElement->document() != this) | 542 m_imageElement->document() != this) |
| 527 return; | 543 return; |
| 528 | 544 |
| 529 if (m_shrinkToFitMode == Viewport) { | 545 if (m_shrinkToFitMode == Viewport) { |
| 530 LayoutSize imageSize = cachedImageSize(m_imageElement); | 546 if (shouldCenterImage()) { |
| 531 int divWidth = calculateDivWidth(); | 547 // Set the size of the <div> containing the <img>. The latter is set |
| 532 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, | 548 // to occupy 100% of the <div>'s width in updateImageStyle(). |
| 533 CSSPrimitiveValue::UnitType::Pixels); | 549 LayoutSize imageSize = cachedImageSize(m_imageElement); |
| 550 int divWidth = calculateDivWidth(); | |
| 551 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, | |
| 552 CSSPrimitiveValue::UnitType::Pixels); | |
| 534 | 553 |
| 535 // Explicitly set the height of the <div> containing the <img> so that it | 554 // Explicitly set the height of the <div> containing the <img> so that it |
| 536 // can display the full image without shrinking it, allowing a full-width | 555 // can display the full image without shrinking it, allowing a full-width |
| 537 // reading mode for normal-width-huge-height images. | 556 // reading mode for normal-width-huge-height images. |
| 538 float viewportAspectRatio = | 557 float viewportAspectRatio = |
| 539 frame()->host()->visualViewport().size().aspectRatio(); | 558 frame()->host()->visualViewport().size().aspectRatio(); |
| 540 int divHeight = std::max(imageSize.height().toInt(), | 559 int divHeight = |
| 541 static_cast<int>(divWidth / viewportAspectRatio)); | 560 std::max(imageSize.height().toInt(), |
| 542 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, | 561 static_cast<int>(divWidth / viewportAspectRatio)); |
| 543 CSSPrimitiveValue::UnitType::Pixels); | 562 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, |
| 563 CSSPrimitiveValue::UnitType::Pixels); | |
| 564 } else { | |
| 565 // Set the max width of the <img> to prevent it from becoming too large. | |
| 566 // See calculateDivWidth() for details. | |
| 567 int viewportWidth = frame()->host()->visualViewport().size().width(); | |
| 568 m_imageElement->setInlineStyleProperty( | |
|
aelias_OOO_until_Jul13
2017/01/19 00:23:49
Could you try instead returning false from ImageDo
| |
| 569 CSSPropertyMaxWidth, viewportWidth * 10, | |
| 570 CSSPrimitiveValue::UnitType::Pixels); | |
| 571 } | |
| 544 return; | 572 return; |
| 545 } | 573 } |
| 546 | 574 |
| 547 bool fitsInWindow = imageFitsInWindow(); | 575 bool fitsInWindow = imageFitsInWindow(); |
| 548 | 576 |
| 549 // If the image has been explicitly zoomed in, restore the cursor if the image | 577 // If the image has been explicitly zoomed in, restore the cursor if the image |
| 550 // fits and set it to a zoom out cursor if the image doesn't fit | 578 // fits and set it to a zoom out cursor if the image doesn't fit |
| 551 if (!m_shouldShrinkImage) { | 579 if (!m_shouldShrinkImage) { |
| 552 updateImageStyle(); | 580 updateImageStyle(); |
| 553 return; | 581 return; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 } | 647 } |
| 620 | 648 |
| 621 bool ImageEventListener::operator==(const EventListener& listener) const { | 649 bool ImageEventListener::operator==(const EventListener& listener) const { |
| 622 if (const ImageEventListener* imageEventListener = | 650 if (const ImageEventListener* imageEventListener = |
| 623 ImageEventListener::cast(&listener)) | 651 ImageEventListener::cast(&listener)) |
| 624 return m_doc == imageEventListener->m_doc; | 652 return m_doc == imageEventListener->m_doc; |
| 625 return false; | 653 return false; |
| 626 } | 654 } |
| 627 | 655 |
| 628 } // namespace blink | 656 } // namespace blink |
| OLD | NEW |