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
31namespace WebCore {
32
33class LayoutSize;
34class LayoutRect;
35class RenderStyle;
36
37enum ENinePieceImageRule { StretchImageRule, RoundImageRule, SpaceImageRule, RepeatImageRule };
38
39enum 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
53inline ImagePiece& operator++(ImagePiece& piece)
54{
55 piece = static_cast<ImagePiece>(static_cast<int>(piece) + 1);
56 return piece;
57}
58
59inline bool isCornerPiece(ImagePiece piece)
60{
61 return piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPiece || piece == BottomRightPiece;
62}
63
64inline bool isMiddlePiece(ImagePiece piece)
65{
66 return piece == MiddlePiece;
67}
68
69inline bool isHorizontalPiece(ImagePiece piece)
70{
71 return piece == TopPiece || piece == BottomPiece || piece == MiddlePiece;
72}
73
74inline bool isVerticalPiece(ImagePiece piece)
75{
76 return piece == LeftPiece || piece == RightPiece || piece == MiddlePiece;
77}
78
79inline 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
90inline 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
101class NinePieceImage {
102public:
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
184private:
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
212WTF::TextStream& operator<<(WTF::TextStream&, const NinePieceImage&);
213
214} // namespace WebCore
215