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