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

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

Issue 1164573003: Move NinePieceImage painting to a separate class (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/paint/NinePieceImagePainter.h"
7
8 #include "core/layout/ImageQualityController.h"
9 #include "core/layout/LayoutBoxModelObject.h"
10 #include "core/paint/BoxPainter.h"
11 #include "core/style/ComputedStyle.h"
12 #include "core/style/NinePieceImage.h"
13 #include "platform/LengthFunctions.h"
14 #include "platform/geometry/LayoutRect.h"
15 #include "platform/graphics/GraphicsContext.h"
16
17 namespace blink {
18
19 NinePieceImagePainter::NinePieceImagePainter(LayoutBoxModelObject& layoutObject)
20 : m_layoutObject(layoutObject)
21 {
22 }
23
24 LayoutUnit NinePieceImagePainter::computeBorderImageSide(const BorderImageLength & borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent )
25 {
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)
34 {
35 StyleImage* styleImage = ninePieceImage.image();
36 if (!styleImage)
37 return false;
38
39 if (!styleImage->isLoaded())
40 return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
41
42 if (!styleImage->canRender(m_layoutObject, style.effectiveZoom()))
43 return false;
44
45 // 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.
47 LayoutRect rectWithOutsets = rect;
48 rectWithOutsets.expand(style.imageOutsets(ninePieceImage));
49 IntRect borderImageRect = pixelSnappedIntRect(rectWithOutsets);
50
51 IntSize imageSize = m_layoutObject.calculateImageIntrinsicDimensions(styleIm age, borderImageRect.size(), LayoutBoxModelObject::DoNotScaleByEffectiveZoom);
52
53 // 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());
55
56 int imageWidth = imageSize.width();
57 int imageHeight = imageSize.height();
58
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
94 RefPtr<Image> image = styleImage->image(&m_layoutObject, imageSize);
95
96 float destinationWidth = borderImageRect.width() - leftWidth - rightWidth;
97 float destinationHeight = borderImageRect.height() - topWidth - bottomWidth;
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();
109 graphicsContext->setImageInterpolationQuality(interpolationQuality);
110
111 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", " data", InspectorPaintImageEvent::data(m_layoutObject, *styleImage));
112 if (drawLeft) {
113 // Paint the top and bottom left corners.
114
115 // The top left corner rect is (tx, ty, leftWidth, topWidth)
116 // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
117 if (drawTop) {
118 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.loca tion(), IntSize(leftWidth, topWidth)),
119 LayoutRect(0, 0, leftSlice, topSlice), op);
120 }
121
122 // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth)
123 // The rect to use from within the image is (0, imageHeight - bottomSlic e, leftSlice, botomSlice)
124 if (drawBottom) {
125 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.x(), borderImageRect.maxY() - bottomWidth, leftWidth, bottomWidth),
126 LayoutRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice) , op);
127 }
128
129 // Paint the left edge.
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 }
135 }
136
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);
207 return true;
208 }
209
210 } // namespace blink
OLDNEW
« Source/core/paint/NinePieceImagePainter.h ('K') | « Source/core/paint/NinePieceImagePainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698