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

Side by Side Diff: Source/core/rendering/RenderImage.cpp

Issue 481753002: Use Shadow DOM to display fallback content for images (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Updated Created 6 years, 3 months 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org) 4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) 5 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
6 * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) 6 * (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved. 7 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved.
8 * Copyright (C) 2010 Google Inc. All rights reserved. 8 * Copyright (C) 2010 Google Inc. All rights reserved.
9 * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved. 9 * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
10 * 10 *
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 float deviceScaleFactor(LocalFrame*); 56 float deviceScaleFactor(LocalFrame*);
57 57
58 using namespace HTMLNames; 58 using namespace HTMLNames;
59 59
60 RenderImage::RenderImage(Element* element) 60 RenderImage::RenderImage(Element* element)
61 : RenderReplaced(element, IntSize()) 61 : RenderReplaced(element, IntSize())
62 , m_didIncrementVisuallyNonEmptyPixelCount(false) 62 , m_didIncrementVisuallyNonEmptyPixelCount(false)
63 , m_isGeneratedContent(false) 63 , m_isGeneratedContent(false)
64 , m_imageDevicePixelRatio(1.0f) 64 , m_imageDevicePixelRatio(1.0f)
65 { 65 {
66 updateAltText();
67 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObj ect(this); 66 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addRenderObj ect(this);
68 } 67 }
69 68
70 RenderImage* RenderImage::createAnonymous(Document* document) 69 RenderImage* RenderImage::createAnonymous(Document* document)
71 { 70 {
72 RenderImage* image = new RenderImage(0); 71 RenderImage* image = new RenderImage(0);
73 image->setDocumentForAnonymous(document); 72 image->setDocumentForAnonymous(document);
74 return image; 73 return image;
75 } 74 }
76 75
77 RenderImage::~RenderImage() 76 RenderImage::~RenderImage()
78 { 77 {
79 } 78 }
80 79
81 void RenderImage::destroy() 80 void RenderImage::destroy()
82 { 81 {
83 ASSERT(m_imageResource); 82 ASSERT(m_imageResource);
84 m_imageResource->shutdown(); 83 m_imageResource->shutdown();
85 RenderReplaced::destroy(); 84 RenderReplaced::destroy();
86 } 85 }
87 86
88 void RenderImage::setImageResource(PassOwnPtr<RenderImageResource> imageResource ) 87 void RenderImage::setImageResource(PassOwnPtr<RenderImageResource> imageResource )
89 { 88 {
90 ASSERT(!m_imageResource); 89 ASSERT(!m_imageResource);
91 m_imageResource = imageResource; 90 m_imageResource = imageResource;
92 m_imageResource->initialize(this); 91 m_imageResource->initialize(this);
93 } 92 }
94 93
95 // If we'll be displaying either alt text or an image, add some padding.
96 static const unsigned short paddingWidth = 4;
97 static const unsigned short paddingHeight = 4;
98
99 // Alt text is restricted to this maximum size, in pixels. These are
100 // signed integers because they are compared with other signed values.
101 static const float maxAltTextWidth = 1024;
102 static const int maxAltTextHeight = 256;
103
104 IntSize RenderImage::imageSizeForError(ImageResource* newImage) const
105 {
106 ASSERT_ARG(newImage, newImage);
107 ASSERT_ARG(newImage, newImage->imageForRenderer(this));
108
109 IntSize imageSize;
110 if (newImage->willPaintBrokenImage()) {
111 float deviceScaleFactor = blink::deviceScaleFactor(frame());
112 pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brok enImage(deviceScaleFactor);
113 imageSize = brokenImageAndImageScaleFactor.first->size();
114 imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
115 } else
116 imageSize = newImage->imageForRenderer(this)->size();
117
118 // imageSize() returns 0 for the error image. We need the true size of the
119 // error image, so we have to get it by grabbing image() directly.
120 return IntSize(paddingWidth + imageSize.width() * style()->effectiveZoom(), paddingHeight + imageSize.height() * style()->effectiveZoom());
121 }
122
123 // Sets the image height and width to fit the alt text. Returns true if the
124 // image size changed.
125 bool RenderImage::setImageSizeForAltText(ImageResource* newImage /* = 0 */)
126 {
127 IntSize imageSize;
128 if (newImage && newImage->imageForRenderer(this))
129 imageSize = imageSizeForError(newImage);
130 else if (!m_altText.isEmpty() || newImage) {
131 // If we'll be displaying either text or an image, add a little padding.
132 imageSize = IntSize(paddingWidth, paddingHeight);
133 }
134
135 // we have an alt and the user meant it (its not a text we invented)
136 if (!m_altText.isEmpty()) {
137 FontCachePurgePreventer fontCachePurgePreventer;
138
139 const Font& font = style()->font();
140 IntSize paddedTextSize(paddingWidth + std::min(ceilf(font.width(construc tTextRun(this, font, m_altText, style()))), maxAltTextWidth), paddingHeight + st d::min(font.fontMetrics().height(), maxAltTextHeight));
141 imageSize = imageSize.expandedTo(paddedTextSize);
142 }
143
144 if (imageSize == intrinsicSize())
145 return false;
146
147 setIntrinsicSize(imageSize);
148 return true;
149 }
150
151 void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) 94 void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect)
152 { 95 {
153 if (documentBeingDestroyed()) 96 if (documentBeingDestroyed())
154 return; 97 return;
155 98
156 if (hasBoxDecorationBackground() || hasMask() || hasShapeOutside()) 99 if (hasBoxDecorationBackground() || hasMask() || hasShapeOutside())
157 RenderReplaced::imageChanged(newImage, rect); 100 RenderReplaced::imageChanged(newImage, rect);
158 101
159 if (!m_imageResource) 102 if (!m_imageResource)
160 return; 103 return;
161 104
162 if (newImage != m_imageResource->imagePtr()) 105 if (newImage != m_imageResource->imagePtr())
163 return; 106 return;
164 107
165 // Per the spec, we let the server-sent header override srcset/other sources of dpr. 108 // Per the spec, we let the server-sent header override srcset/other sources of dpr.
166 // https://github.com/igrigorik/http-client-hints/blob/master/draft-grigorik -http-client-hints-01.txt#L255 109 // https://github.com/igrigorik/http-client-hints/blob/master/draft-grigorik -http-client-hints-01.txt#L255
167 if (m_imageResource->cachedImage() && m_imageResource->cachedImage()->hasDev icePixelRatioHeaderValue()) 110 if (m_imageResource->cachedImage() && m_imageResource->cachedImage()->hasDev icePixelRatioHeaderValue())
168 m_imageDevicePixelRatio = 1 / m_imageResource->cachedImage()->devicePixe lRatioHeaderValue(); 111 m_imageDevicePixelRatio = 1 / m_imageResource->cachedImage()->devicePixe lRatioHeaderValue();
169 112
170 if (!m_didIncrementVisuallyNonEmptyPixelCount) { 113 if (!m_didIncrementVisuallyNonEmptyPixelCount) {
171 // At a zoom level of 1 the image is guaranteed to have an integer size. 114 // At a zoom level of 1 the image is guaranteed to have an integer size.
172 view()->frameView()->incrementVisuallyNonEmptyPixelCount(flooredIntSize( m_imageResource->imageSize(1.0f))); 115 view()->frameView()->incrementVisuallyNonEmptyPixelCount(flooredIntSize( m_imageResource->imageSize(1.0f)));
173 m_didIncrementVisuallyNonEmptyPixelCount = true; 116 m_didIncrementVisuallyNonEmptyPixelCount = true;
174 } 117 }
175 118
176 bool imageSizeChanged = false; 119 repaintOrMarkForLayout(rect);
177
178 // Set image dimensions, taking into account the size of the alt text.
179 if (m_imageResource->errorOccurred() || !newImage)
180 imageSizeChanged = setImageSizeForAltText(m_imageResource->cachedImage() );
181
182 paintInvalidationOrMarkForLayout(imageSizeChanged, rect);
183 } 120 }
184 121
185 void RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize) 122 void RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize)
186 { 123 {
187 if (m_imageResource->errorOccurred() || !m_imageResource->hasImage()) 124 if (m_imageResource->errorOccurred() || !m_imageResource->hasImage())
188 return; 125 return;
189 setIntrinsicSize(newSize); 126 setIntrinsicSize(newSize);
190 } 127 }
191 128
192 void RenderImage::updateInnerContentRect() 129 void RenderImage::updateInnerContentRect()
193 { 130 {
194 // Propagate container size to the image resource. 131 // Propagate container size to the image resource.
195 LayoutRect containerRect = replacedContentRect(); 132 LayoutRect containerRect = replacedContentRect();
196 IntSize containerSize(containerRect.width(), containerRect.height()); 133 IntSize containerSize(containerRect.width(), containerRect.height());
197 if (!containerSize.isEmpty()) 134 if (!containerSize.isEmpty())
198 m_imageResource->setContainerSizeForRenderer(containerSize); 135 m_imageResource->setContainerSizeForRenderer(containerSize);
199 } 136 }
200 137
201 void RenderImage::paintInvalidationOrMarkForLayout(bool imageSizeChangedToAccomo dateAltText, const IntRect* rect) 138 void RenderImage::repaintOrMarkForLayout(const IntRect* rect)
202 { 139 {
203 LayoutSize oldIntrinsicSize = intrinsicSize(); 140 LayoutSize oldIntrinsicSize = intrinsicSize();
204 LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(style()->effect iveZoom()); 141 LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(style()->effect iveZoom());
205 updateIntrinsicSizeIfNeeded(newIntrinsicSize); 142 updateIntrinsicSizeIfNeeded(newIntrinsicSize);
206 143
207 // In the case of generated image content using :before/:after/content, we m ight not be 144 // In the case of generated image content using :before/:after/content, we m ight not be
208 // in the render tree yet. In that case, we just need to update our intrinsi c size. 145 // in the render tree yet. In that case, we just need to update our intrinsi c size.
209 // layout() will be called after we are inserted in the tree which will take care of 146 // layout() will be called after we are inserted in the tree which will take care of
210 // what we are doing here. 147 // what we are doing here.
211 if (!containingBlock()) 148 if (!containingBlock())
212 return; 149 return;
213 150
214 bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || ima geSizeChangedToAccomodateAltText; 151 bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize;
215 if (imageSourceHasChangedSize) 152 if (imageSourceHasChangedSize)
216 setPreferredLogicalWidthsDirty(); 153 setPreferredLogicalWidthsDirty();
217 154
218 // If the actual area occupied by the image has changed and it is not constr ained by style then a layout is required. 155 // If the actual area occupied by the image has changed and it is not constr ained by style then a layout is required.
219 bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style ()->logicalHeight().isSpecified(); 156 bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style ()->logicalHeight().isSpecified();
220 157
221 // FIXME: We only need to recompute the containing block's preferred size if the containing block's size 158 // FIXME: We only need to recompute the containing block's preferred size if the containing block's size
222 // depends on the image's size (i.e., the container uses shrink-to-fit sizin g). 159 // depends on the image's size (i.e., the container uses shrink-to-fit sizin g).
223 // There's no easy way to detect that shrink-to-fit is needed, always force a layout. 160 // There's no easy way to detect that shrink-to-fit is needed, always force a layout.
224 bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth(). isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWid th().isPercent(); 161 bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth(). isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWid th().isPercent();
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 contentChanged(ImageChanged); 213 contentChanged(ImageChanged);
277 } 214 }
278 } 215 }
279 216
280 void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf fset) 217 void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf fset)
281 { 218 {
282 LayoutUnit cWidth = contentWidth(); 219 LayoutUnit cWidth = contentWidth();
283 LayoutUnit cHeight = contentHeight(); 220 LayoutUnit cHeight = contentHeight();
284 221
285 GraphicsContext* context = paintInfo.context; 222 GraphicsContext* context = paintInfo.context;
286 223 if (!m_imageResource->hasImage()) {
287 if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) {
288 if (paintInfo.phase == PaintPhaseSelection) 224 if (paintInfo.phase == PaintPhaseSelection)
289 return; 225 return;
290 226
291 if (cWidth > 2 && cHeight > 2) { 227 if (cWidth > 2 && cHeight > 2) {
292 const int borderWidth = 1;
293
294 LayoutUnit leftBorder = borderLeft();
295 LayoutUnit topBorder = borderTop();
296 LayoutUnit leftPad = paddingLeft();
297 LayoutUnit topPad = paddingTop();
298
299 // Draw an outline rect where the image should be. 228 // Draw an outline rect where the image should be.
300 context->setStrokeStyle(SolidStroke); 229 context->setStrokeStyle(SolidStroke);
301 context->setStrokeColor(Color::lightGray); 230 context->setStrokeColor(Color::lightGray);
302 context->setFillColor(Color::transparent); 231 context->setFillColor(Color::transparent);
303 context->drawRect(pixelSnappedIntRect(LayoutRect(paintOffset.x() + l eftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight))); 232 context->drawRect(pixelSnappedIntRect(LayoutRect(paintOffset.x() + b orderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop(), cWidt h, cHeight)));
esprehn 2014/09/05 00:47:52 What is this drawing?
rhogan 2014/09/08 19:52:43 This is for when an image has no src and no alt te
304
305 bool errorPictureDrawn = false;
306 LayoutSize imageOffset;
307 // When calculating the usable dimensions, exclude the pixels of
308 // the ouline rect so the error image/alt text doesn't draw on it.
309 LayoutUnit usableWidth = cWidth - 2 * borderWidth;
310 LayoutUnit usableHeight = cHeight - 2 * borderWidth;
311
312 RefPtr<Image> image = m_imageResource->image();
313
314 if (m_imageResource->errorOccurred() && !image->isNull() && usableWi dth >= image->width() && usableHeight >= image->height()) {
315 float deviceScaleFactor = blink::deviceScaleFactor(frame());
316 // Call brokenImage() explicitly to ensure we get the broken ima ge icon at the appropriate resolution.
317 pair<Image*, float> brokenImageAndImageScaleFactor = ImageResour ce::brokenImage(deviceScaleFactor);
318 image = brokenImageAndImageScaleFactor.first;
319 IntSize imageSize = image->size();
320 imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
321 // Center the error image, accounting for border and padding.
322 LayoutUnit centerX = (usableWidth - imageSize.width()) / 2;
323 if (centerX < 0)
324 centerX = 0;
325 LayoutUnit centerY = (usableHeight - imageSize.height()) / 2;
326 if (centerY < 0)
327 centerY = 0;
328 imageOffset = LayoutSize(leftBorder + leftPad + centerX + border Width, topBorder + topPad + centerY + borderWidth);
329 context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(p aintOffset + imageOffset, imageSize)), CompositeSourceOver, shouldRespectImageOr ientation());
330 errorPictureDrawn = true;
331 }
332
333 if (!m_altText.isEmpty()) {
334 const Font& font = style()->font();
335 const FontMetrics& fontMetrics = font.fontMetrics();
336 LayoutUnit ascent = fontMetrics.ascent();
337 LayoutPoint textRectOrigin = paintOffset;
338 textRectOrigin.move(leftBorder + leftPad + (paddingWidth / 2) - borderWidth, topBorder + topPad + (paddingHeight / 2) - borderWidth);
339 LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent);
340
341 // Only draw the alt text if it'll fit within the content box,
342 // and only if it fits above the error image.
343 TextRun textRun = constructTextRun(this, font, m_altText, style( ), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTex tRunFlags | RespectDirection);
344 float textWidth = font.width(textRun);
345 TextRunPaintInfo textRunPaintInfo(textRun);
346 textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(te xtWidth, fontMetrics.height()));
347 context->setFillColor(resolveColor(CSSPropertyColor));
348 if (textRun.direction() == RTL) {
349 int availableWidth = cWidth - static_cast<int>(paddingWidth) ;
350 textOrigin.move(availableWidth - ceilf(textWidth), 0);
351 }
352 if (errorPictureDrawn) {
353 if (usableWidth >= textWidth && fontMetrics.height() <= imag eOffset.height())
354 context->drawBidiText(font, textRunPaintInfo, textOrigin );
355 } else if (usableWidth >= textWidth && usableHeight >= fontMetri cs.height()) {
356 context->drawBidiText(font, textRunPaintInfo, textOrigin);
357 }
358 }
359 } 233 }
360 } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) { 234 } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) {
361 LayoutRect contentRect = contentBoxRect(); 235 LayoutRect contentRect = contentBoxRect();
362 contentRect.moveBy(paintOffset); 236 contentRect.moveBy(paintOffset);
363 LayoutRect paintRect = replacedContentRect(); 237 LayoutRect paintRect = replacedContentRect();
364 paintRect.moveBy(paintOffset); 238 paintRect.moveBy(paintOffset);
365 bool clip = !contentRect.contains(paintRect); 239 bool clip = !contentRect.contains(paintRect);
366 if (clip) { 240 if (clip) {
367 context->save(); 241 context->save();
368 context->clip(contentRect); 242 context->clip(contentRect);
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 } 409 }
536 } 410 }
537 411
538 if (!inside && result.isRectBasedTest()) 412 if (!inside && result.isRectBasedTest())
539 result.append(tempResult); 413 result.append(tempResult);
540 if (inside) 414 if (inside)
541 result = tempResult; 415 result = tempResult;
542 return inside; 416 return inside;
543 } 417 }
544 418
545 void RenderImage::updateAltText()
546 {
547 if (!node())
548 return;
549
550 if (isHTMLInputElement(*node()))
551 m_altText = toHTMLInputElement(node())->altText();
552 else if (isHTMLImageElement(*node()))
553 m_altText = toHTMLImageElement(node())->altText();
554 }
555
556 void RenderImage::layout() 419 void RenderImage::layout()
557 { 420 {
558 LayoutRect oldContentRect = replacedContentRect(); 421 LayoutRect oldContentRect = replacedContentRect();
559 RenderReplaced::layout(); 422 RenderReplaced::layout();
560 if (replacedContentRect() != oldContentRect) { 423 if (replacedContentRect() != oldContentRect) {
561 setShouldDoFullPaintInvalidation(true); 424 setShouldDoFullPaintInvalidation(true);
562 updateInnerContentRect(); 425 updateInnerContentRect();
563 } 426 }
564 } 427 }
565 428
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 return 0; 490 return 0;
628 491
629 ImageResource* cachedImage = m_imageResource->cachedImage(); 492 ImageResource* cachedImage = m_imageResource->cachedImage();
630 if (cachedImage && cachedImage->image() && cachedImage->image()->isSVGImage( )) 493 if (cachedImage && cachedImage->image() && cachedImage->image()->isSVGImage( ))
631 return toSVGImage(cachedImage->image())->embeddedContentBox(); 494 return toSVGImage(cachedImage->image())->embeddedContentBox();
632 495
633 return 0; 496 return 0;
634 } 497 }
635 498
636 } // namespace blink 499 } // namespace blink
OLDNEW
« Source/core/rendering/RenderBox.cpp ('K') | « Source/core/rendering/RenderImage.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698