Implement CSS `display: flow-root` (modern clearfix)
[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-2017 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 #pragma once
25
26 #include "DataRef.h"
27 #include "LengthBox.h"
28 #include "StyleImage.h"
29 #include <wtf/Vector.h>
30
31 namespace WebCore {
32
33 class LayoutSize;
34 class LayoutRect;
35 class RenderStyle;
36
37 enum ENinePieceImageRule { StretchImageRule, RoundImageRule, SpaceImageRule, RepeatImageRule };
38
39 enum ImagePiece {
40     MinPiece = 0,
41     TopLeftPiece = MinPiece,
42     LeftPiece,
43     BottomLeftPiece,
44     TopRightPiece,
45     RightPiece,
46     BottomRightPiece,
47     TopPiece,
48     BottomPiece,
49     MiddlePiece,
50     MaxPiece
51 };
52
53 inline ImagePiece& operator++(ImagePiece& piece)
54 {
55     piece = static_cast<ImagePiece>(static_cast<int>(piece) + 1);
56     return piece;
57 }
58
59 inline bool isCornerPiece(ImagePiece piece)
60 {
61     return piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPiece || piece == BottomRightPiece;
62 }
63
64 inline bool isMiddlePiece(ImagePiece piece)
65 {
66     return piece == MiddlePiece;
67 }
68
69 inline bool isHorizontalPiece(ImagePiece piece)
70 {
71     return piece == TopPiece || piece == BottomPiece || piece == MiddlePiece;
72 }
73
74 inline bool isVerticalPiece(ImagePiece piece)
75 {
76     return piece == LeftPiece || piece == RightPiece || piece == MiddlePiece;
77 }
78
79 inline Optional<PhysicalBoxSide> imagePieceHorizontalSide(ImagePiece piece)
80 {
81     if (piece == TopLeftPiece || piece == TopPiece || piece == TopRightPiece)
82         return PhysicalBoxSide::Top;
83
84     if (piece == BottomLeftPiece || piece == BottomPiece || piece == BottomRightPiece)
85         return PhysicalBoxSide::Bottom;
86
87     return WTF::nullopt;
88 }
89
90 inline Optional<PhysicalBoxSide> imagePieceVerticalSide(ImagePiece piece)
91 {
92     if (piece == TopLeftPiece || piece == LeftPiece || piece == BottomLeftPiece)
93         return PhysicalBoxSide::Left;
94
95     if (piece == TopRightPiece || piece == RightPiece || piece == BottomRightPiece)
96         return PhysicalBoxSide::Right;
97
98     return WTF::nullopt;
99 }
100
101 class NinePieceImage {
102 public:
103     NinePieceImage();
104     NinePieceImage(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule);
105
106     bool operator==(const NinePieceImage& other) const { return m_data == other.m_data; }
107     bool operator!=(const NinePieceImage& other) const { return m_data != other.m_data; }
108
109     bool hasImage() const { return m_data->image; }
110     StyleImage* image() const { return m_data->image.get(); }
111     void setImage(RefPtr<StyleImage>&& image) { m_data.access().image = WTFMove(image); }
112
113     const LengthBox& imageSlices() const { return m_data->imageSlices; }
114     void setImageSlices(LengthBox slices) { m_data.access().imageSlices = WTFMove(slices); }
115
116     bool fill() const { return m_data->fill; }
117     void setFill(bool fill) { m_data.access().fill = fill; }
118
119     const LengthBox& borderSlices() const { return m_data->borderSlices; }
120     void setBorderSlices(LengthBox slices) { m_data.access().borderSlices = WTFMove(slices); }
121
122     const LengthBox& outset() const { return m_data->outset; }
123     void setOutset(LengthBox outset) { m_data.access().outset = WTFMove(outset); }
124
125     ENinePieceImageRule horizontalRule() const { return static_cast<ENinePieceImageRule>(m_data->horizontalRule); }
126     void setHorizontalRule(ENinePieceImageRule rule) { m_data.access().horizontalRule = rule; }
127     
128     ENinePieceImageRule verticalRule() const { return static_cast<ENinePieceImageRule>(m_data->verticalRule); }
129     void setVerticalRule(ENinePieceImageRule rule) { m_data.access().verticalRule = rule; }
130
131     void copyImageSlicesFrom(const NinePieceImage& other)
132     {
133         m_data.access().imageSlices = other.m_data->imageSlices;
134         m_data.access().fill = other.m_data->fill;
135     }
136
137     void copyBorderSlicesFrom(const NinePieceImage& other)
138     {
139         m_data.access().borderSlices = other.m_data->borderSlices;
140     }
141     
142     void copyOutsetFrom(const NinePieceImage& other)
143     {
144         m_data.access().outset = other.m_data->outset;
145     }
146
147     void copyRepeatFrom(const NinePieceImage& other)
148     {
149         m_data.access().horizontalRule = other.m_data->horizontalRule;
150         m_data.access().verticalRule = other.m_data->verticalRule;
151     }
152
153     void setMaskDefaults()
154     {
155         m_data.access().imageSlices = LengthBox(0);
156         m_data.access().fill = true;
157         m_data.access().borderSlices = LengthBox();
158     }
159
160     static LayoutUnit computeOutset(const Length& outsetSide, LayoutUnit borderSide)
161     {
162         if (outsetSide.isRelative())
163             return outsetSide.value() * borderSide;
164         return outsetSide.value();
165     }
166
167     static LayoutUnit computeSlice(Length, LayoutUnit width, LayoutUnit slice, LayoutUnit extent);
168     static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, int scaleFactor);
169     static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, const FloatBoxExtent& widths, const LayoutBoxExtent& slices);
170
171     static bool isEmptyPieceRect(ImagePiece, const LayoutBoxExtent& slices);
172     static bool isEmptyPieceRect(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
173
174     static Vector<FloatRect> computeNineRects(const FloatRect& outer, const LayoutBoxExtent& slices, float deviceScaleFactor);
175
176     static void scaleSlicesIfNeeded(const LayoutSize&, LayoutBoxExtent& slices, float deviceScaleFactor);
177
178     static FloatSize computeSideTileScale(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
179     static FloatSize computeMiddleTileScale(const Vector<FloatSize>& scales, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, ENinePieceImageRule hRule, ENinePieceImageRule vRule);
180     static Vector<FloatSize> computeTileScales(const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, ENinePieceImageRule hRule, ENinePieceImageRule vRule);
181
182     void paint(GraphicsContext&, RenderElement*, const RenderStyle&, const LayoutRect& destination, const LayoutSize& source, float deviceScaleFactor, CompositeOperator) const;
183
184 private:
185     struct Data : RefCounted<Data> {
186         static Ref<Data> create();
187         static Ref<Data> create(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule);
188         Ref<Data> copy() const;
189
190         bool operator==(const Data&) const;
191         bool operator!=(const Data& other) const { return !(*this == other); }
192
193         bool fill : 1;
194         unsigned horizontalRule : 2; // ENinePieceImageRule
195         unsigned verticalRule : 2; // ENinePieceImageRule
196         RefPtr<StyleImage> image;
197         LengthBox imageSlices { { 100, Percent }, { 100, Percent }, { 100, Percent }, { 100, Percent } };
198         LengthBox borderSlices { { 1, Relative }, { 1, Relative }, { 1, Relative }, { 1, Relative } };
199         LengthBox outset { 0 };
200
201     private:
202         Data();
203         Data(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, ENinePieceImageRule horizontalRule, ENinePieceImageRule verticalRule);
204         Data(const Data&);
205     };
206
207     static DataRef<Data>& defaultData();
208
209     DataRef<Data> m_data;
210 };
211
212 WTF::TextStream& operator<<(WTF::TextStream&, const NinePieceImage&);
213
214 } // namespace WebCore