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

Side by Side Diff: Source/core/paint/NinePieceImagePainter.cpp

Issue 1180053009: Rewrite nine piece image painting code (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Address review comments Created 5 years, 6 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
« no previous file with comments | « Source/core/paint/NinePieceImagePainter.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 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "core/paint/NinePieceImagePainter.h" 6 #include "core/paint/NinePieceImagePainter.h"
7 7
8 #include "core/layout/ImageQualityController.h" 8 #include "core/layout/ImageQualityController.h"
9 #include "core/layout/LayoutBoxModelObject.h" 9 #include "core/layout/LayoutBoxModelObject.h"
10 #include "core/paint/BoxPainter.h" 10 #include "core/paint/BoxPainter.h"
11 #include "core/paint/NinePieceImageGrid.h"
11 #include "core/style/ComputedStyle.h" 12 #include "core/style/ComputedStyle.h"
12 #include "core/style/NinePieceImage.h" 13 #include "core/style/NinePieceImage.h"
13 #include "platform/LengthFunctions.h" 14 #include "platform/geometry/IntSize.h"
14 #include "platform/geometry/LayoutRect.h" 15 #include "platform/geometry/LayoutRect.h"
15 #include "platform/graphics/GraphicsContext.h" 16 #include "platform/graphics/GraphicsContext.h"
16 17
17 namespace blink { 18 namespace blink {
18 19
19 NinePieceImagePainter::NinePieceImagePainter(LayoutBoxModelObject& layoutObject) 20 NinePieceImagePainter::NinePieceImagePainter(LayoutBoxModelObject& layoutObject)
20 : m_layoutObject(layoutObject) 21 : m_layoutObject(layoutObject)
21 { 22 {
22 } 23 }
23 24
24 LayoutUnit NinePieceImagePainter::computeBorderImageSide(const BorderImageLength & borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent ) 25 bool NinePieceImagePainter::paint(GraphicsContext* graphicsContext, const Layout Rect& rect, const ComputedStyle& style,
25 { 26 const NinePieceImage& ninePieceImage, SkXfermode::Mode op) const
26 if (borderSlice.isNumber())
27 return borderSlice.number() * borderSide;
28 if (borderSlice.length().isAuto())
29 return imageSide;
30 return valueForLength(borderSlice.length(), boxExtent);
31 }
32
33 bool NinePieceImagePainter::paint(GraphicsContext* graphicsContext, const Layout Rect& rect, const ComputedStyle& style, const NinePieceImage& ninePieceImage, Sk Xfermode::Mode op) const
34 { 27 {
35 StyleImage* styleImage = ninePieceImage.image(); 28 StyleImage* styleImage = ninePieceImage.image();
36 if (!styleImage) 29 if (!styleImage)
37 return false; 30 return false;
38 31
39 if (!styleImage->isLoaded()) 32 if (!styleImage->isLoaded())
40 return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either. 33 return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
41 34
42 if (!styleImage->canRender(m_layoutObject, style.effectiveZoom())) 35 if (!styleImage->canRender(m_layoutObject, style.effectiveZoom()))
43 return false; 36 return false;
44 37
45 // FIXME: border-image is broken with full page zooming when tiling has to h appen, since the tiling function 38 // FIXME: border-image is broken with full page zooming when tiling has to h appen, since the tiling function
46 // doesn't have any understanding of the zoom that is in effect on the tile. 39 // doesn't have any understanding of the zoom that is in effect on the tile.
47 LayoutRect rectWithOutsets = rect; 40 LayoutRect rectWithOutsets = rect;
48 rectWithOutsets.expand(style.imageOutsets(ninePieceImage)); 41 rectWithOutsets.expand(style.imageOutsets(ninePieceImage));
49 IntRect borderImageRect = pixelSnappedIntRect(rectWithOutsets); 42 IntRect borderImageRect = pixelSnappedIntRect(rectWithOutsets);
50 43
51 IntSize imageSize = m_layoutObject.calculateImageIntrinsicDimensions(styleIm age, borderImageRect.size(), LayoutBoxModelObject::DoNotScaleByEffectiveZoom); 44 IntSize imageSize = m_layoutObject.calculateImageIntrinsicDimensions(styleIm age, borderImageRect.size(),
45 LayoutBoxModelObject::DoNotScaleByEffectiveZoom);
52 46
53 // If both values are 'auto' then the intrinsic width and/or height of the i mage should be used, if any. 47 // If both values are 'auto' then the intrinsic width and/or height of the i mage should be used, if any.
54 styleImage->setContainerSizeForLayoutObject(&m_layoutObject, imageSize, styl e.effectiveZoom()); 48 styleImage->setContainerSizeForLayoutObject(&m_layoutObject, imageSize, styl e.effectiveZoom());
55 49
56 int imageWidth = imageSize.width(); 50 IntRectOutsets borderWidths(style.borderTopWidth(), style.borderRightWidth() ,
57 int imageHeight = imageSize.height(); 51 style.borderBottomWidth(), style.borderLeftWidth());
58 52 NinePieceImageGrid grid(ninePieceImage, imageSize, borderImageRect, borderWi dths);
59 float imageScaleFactor = styleImage->imageScaleFactor();
60 int topSlice = std::min<int>(imageHeight, valueForLength(ninePieceImage.imag eSlices().top(), imageHeight)) * imageScaleFactor;
61 int rightSlice = std::min<int>(imageWidth, valueForLength(ninePieceImage.ima geSlices().right(), imageWidth)) * imageScaleFactor;
62 int bottomSlice = std::min<int>(imageHeight, valueForLength(ninePieceImage.i mageSlices().bottom(), imageHeight)) * imageScaleFactor;
63 int leftSlice = std::min<int>(imageWidth, valueForLength(ninePieceImage.imag eSlices().left(), imageWidth)) * imageScaleFactor;
64
65 ENinePieceImageRule hRule = ninePieceImage.horizontalRule();
66 ENinePieceImageRule vRule = ninePieceImage.verticalRule();
67
68 int topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), s tyle.borderTopWidth(), topSlice, borderImageRect.height());
69 int rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right( ), style.borderRightWidth(), rightSlice, borderImageRect.width());
70 int bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().botto m(), style.borderBottomWidth(), bottomSlice, borderImageRect.height());
71 int leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style.borderLeftWidth(), leftSlice, borderImageRect.width());
72
73 // Reduce the widths if they're too large.
74 // The spec says: Given Lwidth as the width of the border image area, Lheigh t as its height, and Wside as the border image width
75 // offset for the side, let f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbo ttom)). If f < 1, then all W are reduced by
76 // multiplying them by f.
77 int borderSideWidth = std::max(1, leftWidth + rightWidth);
78 int borderSideHeight = std::max(1, topWidth + bottomWidth);
79 float borderSideScaleFactor = std::min((float)borderImageRect.width() / bord erSideWidth, (float)borderImageRect.height() / borderSideHeight);
80 if (borderSideScaleFactor < 1) {
81 topWidth *= borderSideScaleFactor;
82 rightWidth *= borderSideScaleFactor;
83 bottomWidth *= borderSideScaleFactor;
84 leftWidth *= borderSideScaleFactor;
85 }
86
87 bool drawLeft = leftSlice > 0 && leftWidth > 0;
88 bool drawTop = topSlice > 0 && topWidth > 0;
89 bool drawRight = rightSlice > 0 && rightWidth > 0;
90 bool drawBottom = bottomSlice > 0 && bottomWidth > 0;
91 bool drawMiddle = ninePieceImage.fill() && (imageWidth - leftSlice - rightSl ice) > 0 && (borderImageRect.width() - leftWidth - rightWidth) > 0
92 && (imageHeight - topSlice - bottomSlice) > 0 && (borderImageRect.height () - topWidth - bottomWidth) > 0;
93 53
94 RefPtr<Image> image = styleImage->image(&m_layoutObject, imageSize); 54 RefPtr<Image> image = styleImage->image(&m_layoutObject, imageSize);
95 55
96 float destinationWidth = borderImageRect.width() - leftWidth - rightWidth; 56 InterpolationQuality interpolationQuality = BoxPainter::chooseInterpolationQ uality(m_layoutObject,
97 float destinationHeight = borderImageRect.height() - topWidth - bottomWidth; 57 graphicsContext, image.get(), 0, rectWithOutsets.size());
98
99 float sourceWidth = imageWidth - leftSlice - rightSlice;
100 float sourceHeight = imageHeight - topSlice - bottomSlice;
101
102 float leftSideScale = drawLeft ? (float)leftWidth / leftSlice : 1;
103 float rightSideScale = drawRight ? (float)rightWidth / rightSlice : 1;
104 float topSideScale = drawTop ? (float)topWidth / topSlice : 1;
105 float bottomSideScale = drawBottom ? (float)bottomWidth / bottomSlice : 1;
106
107 InterpolationQuality interpolationQuality = BoxPainter::chooseInterpolationQ uality(m_layoutObject, graphicsContext, image.get(), 0, rectWithOutsets.size());
108 InterpolationQuality previousInterpolationQuality = graphicsContext->imageIn terpolationQuality(); 58 InterpolationQuality previousInterpolationQuality = graphicsContext->imageIn terpolationQuality();
109 graphicsContext->setImageInterpolationQuality(interpolationQuality); 59 graphicsContext->setImageInterpolationQuality(interpolationQuality);
110 60
111 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", " data", InspectorPaintImageEvent::data(m_layoutObject, *styleImage)); 61 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", " data",
112 if (drawLeft) { 62 InspectorPaintImageEvent::data(m_layoutObject, *styleImage));
113 // Paint the top and bottom left corners.
114 63
115 // The top left corner rect is (tx, ty, leftWidth, topWidth) 64 for (NinePiece piece = MinPiece; piece < MaxPiece; ++piece) {
116 // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice) 65 NinePieceImageGrid::NinePieceDrawInfo drawInfo = grid.getNinePieceDrawIn fo(piece);
117 if (drawTop) {
118 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.loca tion(), IntSize(leftWidth, topWidth)),
119 LayoutRect(0, 0, leftSlice, topSlice), op);
120 }
121 66
122 // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth) 67 if (drawInfo.isDrawable) {
123 // The rect to use from within the image is (0, imageHeight - bottomSlic e, leftSlice, botomSlice) 68 if (drawInfo.isCornerPiece) {
124 if (drawBottom) { 69 graphicsContext->drawImage(image.get(), drawInfo.destination, dr awInfo.source, op);
125 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.x(), borderImageRect.maxY() - bottomWidth, leftWidth, bottomWidth), 70 } else {
126 LayoutRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice) , op); 71 graphicsContext->drawTiledImage(image.get(), enclosingIntRect(dr awInfo.destination),
127 } 72 enclosingIntRect(drawInfo.source), drawInfo.tileScale, drawI nfo.tileRule.horizontal,
128 73 drawInfo.tileRule.vertical, op);
129 // Paint the left edge. 74 }
130 // Have to scale and tile into the border rect.
131 if (sourceHeight > 0) {
132 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect .x(), borderImageRect.y() + topWidth, leftWidth, destinationHeight),
133 IntRect(0, topSlice, leftSlice, sourceHeight), FloatSize(leftSid eScale, leftSideScale), Image::StretchTile, (Image::TileRule)vRule, op);
134 } 75 }
135 } 76 }
136 77
137 if (drawRight) {
138 // Paint the top and bottom right corners
139 // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, to pWidth)
140 // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
141 if (drawTop) {
142 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX () - rightWidth, borderImageRect.y(), rightWidth, topWidth),
143 LayoutRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op );
144 }
145
146 // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottom Width, rightWidth, bottomWidth)
147 // The rect to use from within the image is (imageWidth - rightSlice, im ageHeight - bottomSlice, rightSlice, bottomSlice)
148 if (drawBottom) {
149 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX () - rightWidth, borderImageRect.maxY() - bottomWidth, rightWidth, bottomWidth),
150 LayoutRect(imageWidth - rightSlice, imageHeight - bottomSlice, r ightSlice, bottomSlice), op);
151 }
152
153 // Paint the right edge.
154 if (sourceHeight > 0) {
155 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect .maxX() - rightWidth, borderImageRect.y() + topWidth, rightWidth,
156 destinationHeight),
157 IntRect(imageWidth - rightSlice, topSlice, rightSlice, sourceHei ght),
158 FloatSize(rightSideScale, rightSideScale),
159 Image::StretchTile, (Image::TileRule)vRule, op);
160 }
161 }
162
163 // Paint the top edge.
164 if (drawTop && sourceWidth > 0) {
165 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.y(), destinationWidth, topWidth),
166 IntRect(leftSlice, 0, sourceWidth, topSlice),
167 FloatSize(topSideScale, topSideScale), (Image::TileRule)hRule, Image ::StretchTile, op);
168 }
169
170 // Paint the bottom edge.
171 if (drawBottom && sourceWidth > 0) {
172 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.maxY() - bottomWidth,
173 destinationWidth, bottomWidth),
174 IntRect(leftSlice, imageHeight - bottomSlice, sourceWidth, bottomSli ce),
175 FloatSize(bottomSideScale, bottomSideScale),
176 (Image::TileRule)hRule, Image::StretchTile, op);
177 }
178
179 // Paint the middle.
180 if (drawMiddle) {
181 FloatSize middleScaleFactor(1, 1);
182 if (drawTop)
183 middleScaleFactor.setWidth(topSideScale);
184 else if (drawBottom)
185 middleScaleFactor.setWidth(bottomSideScale);
186 if (drawLeft)
187 middleScaleFactor.setHeight(leftSideScale);
188 else if (drawRight)
189 middleScaleFactor.setHeight(rightSideScale);
190
191 // For "stretch" rules, just override the scale factor and replace. We o nly had to do this for the
192 // center tile, since sides don't even use the scale factor unless they have a rule other than "stretch".
193 // The middle however can have "stretch" specified in one axis but not t he other, so we have to
194 // correct the scale here.
195 if (hRule == StretchImageRule)
196 middleScaleFactor.setWidth(destinationWidth / sourceWidth);
197
198 if (vRule == StretchImageRule)
199 middleScaleFactor.setHeight(destinationHeight / sourceHeight);
200
201 graphicsContext->drawTiledImage(image.get(),
202 IntRect(borderImageRect.x() + leftWidth, borderImageRect.y() + topWi dth, destinationWidth, destinationHeight),
203 IntRect(leftSlice, topSlice, sourceWidth, sourceHeight),
204 middleScaleFactor, (Image::TileRule)hRule, (Image::TileRule)vRule, o p);
205 }
206 graphicsContext->setImageInterpolationQuality(previousInterpolationQuality); 78 graphicsContext->setImageInterpolationQuality(previousInterpolationQuality);
207 return true; 79 return true;
208 } 80 }
209 81
210 } // namespace blink 82 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/paint/NinePieceImagePainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698