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
EmptyTest(CFX_SkiaDeviceDriver * driver,const State &)31 void EmptyTest(CFX_SkiaDeviceDriver* driver, const State&) {
32 driver->SaveState();
33 driver->RestoreState(true);
34 driver->RestoreState(false);
35 }
36
CommonTest(CFX_SkiaDeviceDriver * driver,const State & state)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
OutOfSequenceClipTest(CFX_SkiaDeviceDriver * driver,const State &)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
Harness(void (* Test)(CFX_SkiaDeviceDriver *,const State &),const State & state)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
TEST(fxge,SkiaStateEmpty)144 TEST(fxge, SkiaStateEmpty) {
145 Harness(&EmptyTest, {});
146 }
147
TEST(fxge,SkiaStatePath)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_
TEST(fxge,SkiaStateText)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
TEST(fxge,SkiaStateOOSClip)172 TEST(fxge, SkiaStateOOSClip) {
173 Harness(&OutOfSequenceClipTest, {});
174 }
175