1 // Copyright 2016 PDFium 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fxfa/parser/cxfa_stroke.h"
8
9 #include <utility>
10
11 #include "fxjs/xfa/cjx_object.h"
12 #include "xfa/fxfa/cxfa_ffwidget.h"
13 #include "xfa/fxfa/parser/cxfa_color.h"
14 #include "xfa/fxfa/parser/cxfa_measurement.h"
15 #include "xfa/fxfa/parser/cxfa_node.h"
16 #include "xfa/fxfa/parser/xfa_utils.h"
17 #include "xfa/fxgraphics/cxfa_graphics.h"
18
XFA_StrokeTypeSetLineDash(CXFA_Graphics * pGraphics,XFA_AttributeValue iStrokeType,XFA_AttributeValue iCapType)19 void XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics,
20 XFA_AttributeValue iStrokeType,
21 XFA_AttributeValue iCapType) {
22 switch (iStrokeType) {
23 case XFA_AttributeValue::DashDot: {
24 float dashArray[] = {4, 1, 2, 1};
25 if (iCapType != XFA_AttributeValue::Butt) {
26 dashArray[1] = 2;
27 dashArray[3] = 2;
28 }
29 pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
30 break;
31 }
32 case XFA_AttributeValue::DashDotDot: {
33 float dashArray[] = {4, 1, 2, 1, 2, 1};
34 if (iCapType != XFA_AttributeValue::Butt) {
35 dashArray[1] = 2;
36 dashArray[3] = 2;
37 dashArray[5] = 2;
38 }
39 pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
40 break;
41 }
42 case XFA_AttributeValue::Dashed: {
43 float dashArray[] = {5, 1};
44 if (iCapType != XFA_AttributeValue::Butt)
45 dashArray[1] = 2;
46
47 pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
48 break;
49 }
50 case XFA_AttributeValue::Dotted: {
51 float dashArray[] = {2, 1};
52 if (iCapType != XFA_AttributeValue::Butt)
53 dashArray[1] = 2;
54
55 pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
56 break;
57 }
58 default:
59 pGraphics->SetSolidLineDash();
60 break;
61 }
62 }
63
CXFA_Stroke(CXFA_Document * pDoc,XFA_PacketType ePacket,uint32_t validPackets,XFA_ObjectType oType,XFA_Element eType,pdfium::span<const PropertyData> properties,pdfium::span<const AttributeData> attributes,std::unique_ptr<CJX_Object> js_node)64 CXFA_Stroke::CXFA_Stroke(CXFA_Document* pDoc,
65 XFA_PacketType ePacket,
66 uint32_t validPackets,
67 XFA_ObjectType oType,
68 XFA_Element eType,
69 pdfium::span<const PropertyData> properties,
70 pdfium::span<const AttributeData> attributes,
71 std::unique_ptr<CJX_Object> js_node)
72 : CXFA_Node(pDoc,
73 ePacket,
74 validPackets,
75 oType,
76 eType,
77 properties,
78 attributes,
79 std::move(js_node)) {}
80
81 CXFA_Stroke::~CXFA_Stroke() = default;
82
IsVisible()83 bool CXFA_Stroke::IsVisible() {
84 XFA_AttributeValue presence = JSObject()
85 ->TryEnum(XFA_Attribute::Presence, true)
86 .value_or(XFA_AttributeValue::Visible);
87 return presence == XFA_AttributeValue::Visible;
88 }
89
GetCapType()90 XFA_AttributeValue CXFA_Stroke::GetCapType() {
91 return JSObject()->GetEnum(XFA_Attribute::Cap);
92 }
93
GetStrokeType()94 XFA_AttributeValue CXFA_Stroke::GetStrokeType() {
95 return JSObject()->GetEnum(XFA_Attribute::Stroke);
96 }
97
GetThickness() const98 float CXFA_Stroke::GetThickness() const {
99 return GetMSThickness().ToUnit(XFA_Unit::Pt);
100 }
101
GetMSThickness() const102 CXFA_Measurement CXFA_Stroke::GetMSThickness() const {
103 return JSObject()->GetMeasure(XFA_Attribute::Thickness);
104 }
105
SetMSThickness(CXFA_Measurement msThinkness)106 void CXFA_Stroke::SetMSThickness(CXFA_Measurement msThinkness) {
107 JSObject()->SetMeasure(XFA_Attribute::Thickness, msThinkness, false);
108 }
109
GetColor()110 FX_ARGB CXFA_Stroke::GetColor() {
111 CXFA_Color* pNode = GetChild<CXFA_Color>(0, XFA_Element::Color, false);
112 if (!pNode)
113 return 0xFF000000;
114
115 return StringToFXARGB(
116 pNode->JSObject()->GetCData(XFA_Attribute::Value).AsStringView());
117 }
118
SetColor(FX_ARGB argb)119 void CXFA_Stroke::SetColor(FX_ARGB argb) {
120 CXFA_Color* pNode =
121 JSObject()->GetOrCreateProperty<CXFA_Color>(0, XFA_Element::Color);
122 if (!pNode)
123 return;
124
125 int a;
126 int r;
127 int g;
128 int b;
129 std::tie(a, r, g, b) = ArgbDecode(argb);
130 pNode->JSObject()->SetCData(XFA_Attribute::Value,
131 WideString::Format(L"%d,%d,%d", r, g, b), false,
132 false);
133 }
134
GetJoinType()135 XFA_AttributeValue CXFA_Stroke::GetJoinType() {
136 return JSObject()->GetEnum(XFA_Attribute::Join);
137 }
138
IsInverted()139 bool CXFA_Stroke::IsInverted() {
140 return JSObject()->GetBoolean(XFA_Attribute::Inverted);
141 }
142
GetRadius() const143 float CXFA_Stroke::GetRadius() const {
144 return JSObject()
145 ->TryMeasure(XFA_Attribute::Radius, true)
146 .value_or(CXFA_Measurement(0, XFA_Unit::In))
147 .ToUnit(XFA_Unit::Pt);
148 }
149
SameStyles(CXFA_Stroke * stroke,uint32_t dwFlags)150 bool CXFA_Stroke::SameStyles(CXFA_Stroke* stroke, uint32_t dwFlags) {
151 if (this == stroke)
152 return true;
153 if (fabs(GetThickness() - stroke->GetThickness()) >= 0.01f)
154 return false;
155 if ((dwFlags & XFA_STROKE_SAMESTYLE_NoPresence) == 0 &&
156 IsVisible() != stroke->IsVisible()) {
157 return false;
158 }
159 if (GetStrokeType() != stroke->GetStrokeType())
160 return false;
161 if (GetColor() != stroke->GetColor())
162 return false;
163 if ((dwFlags & XFA_STROKE_SAMESTYLE_Corner) != 0 &&
164 fabs(GetRadius() - stroke->GetRadius()) >= 0.01f) {
165 return false;
166 }
167 return true;
168 }
169
Stroke(CXFA_GEPath * pPath,CXFA_Graphics * pGS,const CFX_Matrix & matrix)170 void CXFA_Stroke::Stroke(CXFA_GEPath* pPath,
171 CXFA_Graphics* pGS,
172 const CFX_Matrix& matrix) {
173 if (!IsVisible())
174 return;
175
176 float fThickness = GetThickness();
177 if (fThickness < 0.001f)
178 return;
179
180 pGS->SaveGraphState();
181 if (IsCorner() && fThickness > 2 * GetRadius())
182 fThickness = 2 * GetRadius();
183
184 pGS->SetLineWidth(fThickness);
185 pGS->EnableActOnDash();
186 pGS->SetLineCap(CFX_GraphStateData::LineCapButt);
187 XFA_StrokeTypeSetLineDash(pGS, GetStrokeType(), XFA_AttributeValue::Butt);
188 pGS->SetStrokeColor(CXFA_GEColor(GetColor()));
189 pGS->StrokePath(pPath, &matrix);
190 pGS->RestoreGraphState();
191 }
192