Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cxfa_box.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fxfa/parser/cxfa_box.h"
8
9#include <math.h>
10
11#include <algorithm>
12#include <utility>
13
14#include "fxjs/xfa/cjx_object.h"
15#include "third_party/base/notreached.h"
16#include "third_party/base/numerics/safe_conversions.h"
17#include "xfa/fgas/graphics/cfgas_gegraphics.h"
18#include "xfa/fgas/graphics/cfgas_gepath.h"
19#include "xfa/fgas/graphics/cfgas_gepattern.h"
20#include "xfa/fgas/graphics/cfgas_geshading.h"
21#include "xfa/fxfa/parser/cxfa_corner.h"
22#include "xfa/fxfa/parser/cxfa_edge.h"
23#include "xfa/fxfa/parser/cxfa_fill.h"
24#include "xfa/fxfa/parser/cxfa_margin.h"
25#include "xfa/fxfa/parser/cxfa_measurement.h"
26#include "xfa/fxfa/parser/cxfa_node.h"
27#include "xfa/fxfa/parser/cxfa_rectangle.h"
28
29namespace {
30
31std::pair<XFA_AttributeValue, CXFA_Stroke*> Style3D(
32 const std::vector<CXFA_Stroke*>& strokes) {
33 if (strokes.empty())
34 return {XFA_AttributeValue::Unknown, nullptr};
35
36 CXFA_Stroke* stroke = strokes[0];
37 for (size_t i = 1; i < strokes.size(); i++) {
38 CXFA_Stroke* find = strokes[i];
39 if (!find)
40 continue;
41 if (!stroke)
42 stroke = find;
43 else if (stroke->GetStrokeType() != find->GetStrokeType())
44 stroke = find;
45 break;
46 }
47
49 if (iType == XFA_AttributeValue::Lowered ||
50 iType == XFA_AttributeValue::Raised ||
51 iType == XFA_AttributeValue::Etched ||
52 iType == XFA_AttributeValue::Embossed) {
53 return {iType, stroke};
54 }
55 return {XFA_AttributeValue::Unknown, stroke};
56}
57
58CXFA_Rectangle* ToRectangle(CXFA_Box* box) {
59 return static_cast<CXFA_Rectangle*>(box);
60}
61
62} // namespace
63
64CXFA_Box::CXFA_Box(CXFA_Document* pDoc,
65 XFA_PacketType ePacket,
66 Mask<XFA_XDPPACKET> validPackets,
67 XFA_ObjectType oType,
68 XFA_Element eType,
69 pdfium::span<const PropertyData> properties,
70 pdfium::span<const AttributeData> attributes,
71 CJX_Object* js_node)
72 : CXFA_Node(pDoc,
73 ePacket,
74 validPackets,
75 oType,
76 eType,
77 properties,
78 attributes,
79 js_node) {}
80
81CXFA_Box::~CXFA_Box() = default;
82
84 return JSObject()->GetEnum(XFA_Attribute::Hand);
85}
86
88 return JSObject()
89 ->TryEnum(XFA_Attribute::Presence, true)
90 .value_or(XFA_AttributeValue::Visible);
91}
92
94 return CountChildren(XFA_Element::Edge, false);
95}
96
97CXFA_Edge* CXFA_Box::GetEdgeIfExists(size_t nIndex) {
98 if (nIndex == 0) {
99 return JSObject()->GetOrCreateProperty<CXFA_Edge>(
100 pdfium::base::checked_cast<int32_t>(nIndex), XFA_Element::Edge);
101 }
102 return JSObject()->GetProperty<CXFA_Edge>(
103 pdfium::base::checked_cast<int32_t>(nIndex), XFA_Element::Edge);
104}
105
107 return GetStrokesInternal(false);
108}
109
110bool CXFA_Box::IsCircular() {
111 return JSObject()->GetBoolean(XFA_Attribute::Circular);
112}
113
114absl::optional<int32_t> CXFA_Box::GetStartAngle() {
115 return JSObject()->TryInteger(XFA_Attribute::StartAngle, false);
116}
117
118absl::optional<int32_t> CXFA_Box::GetSweepAngle() {
119 return JSObject()->TryInteger(XFA_Attribute::SweepAngle, false);
120}
121
123 return JSObject()->GetOrCreateProperty<CXFA_Fill>(0, XFA_Element::Fill);
124}
125
126std::tuple<XFA_AttributeValue, bool, float> CXFA_Box::Get3DStyle() {
127 if (GetElementType() == XFA_Element::Arc)
128 return {XFA_AttributeValue::Unknown, false, 0.0f};
129
130 std::vector<CXFA_Stroke*> strokes = GetStrokesInternal(true);
131 CXFA_Stroke* stroke;
132 XFA_AttributeValue iType;
133
134 std::tie(iType, stroke) = Style3D(strokes);
135 if (iType == XFA_AttributeValue::Unknown)
136 return {XFA_AttributeValue::Unknown, false, 0.0f};
137
138 return {iType, stroke->IsVisible(), stroke->GetThickness()};
139}
140
141std::vector<CXFA_Stroke*> CXFA_Box::GetStrokesInternal(bool bNull) {
142 std::vector<CXFA_Stroke*> strokes;
143 strokes.resize(8);
144
145 for (int32_t i = 0, j = 0; i < 4; i++) {
146 CXFA_Corner* corner;
147 if (i == 0) {
148 corner =
149 JSObject()->GetOrCreateProperty<CXFA_Corner>(i, XFA_Element::Corner);
150 } else {
151 corner = JSObject()->GetProperty<CXFA_Corner>(i, XFA_Element::Corner);
152 }
153
154 // TODO(dsinclair): If i == 0 and GetOrCreateProperty failed, we can end up
155 // with a null corner in the first position.
156 if (corner || i == 0) {
157 strokes[j] = corner;
158 } else if (!bNull) {
159 if (i == 1 || i == 2)
160 strokes[j] = strokes[0];
161 else
162 strokes[j] = strokes[2];
163 }
164 j++;
165
166 CXFA_Edge* edge;
167 if (i == 0)
168 edge = JSObject()->GetOrCreateProperty<CXFA_Edge>(i, XFA_Element::Edge);
169 else
170 edge = JSObject()->GetProperty<CXFA_Edge>(i, XFA_Element::Edge);
171
172 // TODO(dsinclair): If i == 0 and GetOrCreateProperty failed, we can end up
173 // with a null edge in the first position.
174 if (edge || i == 0) {
175 strokes[j] = edge;
176 } else if (!bNull) {
177 if (i == 1 || i == 2)
178 strokes[j] = strokes[1];
179 else
180 strokes[j] = strokes[3];
181 }
182 j++;
183 }
184 return strokes;
185}
186
188 const CFX_RectF& rtWidget,
189 const CFX_Matrix& matrix,
190 bool forceRound) {
191 if (GetPresence() != XFA_AttributeValue::Visible)
192 return;
193
194 XFA_Element eType = GetElementType();
195 if (eType != XFA_Element::Arc && eType != XFA_Element::Border &&
196 eType != XFA_Element::Rectangle) {
197 return;
198 }
199 std::vector<CXFA_Stroke*> strokes;
200 if (!forceRound && eType != XFA_Element::Arc)
201 strokes = GetStrokes();
202
203 DrawFill(strokes, pGS, rtWidget, matrix, forceRound);
205 if (type == XFA_Element::Arc || forceRound) {
206 StrokeArcOrRounded(pGS, rtWidget, matrix, forceRound);
207 } else if (type == XFA_Element::Rectangle || type == XFA_Element::Border) {
208 ToRectangle(this)->Draw(strokes, pGS, rtWidget, matrix);
209 } else {
210 NOTREACHED_NORETURN();
211 }
212}
213
214void CXFA_Box::DrawFill(const std::vector<CXFA_Stroke*>& strokes,
215 CFGAS_GEGraphics* pGS,
216 CFX_RectF rtWidget,
217 const CFX_Matrix& matrix,
218 bool forceRound) {
219 CXFA_Fill* fill = JSObject()->GetProperty<CXFA_Fill>(0, XFA_Element::Fill);
220 if (!fill || !fill->IsVisible())
221 return;
222
223 CFGAS_GEPath fillPath;
226 if (type == XFA_Element::Arc || forceRound) {
227 CXFA_Edge* edge = GetEdgeIfExists(0);
228 float fThickness = fmax(0.0, edge ? edge->GetThickness() : 0);
229 float fHalf = fThickness / 2;
231 if (iHand == XFA_AttributeValue::Left)
232 rtWidget.Inflate(fHalf, fHalf);
233 else if (iHand == XFA_AttributeValue::Right)
234 rtWidget.Deflate(fHalf, fHalf);
235
236 GetPathArcOrRounded(rtWidget, forceRound, &fillPath);
237 } else if (type == XFA_Element::Rectangle || type == XFA_Element::Border) {
238 ToRectangle(this)->GetFillPath(strokes, rtWidget, &fillPath);
239 } else {
240 NOTREACHED_NORETURN();
241 }
242 fillPath.Close();
243 fill->Draw(pGS, fillPath, rtWidget, matrix);
244}
245
246void CXFA_Box::GetPathArcOrRounded(CFX_RectF rtDraw,
247 bool forceRound,
248 CFGAS_GEPath* fillPath) {
249 float a = rtDraw.width / 2.0f;
250 float b = rtDraw.height / 2.0f;
251 if (IsCircular() || forceRound)
252 a = b = std::min(a, b);
253
254 CFX_PointF center = rtDraw.Center();
255 rtDraw.left = center.x - a;
256 rtDraw.top = center.y - b;
257 rtDraw.width = a + a;
258 rtDraw.height = b + b;
259 absl::optional<int32_t> startAngle = GetStartAngle();
260 absl::optional<int32_t> sweepAngle = GetSweepAngle();
261 if (!startAngle.has_value() && !sweepAngle.has_value()) {
262 fillPath->AddEllipse(rtDraw);
263 return;
264 }
265
266 fillPath->AddArc(rtDraw.TopLeft(), rtDraw.Size(),
267 -startAngle.value_or(0) * FXSYS_PI / 180.0f,
268 -sweepAngle.value_or(360) * FXSYS_PI / 180.0f);
269}
270
271void CXFA_Box::StrokeArcOrRounded(CFGAS_GEGraphics* pGS,
272 CFX_RectF rtWidget,
273 const CFX_Matrix& matrix,
274 bool forceRound) {
275 CXFA_Edge* edge = GetEdgeIfExists(0);
276 if (!edge || !edge->IsVisible())
277 return;
278
279 bool bVisible;
280 float fThickness;
281 XFA_AttributeValue i3DType;
282 std::tie(i3DType, bVisible, fThickness) = Get3DStyle();
283 bool lowered3d = false;
284 if (i3DType != XFA_AttributeValue::Unknown) {
285 if (bVisible && fThickness >= 0.001f)
286 lowered3d = true;
287 }
288
289 float fHalf = edge->GetThickness() / 2;
290 if (fHalf < 0) {
291 fHalf = 0;
292 }
293
295 if (iHand == XFA_AttributeValue::Left) {
296 rtWidget.Inflate(fHalf, fHalf);
297 } else if (iHand == XFA_AttributeValue::Right) {
298 rtWidget.Deflate(fHalf, fHalf);
299 }
300 if (!forceRound || !lowered3d) {
301 if (fHalf < 0.001f)
302 return;
303
304 CFGAS_GEPath arcPath;
305 GetPathArcOrRounded(rtWidget, forceRound, &arcPath);
306 if (edge)
307 edge->Stroke(pGS, arcPath, matrix);
308 return;
309 }
311 pGS->SetLineWidth(fHalf);
312
313 float a = rtWidget.width / 2.0f;
314 float b = rtWidget.height / 2.0f;
315 if (forceRound) {
316 a = std::min(a, b);
317 b = a;
318 }
319
320 CFX_PointF center = rtWidget.Center();
321 rtWidget.left = center.x - a;
322 rtWidget.top = center.y - b;
323 rtWidget.width = a + a;
324 rtWidget.height = b + b;
325
326 CFGAS_GEPath arcPath;
327 arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FXSYS_PI / 4.0f,
328 FXSYS_PI);
329
331 pGS->StrokePath(arcPath, matrix);
332 arcPath.Clear();
333 arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FXSYS_PI / 4.0f,
334 FXSYS_PI);
335
337 pGS->StrokePath(arcPath, matrix);
338 rtWidget.Deflate(fHalf, fHalf);
339 arcPath.Clear();
340 arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FXSYS_PI / 4.0f,
341 FXSYS_PI);
342
344 pGS->StrokePath(arcPath, matrix);
345 arcPath.Clear();
346 arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FXSYS_PI / 4.0f,
347 FXSYS_PI);
348
350 pGS->StrokePath(arcPath, matrix);
351}
CFGAS_GEColor(const FX_ARGB argb)
StateRestorer(CFGAS_GEGraphics *graphics)
void SetLineWidth(float lineWidth)
void SetStrokeColor(const CFGAS_GEColor &color)
void StrokePath(const CFGAS_GEPath &path, const CFX_Matrix &matrix)
void AddEllipse(const CFX_RectF &rect)
void AddArc(const CFX_PointF &pos, const CFX_SizeF &size, float startAngle, float sweepAngle)
void Inflate(float x, float y)
void Deflate(float x, float y)
std::tuple< XFA_AttributeValue, bool, float > Get3DStyle()
Definition cxfa_box.cpp:126
std::vector< CXFA_Stroke * > GetStrokes()
Definition cxfa_box.cpp:106
XFA_AttributeValue GetHand()
Definition cxfa_box.cpp:83
CXFA_Edge * GetEdgeIfExists(size_t nIndex)
Definition cxfa_box.cpp:97
size_t CountEdges()
Definition cxfa_box.cpp:93
~CXFA_Box() override
XFA_AttributeValue GetPresence()
Definition cxfa_box.cpp:87
CXFA_Fill * GetOrCreateFillIfPossible()
Definition cxfa_box.cpp:122
void Draw(CFGAS_GEGraphics *pGS, const CFX_RectF &rtWidget, const CFX_Matrix &matrix, bool forceRound)
Definition cxfa_box.cpp:187
CXFA_Box(CXFA_Document *pDoc, XFA_PacketType ePacket, Mask< XFA_XDPPACKET > validPackets, XFA_ObjectType oType, XFA_Element eType, pdfium::span< const PropertyData > properties, pdfium::span< const AttributeData > attributes, CJX_Object *js_node)
Definition cxfa_box.cpp:64
void Draw(CFGAS_GEGraphics *pGS, const CFGAS_GEPath &fillPath, const CFX_RectF &rtWidget, const CFX_Matrix &matrix)
Definition cxfa_fill.cpp:95
bool IsVisible()
Definition cxfa_fill.cpp:57
XFA_Element GetElementType() const
Definition cxfa_object.h:91
void Stroke(CFGAS_GEGraphics *pGS, const CFGAS_GEPath &pPath, const CFX_Matrix &matrix)
bool IsVisible()
float GetThickness() const
XFA_AttributeValue GetStrokeType()
XFA_ObjectType
Definition cxfa_object.h:21
#define FXSYS_PI
Definition fx_system.h:43
XFA_Attribute
Definition fxfa_basic.h:67
XFA_XDPPACKET
Definition fxfa_basic.h:51
XFA_Element
Definition fxfa_basic.h:75
XFA_AttributeValue
Definition fxfa_basic.h:60
XFA_PacketType
Definition fxfa_basic.h:44