An SVG with no intrinsic size does not draw correct slices when used as a border...
[WebKit-https.git] / Source / WebCore / rendering / style / NinePieceImage.h
1 /*
2  * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3  *           (C) 2000 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2003, 2005, 2006, 2007, 2008, 2013, 2015 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifndef NinePieceImage_h
25 #define NinePieceImage_h
26
27 #include "DataRef.h"
28 #include "LayoutRect.h"
29 #include "LayoutSize.h"
30 #include "LayoutUnit.h"
31 #include "LengthBox.h"
32 #include "StyleImage.h"
33 #include <wtf/Vector.h>
34
35 namespace WebCore {
36
37 enum ENinePieceImageRule {
38     StretchImageRule, RoundImageRule, SpaceImageRule, RepeatImageRule
39 };
40
41 enum ImagePiece {
42     MinPiece = 0,
43     TopLeftPiece = MinPiece,
44     LeftPiece,
45     BottomLeftPiece,
46     TopRightPiece,
47     RightPiece,
48     BottomRightPiece,
49     TopPiece,
50     BottomPiece,
51     MiddlePiece,
52     MaxPiece
53 };
54
55 inline ImagePiece& operator++(ImagePiece& piece)
56 {
57     piece = static_cast<ImagePiece>(static_cast<int>(piece) + 1);
58     return piece;
59 }
60
61 inline bool isCornerPiece(ImagePiece piece)
62 {
63     return piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPiece || piece == BottomRightPiece;
64 }
65
66 inline bool isMiddlePiece(ImagePiece piece)
67 {
68     return piece == MiddlePiece;
69 }
70
71 inline bool isHorizontalPiece(ImagePiece piece)
72 {
73     return piece == TopPiece || piece == BottomPiece || piece == MiddlePiece;
74 }
75
76 inline bool isVerticalPiece(ImagePiece piece)
77 {
78     return piece == LeftPiece || piece == RightPiece || piece == MiddlePiece;
79 }
80
81 inline PhysicalBoxSide imagePieceHorizontalSide(ImagePiece piece)
82 {
83     if (piece == TopLeftPiece || piece == TopPiece || piece == TopRightPiece)
84         return TopSide;
85
86     if (piece == BottomLeftPiece || piece == BottomPiece || piece == BottomRightPiece)
87         return BottomSide;
88
89     return NilSide;
90 }
91
92 inline PhysicalBoxSide imagePieceVerticalSide(ImagePiece piece)
93 {
94     if (piece == TopLeftPiece || piece == LeftPiece || piece == BottomLeftPiece)
95         return LeftSide;
96
97     if (piece == TopRightPiece || piece == RightPiece || piece == BottomRightPiece)
98         return RightSide;
99
100     return NilSide;
101 }
102
103 class RenderStyle;
104
105 class NinePieceImageData : public RefCounted<NinePieceImageData> {
106 public:
107     static Ref<NinePieceImageData> create() { return adoptRef(*new NinePieceImageData); }
108     Ref<NinePieceImageData> copy() const;
109
110     bool operator==(const NinePieceImageData&) const;
111     bool operator!=(const NinePieceImageData& o) const { return !(*this == o); }
112
113     bool fill : 1;
114     unsigned horizontalRule : 2; // ENinePieceImageRule
115     unsigned verticalRule : 2; // ENinePieceImageRule
116     RefPtr<StyleImage> image;
117     LengthBox imageSlices;
118     LengthBox borderSlices;
119     LengthBox outset;
120
121 private:
122     NinePieceImageData();
123     NinePieceImageData(const NinePieceImageData&);
124 };
125
126 class NinePieceImage {
127 public:
128     NinePieceImage();
129     NinePieceImage(PassRefPtr<StyleImage>, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule);
130
131     bool operator==(const NinePieceImage& other) const { return m_data == other.m_data; }
132     bool operator!=(const NinePieceImage& other) const { return m_data != other.m_data; }
133
134     bool hasImage() const { return m_data->image; }
135     StyleImage* image() const { return m_data->image.get(); }
136     void setImage(PassRefPtr<StyleImage> image) { m_data.access()->image = image; }
137     
138     const LengthBox& imageSlices() const { return m_data->imageSlices; }
139     void setImageSlices(LengthBox slices) { m_data.access()->imageSlices = WTF::move(slices); }
140
141     bool fill() const { return m_data->fill; }
142     void setFill(bool fill) { m_data.access()->fill = fill; }
143
144     const LengthBox& borderSlices() const { return m_data->borderSlices; }
145     void setBorderSlices(LengthBox slices) { m_data.access()->borderSlices = WTF::move(slices); }
146
147     const LengthBox& outset() const { return m_data->outset; }
148     void setOutset(LengthBox outset) { m_data.access()->outset = WTF::move(outset); }
149
150     ENinePieceImageRule horizontalRule() const { return static_cast<ENinePieceImageRule>(m_data->horizontalRule); }
151     void setHorizontalRule(ENinePieceImageRule rule) { m_data.access()->horizontalRule = rule; }
152     
153     ENinePieceImageRule verticalRule() const { return static_cast<ENinePieceImageRule>(m_data->verticalRule); }
154     void setVerticalRule(ENinePieceImageRule rule) { m_data.access()->verticalRule = rule; }
155
156     void copyImageSlicesFrom(const NinePieceImage& other)
157     {
158         m_data.access()->imageSlices = other.m_data->imageSlices;
159         m_data.access()->fill = other.m_data->fill;
160     }
161
162     void copyBorderSlicesFrom(const NinePieceImage& other)
163     {
164         m_data.access()->borderSlices = other.m_data->borderSlices;
165     }
166     
167     void copyOutsetFrom(const NinePieceImage& other)
168     {
169         m_data.access()->outset = other.m_data->outset;
170     }
171
172     void copyRepeatFrom(const NinePieceImage& other)
173     {
174         m_data.access()->horizontalRule = other.m_data->horizontalRule;
175         m_data.access()->verticalRule = other.m_data->verticalRule;
176     }
177
178     void setMaskDefaults()
179     {
180         m_data.access()->imageSlices = LengthBox(0);
181         m_data.access()->fill = true;
182         m_data.access()->borderSlices = LengthBox();
183     }
184
185     static LayoutUnit computeOutset(const Length& outsetSide, LayoutUnit borderSide)
186     {
187         if (outsetSide.isRelative())
188             return outsetSide.value() * borderSide;
189         return outsetSide.value();
190     }
191
192     static LayoutUnit computeSlice(Length, LayoutUnit width, LayoutUnit slice, LayoutUnit extent);
193     static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, int scaleFactor);
194     static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, const FloatBoxExtent& widths, const LayoutBoxExtent& slices);
195
196     static bool isEmptyPieceRect(ImagePiece, const LayoutBoxExtent& slices);
197     static bool isEmptyPieceRect(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
198
199     static Vector<FloatRect> computeIntrinsicRects(const FloatRect& outer, const LayoutBoxExtent& slices, float deviceScaleFactor);
200     static Vector<FloatRect> computeNonIntrinsicRects(const Vector<FloatRect>& intrinsicRects, const LayoutBoxExtent& slices);
201
202     static void scaleSlicesIfNeeded(const LayoutSize&, LayoutBoxExtent& slices, int scaleFactor);
203
204     static FloatSize computeIntrinsicSideTileScale(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
205     static FloatSize computeIntrinsicMiddleTileScale(const Vector<FloatSize>& scales, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, ENinePieceImageRule hRule, ENinePieceImageRule vRule);
206     static Vector<FloatSize> computeIntrinsicTileScales(const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, ENinePieceImageRule hRule, ENinePieceImageRule vRule);
207     static Vector<FloatSize> computeNonIntrinsicTileScales();
208
209     void paint(GraphicsContext*, RenderElement*, const RenderStyle&, const LayoutRect& destination, const LayoutSize& source, bool intrinsicSource, float deviceScaleFactor, CompositeOperator) const;
210
211 private:
212     DataRef<NinePieceImageData> m_data;
213 };
214
215 } // namespace WebCore
216
217 #endif // NinePieceImage_h