Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: third_party/WebKit/Source/core/html/ImageDocument.cpp

Issue 2445413003: [Blink] Display images on a dark background (Closed)
Patch Set: Rebased Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/html/ImageDocument.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 String fileName = 165 String fileName =
166 decodeURLEscapeSequences(document()->url().lastPathComponent()); 166 decodeURLEscapeSequences(document()->url().lastPathComponent());
167 if (fileName.isEmpty()) 167 if (fileName.isEmpty())
168 fileName = document()->url().host(); 168 fileName = document()->url().host();
169 document()->setTitle(imageTitle(fileName, size)); 169 document()->setTitle(imageTitle(fileName, size));
170 if (isDetached()) 170 if (isDetached())
171 return; 171 return;
172 } 172 }
173 173
174 document()->imageUpdated(); 174 document()->imageUpdated();
175 document()->imageLoaded();
175 } 176 }
176 177
177 if (!isDetached()) 178 if (!isDetached())
178 document()->finishedParsing(); 179 document()->finishedParsing();
179 } 180 }
180 181
181 // -------- 182 // --------
182 183
183 ImageDocument::ImageDocument(const DocumentInit& initializer) 184 ImageDocument::ImageDocument(const DocumentInit& initializer)
184 : HTMLDocument(initializer, ImageDocumentClass), 185 : HTMLDocument(initializer, ImageDocumentClass),
185 m_divElement(nullptr), 186 m_divElement(nullptr),
186 m_imageElement(nullptr), 187 m_imageElement(nullptr),
187 m_imageSizeIsKnown(false), 188 m_imageSizeIsKnown(false),
188 m_didShrinkImage(false), 189 m_didShrinkImage(false),
189 m_shouldShrinkImage(shouldShrinkToFit()), 190 m_shouldShrinkImage(shouldShrinkToFit()),
191 m_imageIsLoaded(false),
192 m_checkerSizeInitialized(false),
193 m_divWidth(0),
190 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport 194 m_shrinkToFitMode(frame()->settings()->viewportEnabled() ? Viewport
191 : Desktop) { 195 : Desktop) {
192 setCompatibilityMode(QuirksMode); 196 setCompatibilityMode(QuirksMode);
193 lockCompatibilityMode(); 197 lockCompatibilityMode();
194 UseCounter::count(*this, UseCounter::ImageDocument); 198 UseCounter::count(*this, UseCounter::ImageDocument);
195 if (!isInMainFrame()) 199 if (!isInMainFrame())
196 UseCounter::count(*this, UseCounter::ImageDocumentInFrame); 200 UseCounter::count(*this, UseCounter::ImageDocumentInFrame);
197 } 201 }
198 202
199 DocumentParser* ImageDocument::createParser() { 203 DocumentParser* ImageDocument::createParser() {
(...skipping 11 matching lines...) Expand all
211 HTMLHeadElement* head = HTMLHeadElement::create(*this); 215 HTMLHeadElement* head = HTMLHeadElement::create(*this);
212 HTMLMetaElement* meta = HTMLMetaElement::create(*this); 216 HTMLMetaElement* meta = HTMLMetaElement::create(*this);
213 meta->setAttribute(nameAttr, "viewport"); 217 meta->setAttribute(nameAttr, "viewport");
214 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1"); 218 meta->setAttribute(contentAttr, "width=device-width, minimum-scale=0.1");
215 head->appendChild(meta); 219 head->appendChild(meta);
216 220
217 HTMLBodyElement* body = HTMLBodyElement::create(*this); 221 HTMLBodyElement* body = HTMLBodyElement::create(*this);
218 222
219 if (shouldShrinkToFit()) { 223 if (shouldShrinkToFit()) {
220 // Display the image prominently centered in the frame. 224 // Display the image prominently centered in the frame.
221 body->setAttribute(styleAttr, "margin: 0px;"); 225 body->setAttribute(styleAttr, "margin: 0px; background: #0e0e0e;");
222 226
223 // See w3c example on how to centering an element: 227 // See w3c example on how to center an element:
224 // https://www.w3.org/Style/Examples/007/center.en.html 228 // https://www.w3.org/Style/Examples/007/center.en.html
225 m_divElement = HTMLDivElement::create(*this); 229 m_divElement = HTMLDivElement::create(*this);
226 m_divElement->setAttribute(styleAttr, 230 m_divElement->setAttribute(styleAttr,
227 "display: flex;" 231 "display: flex;"
228 "flex-direction: column;" 232 "flex-direction: column;"
229 "justify-content: center;" 233 "justify-content: center;"
230 "align-items: center;" 234 "align-items: center;"
231 "min-height: min-content;" 235 "min-height: min-content;"
232 "min-width: min-content;" 236 "min-width: min-content;"
233 "height: 100%;" 237 "height: 100%;"
234 "width: 100%;"); 238 "width: 100%;");
235 HTMLContentElement* content = HTMLContentElement::create(*this); 239 HTMLContentElement* content = HTMLContentElement::create(*this);
236 m_divElement->appendChild(content); 240 m_divElement->appendChild(content);
237 241
238 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot(); 242 ShadowRoot& shadowRoot = body->ensureUserAgentShadowRoot();
239 shadowRoot.appendChild(m_divElement); 243 shadowRoot.appendChild(m_divElement);
240 } else { 244 } else {
241 body->setAttribute(styleAttr, "margin: 0px;"); 245 body->setAttribute(styleAttr, "margin: 0px;");
242 } 246 }
243 247
244 willInsertBody(); 248 willInsertBody();
245 249
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); 250 m_imageElement = HTMLImageElement::create(*this);
251 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString()); 251 updateImageStyle();
252 m_imageElement->setLoadingImageDocument(); 252 m_imageElement->setLoadingImageDocument();
253 m_imageElement->setSrc(url().getString()); 253 m_imageElement->setSrc(url().getString());
254 body->appendChild(m_imageElement.get()); 254 body->appendChild(m_imageElement.get());
255 if (loader() && m_imageElement->cachedImage()) 255 if (loader() && m_imageElement->cachedImage())
256 m_imageElement->cachedImage()->responseReceived(loader()->response(), 256 m_imageElement->cachedImage()->responseReceived(loader()->response(),
257 nullptr); 257 nullptr);
258 258
259 if (shouldShrinkToFit()) { 259 if (shouldShrinkToFit()) {
260 // Add event listeners 260 // Add event listeners
261 EventListener* listener = ImageEventListener::create(this); 261 EventListener* listener = ImageEventListener::create(this);
262 if (LocalDOMWindow* domWindow = this->domWindow()) 262 if (LocalDOMWindow* domWindow = this->domWindow())
263 domWindow->addEventListener("resize", listener, false); 263 domWindow->addEventListener(EventTypeNames::resize, listener, false);
264 if (m_shrinkToFitMode == Desktop) 264
265 m_imageElement->addEventListener("click", listener, false); 265 if (m_shrinkToFitMode == Desktop) {
266 m_imageElement->addEventListener(EventTypeNames::click, listener, false);
267 } else if (m_shrinkToFitMode == Viewport) {
pdr. 2016/10/28 21:20:48 Because many desktops have touchscreens these days
gone 2016/10/28 21:36:20 The touch listeners applied only to viewport mode
pdr. 2016/10/28 22:16:50 ah, sgtm.
268 m_imageElement->addEventListener(EventTypeNames::touchend, listener,
269 false);
270 m_imageElement->addEventListener(EventTypeNames::touchcancel, listener,
271 false);
272 }
266 } 273 }
267 274
268 rootElement->appendChild(head); 275 rootElement->appendChild(head);
269 rootElement->appendChild(body); 276 rootElement->appendChild(body);
270 } 277 }
271 278
272 float ImageDocument::scale() const { 279 float ImageDocument::scale() const {
273 DCHECK_EQ(m_shrinkToFitMode, Desktop); 280 DCHECK_EQ(m_shrinkToFitMode, Desktop);
274 if (!m_imageElement || m_imageElement->document() != this) 281 if (!m_imageElement || m_imageElement->document() != this)
275 return 1.0f; 282 return 1.0f;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 float scrollX = 346 float scrollX =
340 imageX / scale - static_cast<float>(frame()->view()->width()) / 2; 347 imageX / scale - static_cast<float>(frame()->view()->width()) / 2;
341 float scrollY = 348 float scrollY =
342 imageY / scale - static_cast<float>(frame()->view()->height()) / 2; 349 imageY / scale - static_cast<float>(frame()->view()->height()) / 2;
343 350
344 frame()->view()->layoutViewportScrollableArea()->setScrollOffset( 351 frame()->view()->layoutViewportScrollableArea()->setScrollOffset(
345 ScrollOffset(scrollX, scrollY), ProgrammaticScroll); 352 ScrollOffset(scrollX, scrollY), ProgrammaticScroll);
346 } 353 }
347 } 354 }
348 355
356 void ImageDocument::imageLoaded() {
357 m_imageIsLoaded = true;
358 updateImageStyle();
359 }
360
361 void ImageDocument::updateImageStyle() {
362 StringBuilder imageStyle;
363 imageStyle.append("-webkit-user-select: none;");
364 if (shouldShrinkToFit()) {
365 if (m_shrinkToFitMode == Viewport) {
366 imageStyle.append("max-width: 100%;");
367 }
368
369 // Once the image has fully loaded, it is displayed atop a checkerboard to
370 // show transparency more faithfully. The pattern is generated via CSS.
371 if (m_imageIsLoaded) {
372 // The base square size is set to 10 because it rounds nicely for both the
373 // minimum scale (0.1) and maximum scale (5.0).
374 double checkerSize = 10;
375
376 if (m_shrinkToFitMode == Viewport) {
377 // To ensure the checker pattern is visible for large images in
378 // viewports, the checker size must be dynamically adjusted to account
379 // for how much the page is currently being scaled.
380 //
381 // Unfortunately, the page scale is not properly initialized when this
pdr. 2016/10/28 21:20:48 This workaround is unfortunate. Can you think of a
gone 2016/10/28 21:36:20 Yeah, I'm not happy with it either, which is why I
pdr. 2016/10/28 22:16:50 Any idea where 0.367 comes from? Could be worth fi
gone 2016/10/28 23:42:22 Did some more experimentation about found that the
382 // function is called the first time. This workaround determines the
383 // initial scale by comparing the size of the image's container against
384 // the viewport's size (see ImageDocument::windowSizeChanged).
385 double scale =
386 m_checkerSizeInitialized
387 ? frame()->host()->visualViewport().scale()
388 : double(frame()->host()->visualViewport().size().width()) /
389 m_divWidth;
390 checkerSize = std::max(1.0, checkerSize / scale);
391 m_checkerSizeInitialized = true;
392 }
393
394 int roundedSize = static_cast<int>(round(checkerSize));
395 int tileSize = roundedSize * 2;
396
397 imageStyle.append("background-position: 0px 0px, ");
398 imageStyle.append(AtomicString::number(roundedSize));
399 imageStyle.append("px ");
400 imageStyle.append(AtomicString::number(roundedSize));
401 imageStyle.append("px;");
402
403 imageStyle.append("background-size: ");
404 imageStyle.append(AtomicString::number(tileSize));
405 imageStyle.append("px ");
406 imageStyle.append(AtomicString::number(tileSize));
407 imageStyle.append("px;");
408
409 imageStyle.append(
410 "background-color: white;"
411 "background-image:"
412 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, "
413 "#eee 75%, #eee 100%),"
414 "linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, "
415 "#eee 75%, #eee 100%);");
416 }
417 }
418
419 m_imageElement->setAttribute(styleAttr, imageStyle.toAtomicString());
420 }
421
349 void ImageDocument::imageUpdated() { 422 void ImageDocument::imageUpdated() {
350 DCHECK(m_imageElement); 423 DCHECK(m_imageElement);
351 424
352 if (m_imageSizeIsKnown) 425 if (m_imageSizeIsKnown)
353 return; 426 return;
354 427
355 updateStyleAndLayoutTree(); 428 updateStyleAndLayoutTree();
356 if (!m_imageElement->cachedImage() || 429 if (!m_imageElement->cachedImage() ||
357 m_imageElement->cachedImage() 430 m_imageElement->cachedImage()
358 ->imageSize(LayoutObject::shouldRespectImageOrientation( 431 ->imageSize(LayoutObject::shouldRespectImageOrientation(
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 m_imageElement->layoutObject()), 488 m_imageElement->layoutObject()),
416 1.f); 489 1.f);
417 int viewportWidth = frame()->host()->visualViewport().size().width(); 490 int viewportWidth = frame()->host()->visualViewport().size().width();
418 int viewportHeight = frame()->host()->visualViewport().size().height(); 491 int viewportHeight = frame()->host()->visualViewport().size().height();
419 float viewportAspectRatio = (float)viewportWidth / viewportHeight; 492 float viewportAspectRatio = (float)viewportWidth / viewportHeight;
420 493
421 // For huge images, minimum-scale=0.1 is still too big on small screens. 494 // 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 495 // Set the <div> width so that the image will shrink to fit the width of the
423 // screen when the scale is minimum. 496 // screen when the scale is minimum.
424 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10); 497 int maxWidth = std::min(imageSize.width().toInt(), viewportWidth * 10);
425 int divWidth = std::max(viewportWidth, maxWidth); 498 m_divWidth = std::max(viewportWidth, maxWidth);
426 m_divElement->setInlineStyleProperty(CSSPropertyWidth, divWidth, 499 m_divElement->setInlineStyleProperty(CSSPropertyWidth, m_divWidth,
427 CSSPrimitiveValue::UnitType::Pixels); 500 CSSPrimitiveValue::UnitType::Pixels);
428 501
429 // Explicitly set the height of the <div> containing the <img> so that it 502 // 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 503 // can display the full image without shrinking it, allowing a full-width
431 // reading mode for normal-width-huge-height images. 504 // reading mode for normal-width-huge-height images.
432 int divHeight = std::max(imageSize.height().toInt(), 505 int divHeight =
433 (int)(divWidth / viewportAspectRatio)); 506 std::max(imageSize.height().toInt(),
507 static_cast<int>(m_divWidth / viewportAspectRatio));
434 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight, 508 m_divElement->setInlineStyleProperty(CSSPropertyHeight, divHeight,
435 CSSPrimitiveValue::UnitType::Pixels); 509 CSSPrimitiveValue::UnitType::Pixels);
510 updateImageStyle();
436 return; 511 return;
437 } 512 }
438 513
439 bool fitsInWindow = imageFitsInWindow(); 514 bool fitsInWindow = imageFitsInWindow();
440 515
441 // If the image has been explicitly zoomed in, restore the cursor if the image 516 // 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 517 // fits and set it to a zoom out cursor if the image doesn't fit
443 if (!m_shouldShrinkImage) { 518 if (!m_shouldShrinkImage) {
444 if (fitsInWindow) 519 if (fitsInWindow)
445 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor); 520 m_imageElement->removeInlineStyleProperty(CSSPropertyCursor);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 } 563 }
489 564
490 // -------- 565 // --------
491 566
492 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) { 567 void ImageEventListener::handleEvent(ExecutionContext*, Event* event) {
493 if (event->type() == EventTypeNames::resize) { 568 if (event->type() == EventTypeNames::resize) {
494 m_doc->windowSizeChanged(); 569 m_doc->windowSizeChanged();
495 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) { 570 } else if (event->type() == EventTypeNames::click && event->isMouseEvent()) {
496 MouseEvent* mouseEvent = toMouseEvent(event); 571 MouseEvent* mouseEvent = toMouseEvent(event);
497 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y()); 572 m_doc->imageClicked(mouseEvent->x(), mouseEvent->y());
573 } else if (event->isTouchEvent()) {
574 m_doc->updateImageStyle();
498 } 575 }
499 } 576 }
500 577
501 bool ImageEventListener::operator==(const EventListener& listener) const { 578 bool ImageEventListener::operator==(const EventListener& listener) const {
502 if (const ImageEventListener* imageEventListener = 579 if (const ImageEventListener* imageEventListener =
503 ImageEventListener::cast(&listener)) 580 ImageEventListener::cast(&listener))
504 return m_doc == imageEventListener->m_doc; 581 return m_doc == imageEventListener->m_doc;
505 return false; 582 return false;
506 } 583 }
507 584
508 } // namespace blink 585 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/ImageDocument.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698