Changeset 181720 in webkit
- Timestamp:
- Mar 18, 2015 7:15:00 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r181712 r181720 1 2015-03-18 Said Abou-Hallawa <sabouhallawa@apple.com> 2 3 Switching between two SVG images with no intrinsic sizes causes them to get the default SVG size instead of the container size. 4 https://bugs.webkit.org/show_bug.cgi?id=142805. 5 6 Reviewed by Darin Adler. 7 8 * svg/as-image/svg-no-intrinsic-size-switching-expected.html: Added. 9 * svg/as-image/svg-no-intrinsic-size-switching.html: Added. 10 Ensure that switching the source of an <img> element between two SVG images, 11 which have no intrinsic sizes, gets the image the size of the container and 12 not the default SVG intrinsic size which is 300x150 pixels. 13 1 14 2015-03-18 Alexey Proskuryakov <ap@apple.com> 2 15 -
trunk/Source/WebCore/ChangeLog
r181713 r181720 1 2015-03-18 Said Abou-Hallawa <sabouhallawa@apple.com> 2 3 Switching between two SVG images with no intrinsic sizes causes them to get the default SVG size instead of the container size. 4 https://bugs.webkit.org/show_bug.cgi?id=142805. 5 6 Reviewed by Darin Adler. 7 8 The bug happens due to wrong logic in RenderImage::imageDimensionsChanged(). 9 This function decides to setNeedsLayout() if the intrinsic size of the image 10 changes. If the size does not change, it only repaints the image rectangle. 11 When switching the src of the an image between two SVG images and both of 12 them have no intrinsic size, we do not updateInnerContentRect() and this 13 means an SVGImageForContainer is not going to be created for this image. 14 When the image is drawn, it is drawn directly from the SVGImage. And this 15 means the drawing has to be scaled by container_size / SVG_default_intrinsic_size 16 17 After figuring out that I need to updateInnerContentRect() to fix this bug, 18 I found out Blink has already changed this code to do the same thing. But 19 they also did more clean-up in this function. Here is the link 20 https://codereview.chromium.org/114323004. I think their change seems correct 21 although they did not say what exactly they were trying to fix. 22 23 The plan for repaintOrMarkForLayout(), which is the new name of this function, 24 is the following: 25 -- setNeedLayout() if the intrinsic size changes and it affects the size 26 of the image. 27 -- updateInnerContentRect() if the intrinsic size did not change but the 28 image has exiting layout. 29 -- repaint the image rectangle if layout is not needed. 30 31 This change also removes the call to computeLogicalWidthInRegion(), which is 32 almost running a layout for the image. This call figures out whether the image 33 needs to setNeedsLayout(). This call is unnecessary; the image needs to run a 34 layout if the intrinsic size has changed and it affects the size of the image. 35 36 Test: svg/as-image/svg-no-intrinsic-size-switching.html 37 38 * rendering/RenderImage.cpp: 39 (WebCore::RenderImage::styleDidChange): Change the function call. 40 (WebCore::RenderImage::imageChanged): Rename local variable and change the 41 function call. 42 43 (WebCore::RenderImage::updateIntrinsicSizeIfNeeded): Simplify this function. 44 Call setIntrinsicSize() with the new size unless the image is in error state. 45 46 (WebCore::RenderImage::repaintOrMarkForLayout): This a better name for this 47 function since it is called even if the intrinsic size was not changed. 48 (WebCore::RenderImage::imageDimensionsChanged): Deleted. 49 50 * rendering/RenderImage.h: Rename imageDimensionsChanged() and change the 51 updateIntrinsicSizeIfNeeded() to return void. 52 53 * rendering/svg/RenderSVGForeignObject.cpp: 54 (WebCore::RenderSVGForeignObject::paint): Code cleanup. This function can 55 only handle the paint phases PaintPhaseForeground and PaintPhaseSelection. 56 Use this information to simplify the logic and order of painting there. 57 1 58 2015-03-18 Jeremy Jones <jeremyj@apple.com> 2 59 -
trunk/Source/WebCore/rendering/RenderImage.cpp
r181505 r181720 181 181 // Sets the image height and width to fit the alt text. Returns true if the 182 182 // image size changed. 183 boolRenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */)183 ImageSizeChangeType RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */) 184 184 { 185 185 IntSize imageSize; … … 199 199 200 200 if (imageSize == intrinsicSize()) 201 return false;201 return ImageSizeChangeNone; 202 202 203 203 setIntrinsicSize(imageSize); 204 return true;204 return ImageSizeChangeForAltText; 205 205 } 206 206 … … 210 210 if (m_needsToSetSizeForAltText) { 211 211 if (!m_altText.isEmpty() && setImageSizeForAltText(imageResource().cachedImage())) 212 imageDimensionsChanged(true /* imageSizeChanged */);212 repaintOrMarkForLayout(ImageSizeChangeForAltText); 213 213 m_needsToSetSizeForAltText = false; 214 214 } 215 215 #if ENABLE(CSS_IMAGE_ORIENTATION) 216 216 if (diff == StyleDifferenceLayout && oldStyle->imageOrientation() != style().imageOrientation()) 217 return imageDimensionsChanged(true /* imageSizeChanged */);217 return repaintOrMarkForLayout(ImageSizeChangeForAltText); 218 218 #endif 219 219 … … 223 223 || oldStyle->imageResolutionSnap() != style().imageResolutionSnap() 224 224 || oldStyle->imageResolutionSource() != style().imageResolutionSource())) 225 imageDimensionsChanged(true /* imageSizeChanged */);225 repaintOrMarkForLayout(ImageSizeChangeForAltText; 226 226 #endif 227 227 } … … 247 247 } 248 248 249 bool imageSizeChanged = false;249 ImageSizeChangeType imageSizeChange = ImageSizeChangeNone; 250 250 251 251 // Set image dimensions, taking into account the size of the alt text. … … 259 259 return; 260 260 } 261 imageSizeChanged = setImageSizeForAltText(imageResource().cachedImage()); 262 } 263 264 imageDimensionsChanged(imageSizeChanged, rect); 265 } 266 267 bool RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize, bool imageSizeChanged) 268 { 269 if (newSize == intrinsicSize() && !imageSizeChanged) 270 return false; 271 if (imageResource().errorOccurred()) 272 return imageSizeChanged; 261 imageSizeChange = setImageSizeForAltText(imageResource().cachedImage()); 262 } 263 264 repaintOrMarkForLayout(imageSizeChange, rect); 265 } 266 267 void RenderImage::updateIntrinsicSizeIfNeeded(const LayoutSize& newSize) 268 { 269 if (imageResource().errorOccurred() || !m_imageResource->hasImage()) 270 return; 273 271 setIntrinsicSize(newSize); 274 return true;275 272 } 276 273 … … 283 280 } 284 281 285 void RenderImage:: imageDimensionsChanged(bool imageSizeChanged, const IntRect* rect)282 void RenderImage::repaintOrMarkForLayout(ImageSizeChangeType imageSizeChange, const IntRect* rect) 286 283 { 287 284 #if ENABLE(CSS_IMAGE_RESOLUTION) … … 291 288 if (scale <= 0) 292 289 scale = 1; 293 bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(imageResource().intrinsicSize(style().effectiveZoom() / scale), imageSizeChanged);290 LayoutSize newIntrinsicSize = imageResource().intrinsicSize(style().effectiveZoom() / scale); 294 291 #else 295 bool intrinsicSizeChanged = updateIntrinsicSizeIfNeeded(imageResource().intrinsicSize(style().effectiveZoom()), imageSizeChanged); 296 #endif 292 LayoutSize newIntrinsicSize = imageResource().intrinsicSize(style().effectiveZoom()); 293 #endif 294 LayoutSize oldIntrinsicSize = intrinsicSize(); 295 296 updateIntrinsicSizeIfNeeded(newIntrinsicSize); 297 297 298 298 // In the case of generated image content using :before/:after/content, we might not be … … 303 303 return; 304 304 305 bool shouldRepaint = true; 306 if (intrinsicSizeChanged) { 307 if (!preferredLogicalWidthsDirty()) 308 setPreferredLogicalWidthsDirty(true); 309 310 bool hasOverrideSize = hasOverrideHeight() || hasOverrideWidth(); 311 if (!hasOverrideSize && !imageSizeChanged) { 312 LogicalExtentComputedValues computedValues; 313 computeLogicalWidthInRegion(computedValues); 314 LayoutUnit newWidth = computedValues.m_extent; 315 computeLogicalHeight(height(), 0, computedValues); 316 LayoutUnit newHeight = computedValues.m_extent; 317 318 imageSizeChanged = width() != newWidth || height() != newHeight; 319 } 320 321 // FIXME: We only need to recompute the containing block's preferred size 322 // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). 323 // There's no easy way to detect that shrink-to-fit is needed, always force a layout. 324 bool containingBlockNeedsToRecomputePreferredSize = 325 style().logicalWidth().isPercent() 326 || style().logicalMaxWidth().isPercent() 327 || style().logicalMinWidth().isPercent(); 328 329 bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; 330 331 if (imageSizeChanged || hasOverrideSize || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { 332 shouldRepaint = false; 333 if (!selfNeedsLayout()) 334 setNeedsLayout(); 335 } 336 337 if (everHadLayout() && !selfNeedsLayout()) { 338 // The inner content rectangle is calculated during layout, but may need an update now 339 // (unless the box has already been scheduled for layout). In order to calculate it, we 340 // may need values from the containing block, though, so make sure that we're not too 341 // early. It may be that layout hasn't even taken place once yet. 342 343 // FIXME: we should not have to trigger another call to setContainerSizeForRenderer() 344 // from here, since it's already being done during layout. 345 updateInnerContentRect(); 346 } 347 } 348 349 if (shouldRepaint) { 350 LayoutRect repaintRect; 351 if (rect) { 352 // The image changed rect is in source image coordinates (pre-zooming), 353 // so map from the bounds of the image to the contentsBox. 354 repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageResource().imageSize(1.0f)), contentBoxRect())); 355 // Guard against too-large changed rects. 356 repaintRect.intersect(contentBoxRect()); 357 } else 358 repaintRect = contentBoxRect(); 305 bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChange != ImageSizeChangeNone; 306 307 if (imageSourceHasChangedSize) 308 setPreferredLogicalWidthsDirty(true); 309 310 // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. 311 bool imageSizeIsConstrained = style().logicalWidth().isSpecified() && style().logicalHeight().isSpecified(); 312 bool needsLayout = !imageSizeIsConstrained && imageSourceHasChangedSize; 313 314 // FIXME: We only need to recompute the containing block's preferred size 315 // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). 316 // There's no easy way to detect that shrink-to-fit is needed, always force a layout. 317 bool containingBlockNeedsToRecomputePreferredSize = 318 style().logicalWidth().isPercent() 319 || style().logicalMaxWidth().isPercent() 320 || style().logicalMinWidth().isPercent(); 321 322 bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; 323 324 if (needsLayout || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { 325 setNeedsLayout(); 326 return; 327 } 328 329 if (everHadLayout() && !selfNeedsLayout()) { 330 // The inner content rectangle is calculated during layout, but may need an update now 331 // (unless the box has already been scheduled for layout). In order to calculate it, we 332 // may need values from the containing block, though, so make sure that we're not too 333 // early. It may be that layout hasn't even taken place once yet. 334 335 // FIXME: we should not have to trigger another call to setContainerSizeForRenderer() 336 // from here, since it's already being done during layout. 337 updateInnerContentRect(); 338 } 339 340 LayoutRect repaintRect = contentBoxRect(); 341 if (rect) { 342 // The image changed rect is in source image coordinates (pre-zooming), 343 // so map from the bounds of the image to the contentsBox. 344 repaintRect.intersect(enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageResource().imageSize(1.0f)), repaintRect))); 345 } 359 346 360 repaintRectangle(repaintRect); 361 362 // Tell any potential compositing layers that the image needs updating. 363 contentChanged(ImageChanged); 364 } 347 repaintRectangle(repaintRect); 348 349 // Tell any potential compositing layers that the image needs updating. 350 contentChanged(ImageChanged); 365 351 } 366 352 -
trunk/Source/WebCore/rendering/RenderImage.h
r181412 r181720 34 34 class HTMLMapElement; 35 35 36 enum ImageSizeChangeType { 37 ImageSizeChangeNone, 38 ImageSizeChangeForAltText 39 }; 40 36 41 class RenderImage : public RenderReplaced { 37 42 public: … … 44 49 CachedImage* cachedImage() const { return imageResource().cachedImage(); } 45 50 46 bool setImageSizeForAltText(CachedImage* newImage = 0);51 ImageSizeChangeType setImageSizeForAltText(CachedImage* newImage = nullptr); 47 52 48 53 void updateAltText(); … … 75 80 virtual void styleDidChange(StyleDifference, const RenderStyle*) override final; 76 81 77 virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) override;82 virtual void imageChanged(WrappedImagePtr, const IntRect* = nullptr) override; 78 83 79 84 void paintIntoRect(GraphicsContext*, const FloatRect&); … … 108 113 109 114 IntSize imageSizeForError(CachedImage*) const; 110 void imageDimensionsChanged(bool imageSizeChanged, const IntRect* = 0);111 bool updateIntrinsicSizeIfNeeded(const LayoutSize&, bool imageSizeChanged);115 void repaintOrMarkForLayout(ImageSizeChangeType, const IntRect* = nullptr); 116 void updateIntrinsicSizeIfNeeded(const LayoutSize&); 112 117 // Update the size of the image to be rendered. Object-fit may cause this to be different from the CSS box's content rect. 113 118 void updateInnerContentRect(); -
trunk/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp
r179982 r181720 54 54 void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) 55 55 { 56 if (paintInfo.context->paintingDisabled() 57 || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) 56 if (paintInfo.context->paintingDisabled()) 57 return; 58 59 if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection) 58 60 return; 59 61 … … 66 68 67 69 SVGRenderingContext renderingContext; 68 bool continueRendering = true;69 70 if (paintInfo.phase == PaintPhaseForeground) { 70 71 renderingContext.prepareToRenderSVGContent(*this, childPaintInfo); 71 continueRendering = renderingContext.isRenderingPrepared(); 72 if (!renderingContext.isRenderingPrepared()) 73 return; 72 74 } 73 75 74 if (continueRendering) { 75 // Paint all phases of FO elements atomically, as though the FO element established its 76 // own stacking context. 77 bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; 78 LayoutPoint childPoint = IntPoint(); 79 childPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 80 RenderBlock::paint(childPaintInfo, IntPoint()); 81 if (!preservePhase) { 82 childPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 83 RenderBlock::paint(childPaintInfo, childPoint); 84 childPaintInfo.phase = PaintPhaseFloat; 85 RenderBlock::paint(childPaintInfo, childPoint); 86 childPaintInfo.phase = PaintPhaseForeground; 87 RenderBlock::paint(childPaintInfo, childPoint); 88 childPaintInfo.phase = PaintPhaseOutline; 89 RenderBlock::paint(childPaintInfo, childPoint); 90 } 76 LayoutPoint childPoint = IntPoint(); 77 if (paintInfo.phase == PaintPhaseSelection) { 78 RenderBlock::paint(childPaintInfo, childPoint); 79 return; 91 80 } 81 82 // Paint all phases of FO elements atomically, as though the FO element established its 83 // own stacking context. 84 childPaintInfo.phase = PaintPhaseBlockBackground; 85 RenderBlock::paint(childPaintInfo, childPoint); 86 childPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 87 RenderBlock::paint(childPaintInfo, childPoint); 88 childPaintInfo.phase = PaintPhaseFloat; 89 RenderBlock::paint(childPaintInfo, childPoint); 90 childPaintInfo.phase = PaintPhaseForeground; 91 RenderBlock::paint(childPaintInfo, childPoint); 92 childPaintInfo.phase = PaintPhaseOutline; 93 RenderBlock::paint(childPaintInfo, childPoint); 92 94 } 93 95
Note: See TracChangeset
for help on using the changeset viewer.