Home | History | Annotate | Download | only in fpdfsdk
      1 // Copyright 2017 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 #include <vector>
      6 
      7 #include "public/fpdf_edit.h"
      8 
      9 #include "core/fpdfapi/page/cpdf_path.h"
     10 #include "core/fpdfapi/page/cpdf_pathobject.h"
     11 #include "core/fxcrt/fx_system.h"
     12 #include "fpdfsdk/fsdk_define.h"
     13 #include "third_party/base/ptr_util.h"
     14 
     15 // These checks are here because core/ and public/ cannot depend on each other.
     16 static_assert(CFX_GraphStateData::LineCapButt == FPDF_LINECAP_BUTT,
     17               "CFX_GraphStateData::LineCapButt value mismatch");
     18 static_assert(CFX_GraphStateData::LineCapRound == FPDF_LINECAP_ROUND,
     19               "CFX_GraphStateData::LineCapRound value mismatch");
     20 static_assert(CFX_GraphStateData::LineCapSquare ==
     21                   FPDF_LINECAP_PROJECTING_SQUARE,
     22               "CFX_GraphStateData::LineCapSquare value mismatch");
     23 
     24 static_assert(CFX_GraphStateData::LineJoinMiter == FPDF_LINEJOIN_MITER,
     25               "CFX_GraphStateData::LineJoinMiter value mismatch");
     26 static_assert(CFX_GraphStateData::LineJoinRound == FPDF_LINEJOIN_ROUND,
     27               "CFX_GraphStateData::LineJoinRound value mismatch");
     28 static_assert(CFX_GraphStateData::LineJoinBevel == FPDF_LINEJOIN_BEVEL,
     29               "CFX_GraphStateData::LineJoinBevel value mismatch");
     30 
     31 static_assert(static_cast<int>(FXPT_TYPE::LineTo) == FPDF_SEGMENT_LINETO,
     32               "FXPT_TYPE::LineTo value mismatch");
     33 static_assert(static_cast<int>(FXPT_TYPE::BezierTo) == FPDF_SEGMENT_BEZIERTO,
     34               "FXPT_TYPE::BezierTo value mismatch");
     35 static_assert(static_cast<int>(FXPT_TYPE::MoveTo) == FPDF_SEGMENT_MOVETO,
     36               "FXPT_TYPE::MoveTo value mismatch");
     37 
     38 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewPath(float x,
     39                                                                     float y) {
     40   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
     41   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
     42   pPathObj->DefaultStates();
     43   return pPathObj.release();  // Caller takes ownership.
     44 }
     45 
     46 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV FPDFPageObj_CreateNewRect(float x,
     47                                                                     float y,
     48                                                                     float w,
     49                                                                     float h) {
     50   auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
     51   pPathObj->m_Path.AppendRect(x, y, x + w, y + h);
     52   pPathObj->DefaultStates();
     53   return pPathObj.release();  // Caller takes ownership.
     54 }
     55 
     56 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
     57 FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
     58                         unsigned int R,
     59                         unsigned int G,
     60                         unsigned int B,
     61                         unsigned int A) {
     62   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
     63   if (!pPathObj || R > 255 || G > 255 || B > 255 || A > 255)
     64     return false;
     65 
     66   float rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
     67   pPathObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
     68   pPathObj->m_ColorState.SetStrokeColor(
     69       CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
     70   pPathObj->SetDirty(true);
     71   return true;
     72 }
     73 
     74 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
     75 FPDFPath_GetStrokeColor(FPDF_PAGEOBJECT path,
     76                         unsigned int* R,
     77                         unsigned int* G,
     78                         unsigned int* B,
     79                         unsigned int* A) {
     80   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
     81   if (!pPathObj || !R || !G || !B || !A)
     82     return false;
     83 
     84   uint32_t strokeRGB = pPathObj->m_ColorState.GetStrokeRGB();
     85   *R = FXSYS_GetRValue(strokeRGB);
     86   *G = FXSYS_GetGValue(strokeRGB);
     87   *B = FXSYS_GetBValue(strokeRGB);
     88   *A = static_cast<unsigned int>(
     89       (pPathObj->m_GeneralState.GetStrokeAlpha() * 255.f) + 0.5f);
     90   return true;
     91 }
     92 
     93 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
     94 FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width) {
     95   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
     96   if (!pPathObj || width < 0.0f)
     97     return false;
     98 
     99   pPathObj->m_GraphState.SetLineWidth(width);
    100   pPathObj->SetDirty(true);
    101   return true;
    102 }
    103 
    104 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
    105                                                           unsigned int R,
    106                                                           unsigned int G,
    107                                                           unsigned int B,
    108                                                           unsigned int A) {
    109   return FPDFPageObj_SetFillColor(path, R, G, B, A);
    110 }
    111 
    112 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_GetFillColor(FPDF_PAGEOBJECT path,
    113                                                           unsigned int* R,
    114                                                           unsigned int* G,
    115                                                           unsigned int* B,
    116                                                           unsigned int* A) {
    117   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    118   if (!pPathObj || !R || !G || !B || !A)
    119     return false;
    120 
    121   uint32_t fillRGB = pPathObj->m_ColorState.GetFillRGB();
    122   *R = FXSYS_GetRValue(fillRGB);
    123   *G = FXSYS_GetGValue(fillRGB);
    124   *B = FXSYS_GetBValue(fillRGB);
    125   *A = static_cast<unsigned int>(
    126       (pPathObj->m_GeneralState.GetFillAlpha() * 255.f) + 0.5f);
    127   return true;
    128 }
    129 
    130 FPDF_EXPORT int FPDF_CALLCONV FPDFPath_CountSegments(FPDF_PAGEOBJECT path) {
    131   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    132   if (!pPathObj)
    133     return -1;
    134   return pdfium::CollectionSize<int>(pPathObj->m_Path.GetPoints());
    135 }
    136 
    137 FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
    138 FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index) {
    139   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    140   if (!pPathObj)
    141     return nullptr;
    142 
    143   const std::vector<FX_PATHPOINT>& points = pPathObj->m_Path.GetPoints();
    144   return pdfium::IndexInBounds(points, index) ? &points[index] : nullptr;
    145 }
    146 
    147 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_MoveTo(FPDF_PAGEOBJECT path,
    148                                                     float x,
    149                                                     float y) {
    150   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    151   if (!pPathObj)
    152     return false;
    153 
    154   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::MoveTo, false);
    155   pPathObj->SetDirty(true);
    156   return true;
    157 }
    158 
    159 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_LineTo(FPDF_PAGEOBJECT path,
    160                                                     float x,
    161                                                     float y) {
    162   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    163   if (!pPathObj)
    164     return false;
    165 
    166   pPathObj->m_Path.AppendPoint(CFX_PointF(x, y), FXPT_TYPE::LineTo, false);
    167   pPathObj->SetDirty(true);
    168   return true;
    169 }
    170 
    171 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
    172                                                       float x1,
    173                                                       float y1,
    174                                                       float x2,
    175                                                       float y2,
    176                                                       float x3,
    177                                                       float y3) {
    178   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    179   if (!pPathObj)
    180     return false;
    181 
    182   pPathObj->m_Path.AppendPoint(CFX_PointF(x1, y1), FXPT_TYPE::BezierTo, false);
    183   pPathObj->m_Path.AppendPoint(CFX_PointF(x2, y2), FXPT_TYPE::BezierTo, false);
    184   pPathObj->m_Path.AppendPoint(CFX_PointF(x3, y3), FXPT_TYPE::BezierTo, false);
    185   pPathObj->SetDirty(true);
    186   return true;
    187 }
    188 
    189 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_Close(FPDF_PAGEOBJECT path) {
    190   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    191   if (!pPathObj)
    192     return false;
    193 
    194   if (pPathObj->m_Path.GetPoints().empty())
    195     return false;
    196 
    197   pPathObj->m_Path.ClosePath();
    198   pPathObj->SetDirty(true);
    199   return true;
    200 }
    201 
    202 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
    203                                                          int fillmode,
    204                                                          FPDF_BOOL stroke) {
    205   auto* pPathObj = CPDFPathObjectFromFPDFPageObject(path);
    206   if (!pPathObj)
    207     return false;
    208 
    209   if (fillmode == FPDF_FILLMODE_ALTERNATE)
    210     pPathObj->m_FillType = FXFILL_ALTERNATE;
    211   else if (fillmode == FPDF_FILLMODE_WINDING)
    212     pPathObj->m_FillType = FXFILL_WINDING;
    213   else
    214     pPathObj->m_FillType = 0;
    215   pPathObj->m_bStroke = stroke != 0;
    216   pPathObj->SetDirty(true);
    217   return true;
    218 }
    219 
    220 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineJoin(FPDF_PAGEOBJECT path,
    221                                                     int line_join) {
    222   if (!path)
    223     return;
    224   if (line_join <
    225           static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinMiter) ||
    226       line_join >
    227           static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinBevel)) {
    228     return;
    229   }
    230   auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
    231   CFX_GraphStateData::LineJoin lineJoin =
    232       static_cast<CFX_GraphStateData::LineJoin>(line_join);
    233   pPathObj->m_GraphState.SetLineJoin(lineJoin);
    234   pPathObj->SetDirty(true);
    235 }
    236 
    237 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineCap(FPDF_PAGEOBJECT path,
    238                                                    int line_cap) {
    239   if (!path)
    240     return;
    241   if (line_cap < static_cast<int>(CFX_GraphStateData::LineCap::LineCapButt) ||
    242       line_cap > static_cast<int>(CFX_GraphStateData::LineCap::LineCapSquare)) {
    243     return;
    244   }
    245   auto* pPathObj = CPDFPageObjectFromFPDFPageObject(path);
    246   CFX_GraphStateData::LineCap lineCap =
    247       static_cast<CFX_GraphStateData::LineCap>(line_cap);
    248   pPathObj->m_GraphState.SetLineCap(lineCap);
    249   pPathObj->SetDirty(true);
    250 }
    251 
    252 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
    253 FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y) {
    254   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
    255   if (!pPathPoint || !x || !y)
    256     return false;
    257 
    258   *x = pPathPoint->m_Point.x;
    259   *y = pPathPoint->m_Point.y;
    260 
    261   return true;
    262 }
    263 
    264 FPDF_EXPORT int FPDF_CALLCONV
    265 FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment) {
    266   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
    267 
    268   return pPathPoint ? static_cast<int>(pPathPoint->m_Type)
    269                     : FPDF_SEGMENT_UNKNOWN;
    270 }
    271 
    272 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
    273 FPDFPathSegment_GetClose(FPDF_PATHSEGMENT segment) {
    274   auto* pPathPoint = FXPathPointFromFPDFPathSegment(segment);
    275 
    276   return pPathPoint ? pPathPoint->m_CloseFigure : false;
    277 }
    278