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