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