Home | History | Annotate | Download | only in skia
      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 #include "core/fxge/cfx_fxgedevice.h"
      6 #include "core/fxge/cfx_graphstatedata.h"
      7 #include "core/fxge/cfx_pathdata.h"
      8 #include "core/fxge/cfx_renderdevice.h"
      9 #include "core/fxge/skia/fx_skia_device.h"
     10 #include "fpdfsdk/fsdk_define.h"
     11 #include "public/fpdfview.h"
     12 #include "testing/fx_string_testhelpers.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 #include "third_party/skia/include/core/SkPictureRecorder.h"
     15 
     16 namespace {
     17 
     18 struct State {
     19   enum class Change { kNo, kYes };
     20   enum class Save { kNo, kYes };
     21   enum class Clip { kNo, kSame, kDifferentPath, kDifferentMatrix };
     22   enum class Graphic { kNone, kPath, kText };
     23 
     24   Change m_change;
     25   Save m_save;
     26   Clip m_clip;
     27   Graphic m_graphic;
     28   uint32_t m_pixel;
     29 };
     30 
     31 void EmptyTest(CFX_SkiaDeviceDriver* driver, const State&) {
     32   driver->SaveState();
     33   driver->RestoreState(true);
     34   driver->RestoreState(false);
     35 }
     36 
     37 void CommonTest(CFX_SkiaDeviceDriver* driver, const State& state) {
     38   FXTEXT_CHARPOS charPos[1];
     39   charPos[0].m_Origin = CFX_PointF(0, 1);
     40   charPos[0].m_GlyphIndex = 1;
     41   charPos[0].m_FontCharWidth = 4;
     42 
     43   CFX_Font font;
     44   FX_FLOAT fontSize = 1;
     45   CFX_PathData clipPath, clipPath2;
     46   clipPath.AppendRect(0, 0, 3, 1);
     47   clipPath2.AppendRect(0, 0, 2, 1);
     48   CFX_Matrix clipMatrix;
     49   CFX_Matrix clipMatrix2(1, 0, 0, 1, 0, 1);
     50   driver->SaveState();
     51   CFX_PathData path1;
     52   path1.AppendRect(0, 0, 1, 2);
     53 
     54   CFX_Matrix matrix;
     55   CFX_Matrix matrix2;
     56   matrix2.Translate(1, 0);
     57   CFX_GraphStateData graphState;
     58   if (state.m_save == State::Save::kYes)
     59     driver->SaveState();
     60   if (state.m_clip != State::Clip::kNo)
     61     driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
     62   if (state.m_graphic == State::Graphic::kPath) {
     63     driver->DrawPath(&path1, &matrix, &graphState, 0xFF112233, 0,
     64                      FXFILL_WINDING, 0);
     65   } else if (state.m_graphic == State::Graphic::kText) {
     66     driver->DrawDeviceText(SK_ARRAY_COUNT(charPos), charPos, &font, &matrix,
     67                            fontSize, 0xFF445566);
     68   }
     69   if (state.m_save == State::Save::kYes)
     70     driver->RestoreState(true);
     71   CFX_PathData path2;
     72   path2.AppendRect(0, 0, 2, 2);
     73   if (state.m_change == State::Change::kYes) {
     74     if (state.m_graphic == State::Graphic::kPath)
     75       graphState.m_LineCap = CFX_GraphStateData::LineCapRound;
     76     else if (state.m_graphic == State::Graphic::kText)
     77       fontSize = 2;
     78   }
     79   if (state.m_clip == State::Clip::kSame)
     80     driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
     81   else if (state.m_clip == State::Clip::kDifferentPath)
     82     driver->SetClip_PathFill(&clipPath2, &clipMatrix, 0);
     83   else if (state.m_clip == State::Clip::kDifferentMatrix)
     84     driver->SetClip_PathFill(&clipPath, &clipMatrix2, 0);
     85   if (state.m_graphic == State::Graphic::kPath) {
     86     driver->DrawPath(&path2, &matrix2, &graphState, 0xFF112233, 0,
     87                      FXFILL_WINDING, 0);
     88   } else if (state.m_graphic == State::Graphic::kText) {
     89     driver->DrawDeviceText(SK_ARRAY_COUNT(charPos), charPos, &font, &matrix2,
     90                            fontSize, 0xFF445566);
     91   }
     92   if (state.m_save == State::Save::kYes)
     93     driver->RestoreState(false);
     94   driver->RestoreState(false);
     95 }
     96 
     97 void OutOfSequenceClipTest(CFX_SkiaDeviceDriver* driver, const State&) {
     98   CFX_PathData clipPath;
     99   clipPath.AppendRect(1, 0, 3, 1);
    100   CFX_Matrix clipMatrix;
    101   driver->SaveState();
    102   driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
    103   driver->RestoreState(true);
    104   driver->SaveState();
    105   driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
    106   driver->RestoreState(false);
    107   driver->RestoreState(false);
    108 
    109   driver->SaveState();
    110   driver->SaveState();
    111   driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
    112   driver->RestoreState(true);
    113   driver->SetClip_PathFill(&clipPath, &clipMatrix, 0);
    114   driver->RestoreState(false);
    115   driver->RestoreState(false);
    116 }
    117 
    118 void Harness(void (*Test)(CFX_SkiaDeviceDriver*, const State&),
    119              const State& state) {
    120   int h = 1;
    121   int w = 4;
    122   FPDF_BITMAP bitmap = FPDFBitmap_Create(w, h, 1);
    123   EXPECT_NE(nullptr, bitmap);
    124   if (!bitmap)
    125     return;
    126   FPDFBitmap_FillRect(bitmap, 0, 0, w, h, 0x00000000);
    127   CFX_FxgeDevice geDevice;
    128   CFX_DIBitmap* pBitmap = CFXBitmapFromFPDFBitmap(bitmap);
    129   geDevice.Attach(pBitmap, false, nullptr, false);
    130   CFX_SkiaDeviceDriver* driver =
    131       static_cast<CFX_SkiaDeviceDriver*>(geDevice.GetDeviceDriver());
    132   (*Test)(driver, state);
    133   driver->Flush();
    134   uint32_t pixel = pBitmap->GetPixel(0, 0);
    135   EXPECT_EQ(state.m_pixel, pixel);
    136 #ifdef SK_DEBUG
    137   if (!driver)  // force dump to be linked in so it can be called from debugger
    138     driver->Dump();
    139 #endif
    140 }
    141 
    142 }  // namespace
    143 
    144 TEST(fxge, SkiaStateEmpty) {
    145   Harness(&EmptyTest, {});
    146 }
    147 
    148 TEST(fxge, SkiaStatePath) {
    149   Harness(&CommonTest, {State::Change::kNo, State::Save::kYes,
    150                         State::Clip::kSame, State::Graphic::kPath, 0xFF112233});
    151   Harness(&CommonTest,
    152           {State::Change::kNo, State::Save::kYes, State::Clip::kDifferentPath,
    153            State::Graphic::kPath, 0xFF112233});
    154   Harness(&CommonTest, {State::Change::kNo, State::Save::kYes, State::Clip::kNo,
    155                         State::Graphic::kPath, 0xFF112233});
    156   Harness(&CommonTest, {State::Change::kYes, State::Save::kNo, State::Clip::kNo,
    157                         State::Graphic::kPath, 0xFF112233});
    158   Harness(&CommonTest, {State::Change::kNo, State::Save::kNo, State::Clip::kNo,
    159                         State::Graphic::kPath, 0xFF112233});
    160 }
    161 
    162 #ifdef _SKIA_SUPPORT_
    163 TEST(fxge, SkiaStateText) {
    164   Harness(&CommonTest,
    165           {State::Change::kNo, State::Save::kYes, State::Clip::kDifferentMatrix,
    166            State::Graphic::kText, 0xFF445566});
    167   Harness(&CommonTest, {State::Change::kNo, State::Save::kYes,
    168                         State::Clip::kSame, State::Graphic::kText, 0xFF445566});
    169 }
    170 #endif
    171 
    172 TEST(fxge, SkiaStateOOSClip) {
    173   Harness(&OutOfSequenceClipTest, {});
    174 }
    175