Home | History | Annotate | Download | only in parser
      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 
     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 
     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 
     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 
     92 XFA_AttributeEnum CXFA_Stroke::GetCapType() {
     93   return JSObject()->GetEnum(XFA_Attribute::Cap);
     94 }
     95 
     96 XFA_AttributeEnum CXFA_Stroke::GetStrokeType() {
     97   return JSObject()->GetEnum(XFA_Attribute::Stroke);
     98 }
     99 
    100 float CXFA_Stroke::GetThickness() const {
    101   return GetMSThickness().ToUnit(XFA_Unit::Pt);
    102 }
    103 
    104 CXFA_Measurement CXFA_Stroke::GetMSThickness() const {
    105   return JSObject()->GetMeasure(XFA_Attribute::Thickness);
    106 }
    107 
    108 void CXFA_Stroke::SetMSThickness(CXFA_Measurement msThinkness) {
    109   JSObject()->SetMeasure(XFA_Attribute::Thickness, msThinkness, false);
    110 }
    111 
    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 
    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 
    137 XFA_AttributeEnum CXFA_Stroke::GetJoinType() {
    138   return JSObject()->GetEnum(XFA_Attribute::Join);
    139 }
    140 
    141 bool CXFA_Stroke::IsInverted() {
    142   return JSObject()->GetBoolean(XFA_Attribute::Inverted);
    143 }
    144 
    145 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 
    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 
    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