• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_AttributeEnum iStrokeType,XFA_AttributeEnum iCapType)19 void XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics,
20                                XFA_AttributeEnum iStrokeType,
21                                XFA_AttributeEnum iCapType) {
22   switch (iStrokeType) {
23     case XFA_AttributeEnum::DashDot: {
24       float dashArray[] = {4, 1, 2, 1};
25       if (iCapType != XFA_AttributeEnum::Butt) {
26         dashArray[1] = 2;
27         dashArray[3] = 2;
28       }
29       pGraphics->SetLineDash(0, dashArray, 4);
30       break;
31     }
32     case XFA_AttributeEnum::DashDotDot: {
33       float dashArray[] = {4, 1, 2, 1, 2, 1};
34       if (iCapType != XFA_AttributeEnum::Butt) {
35         dashArray[1] = 2;
36         dashArray[3] = 2;
37         dashArray[5] = 2;
38       }
39       pGraphics->SetLineDash(0, dashArray, 6);
40       break;
41     }
42     case XFA_AttributeEnum::Dashed: {
43       float dashArray[] = {5, 1};
44       if (iCapType != XFA_AttributeEnum::Butt)
45         dashArray[1] = 2;
46 
47       pGraphics->SetLineDash(0, dashArray, 2);
48       break;
49     }
50     case XFA_AttributeEnum::Dotted: {
51       float dashArray[] = {2, 1};
52       if (iCapType != XFA_AttributeEnum::Butt)
53         dashArray[1] = 2;
54 
55       pGraphics->SetLineDash(0, dashArray, 2);
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,const PropertyData * properties,const AttributeData * attributes,const WideStringView & elementName,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                          const PropertyData* properties,
70                          const AttributeData* attributes,
71                          const WideStringView& elementName,
72                          std::unique_ptr<CJX_Object> js_node)
73     : CXFA_Node(pDoc,
74                 ePacket,
75                 validPackets,
76                 oType,
77                 eType,
78                 properties,
79                 attributes,
80                 elementName,
81                 std::move(js_node)) {}
82 
83 CXFA_Stroke::~CXFA_Stroke() = default;
84 
IsVisible()85 bool CXFA_Stroke::IsVisible() {
86   XFA_AttributeEnum presence = JSObject()
87                                    ->TryEnum(XFA_Attribute::Presence, true)
88                                    .value_or(XFA_AttributeEnum::Visible);
89   return presence == XFA_AttributeEnum::Visible;
90 }
91 
GetCapType()92 XFA_AttributeEnum CXFA_Stroke::GetCapType() {
93   return JSObject()->GetEnum(XFA_Attribute::Cap);
94 }
95 
GetStrokeType()96 XFA_AttributeEnum CXFA_Stroke::GetStrokeType() {
97   return JSObject()->GetEnum(XFA_Attribute::Stroke);
98 }
99 
GetThickness() const100 float CXFA_Stroke::GetThickness() const {
101   return GetMSThickness().ToUnit(XFA_Unit::Pt);
102 }
103 
GetMSThickness() const104 CXFA_Measurement CXFA_Stroke::GetMSThickness() const {
105   return JSObject()->GetMeasure(XFA_Attribute::Thickness);
106 }
107 
SetMSThickness(CXFA_Measurement msThinkness)108 void CXFA_Stroke::SetMSThickness(CXFA_Measurement msThinkness) {
109   JSObject()->SetMeasure(XFA_Attribute::Thickness, msThinkness, false);
110 }
111 
GetColor()112 FX_ARGB CXFA_Stroke::GetColor() {
113   CXFA_Color* pNode = GetChild<CXFA_Color>(0, XFA_Element::Color, false);
114   if (!pNode)
115     return 0xFF000000;
116 
117   return StringToFXARGB(
118       pNode->JSObject()->GetCData(XFA_Attribute::Value).AsStringView());
119 }
120 
SetColor(FX_ARGB argb)121 void CXFA_Stroke::SetColor(FX_ARGB argb) {
122   CXFA_Color* pNode =
123       JSObject()->GetOrCreateProperty<CXFA_Color>(0, XFA_Element::Color);
124   if (!pNode)
125     return;
126 
127   int a;
128   int r;
129   int g;
130   int b;
131   std::tie(a, r, g, b) = ArgbDecode(argb);
132   pNode->JSObject()->SetCData(XFA_Attribute::Value,
133                               WideString::Format(L"%d,%d,%d", r, g, b), false,
134                               false);
135 }
136 
GetJoinType()137 XFA_AttributeEnum 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,uint32_t dwFlags)152 bool CXFA_Stroke::SameStyles(CXFA_Stroke* stroke, uint32_t dwFlags) {
153   if (this == stroke)
154     return true;
155   if (fabs(GetThickness() - stroke->GetThickness()) >= 0.01f)
156     return false;
157   if ((dwFlags & XFA_STROKE_SAMESTYLE_NoPresence) == 0 &&
158       IsVisible() != stroke->IsVisible()) {
159     return false;
160   }
161   if (GetStrokeType() != stroke->GetStrokeType())
162     return false;
163   if (GetColor() != stroke->GetColor())
164     return false;
165   if ((dwFlags & XFA_STROKE_SAMESTYLE_Corner) != 0 &&
166       fabs(GetRadius() - stroke->GetRadius()) >= 0.01f) {
167     return false;
168   }
169   return true;
170 }
171 
Stroke(CXFA_GEPath * pPath,CXFA_Graphics * pGS,const CFX_Matrix & matrix)172 void CXFA_Stroke::Stroke(CXFA_GEPath* pPath,
173                          CXFA_Graphics* pGS,
174                          const CFX_Matrix& matrix) {
175   if (!IsVisible())
176     return;
177 
178   float fThickness = GetThickness();
179   if (fThickness < 0.001f)
180     return;
181 
182   pGS->SaveGraphState();
183   if (IsCorner() && fThickness > 2 * GetRadius())
184     fThickness = 2 * GetRadius();
185 
186   pGS->SetLineWidth(fThickness);
187   pGS->EnableActOnDash();
188   pGS->SetLineCap(CFX_GraphStateData::LineCapButt);
189   XFA_StrokeTypeSetLineDash(pGS, GetStrokeType(), XFA_AttributeEnum::Butt);
190   pGS->SetStrokeColor(CXFA_GEColor(GetColor()));
191   pGS->StrokePath(pPath, &matrix);
192   pGS->RestoreGraphState();
193 }
194