1//========================================================================
2//
3// PreScanOutputDev.cc
4//
5// Copyright 2005 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
17// Copyright (C) 2010, 2011, 2018-2021 Albert Astals Cid <aacid@kde.org>
18// Copyright (C) 2011, 2014 William Bader <williambader@hotmail.com>
19// Copyright (C) 2011, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
20// Copyright (C) 2011 Adrian Johnson <ajohnson@redneon.com>
21// Copyright (C) 2022 Oliver Sander <oliver.sander@tu-dresden.de>
22//
23// To see a description of the changes please see the Changelog file that
24// came with your tarball or type make ChangeLog if you are building from git
25//
26//========================================================================
27
28#include <config.h>
29
30#include <cmath>
31#include "GlobalParams.h"
32#include "Gfx.h"
33#include "GfxFont.h"
34#include "Link.h"
35#include "Catalog.h"
36#include "Page.h"
37#include "PreScanOutputDev.h"
38
39//------------------------------------------------------------------------
40// PreScanOutputDev
41//------------------------------------------------------------------------
42
43PreScanOutputDev::PreScanOutputDev(PSLevel levelA) : level(levelA)
44{
45 clearStats();
46}
47
48PreScanOutputDev::~PreScanOutputDev() { }
49
50void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/, XRef * /*xref*/) { }
51
52void PreScanOutputDev::endPage() { }
53
54void PreScanOutputDev::stroke(GfxState *state)
55{
56 double dashStart;
57
58 check(colorSpace: state->getStrokeColorSpace(), color: state->getStrokeColor(), opacity: state->getStrokeOpacity(), blendMode: state->getBlendMode());
59 const std::vector<double> &dash = state->getLineDash(start: &dashStart);
60 if (dash.size() != 0) {
61 gdi = false;
62 }
63}
64
65void PreScanOutputDev::fill(GfxState *state)
66{
67 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
68}
69
70void PreScanOutputDev::eoFill(GfxState *state)
71{
72 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
73}
74
75bool PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *catalog, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep)
76{
77 if (tPat->getPaintType() == 1) {
78 bool tilingNeeded = (x1 - x0 != 1 || y1 - y0 != 1);
79 if (tilingNeeded) {
80 inTilingPatternFill++;
81 }
82 gfx->drawForm(str: tPat->getContentStream(), resDict: tPat->getResDict(), matrix: mat, bbox: tPat->getBBox());
83 if (tilingNeeded) {
84 inTilingPatternFill--;
85 }
86 } else {
87 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
88 }
89 return true;
90}
91
92bool PreScanOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading)
93{
94 if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) {
95 gray = false;
96 }
97 mono = false;
98 if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) {
99 transparency = true;
100 }
101 return true;
102}
103
104bool PreScanOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/)
105{
106 if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) {
107 gray = false;
108 }
109 mono = false;
110 if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) {
111 transparency = true;
112 }
113 return true;
114}
115
116bool PreScanOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/)
117{
118 if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) {
119 gray = false;
120 }
121 mono = false;
122 if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) {
123 transparency = true;
124 }
125 return true;
126}
127
128void PreScanOutputDev::clip(GfxState * /*state*/)
129{
130 //~ check for a rectangle "near" the edge of the page;
131 //~ else set gdi to false
132}
133
134void PreScanOutputDev::eoClip(GfxState * /*state*/)
135{
136 //~ see clip()
137}
138
139void PreScanOutputDev::beginStringOp(GfxState *state)
140{
141 int render;
142 double m11, m12, m21, m22;
143 bool simpleTTF;
144
145 render = state->getRender();
146 if (!(render & 1)) {
147 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
148 }
149 if ((render & 3) == 1 || (render & 3) == 2) {
150 check(colorSpace: state->getStrokeColorSpace(), color: state->getStrokeColor(), opacity: state->getStrokeOpacity(), blendMode: state->getBlendMode());
151 }
152
153 std::shared_ptr<const GfxFont> font = state->getFont();
154 state->getFontTransMat(m11: &m11, m12: &m12, m21: &m21, m22: &m22);
155 //~ this should check for external fonts that are non-TrueType
156 simpleTTF = fabs(x: m11 + m22) < 0.01 && m11 > 0 && fabs(x: m12) < 0.01 && fabs(x: m21) < 0.01 && fabs(x: state->getHorizScaling() - 1) < 0.001 && (font->getType() == fontTrueType || font->getType() == fontTrueTypeOT);
157 if (simpleTTF) {
158 //~ need to create a FoFiTrueType object, and check for a Unicode cmap
159 }
160 if (state->getRender() != 0 || !simpleTTF) {
161 gdi = false;
162 }
163}
164
165void PreScanOutputDev::endStringOp(GfxState * /*state*/) { }
166
167bool PreScanOutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/, CharCode /*code*/, const Unicode * /*u*/, int /*uLen*/)
168{
169 // return false so all Type 3 chars get rendered (no caching)
170 return false;
171}
172
173void PreScanOutputDev::endType3Char(GfxState * /*state*/) { }
174
175void PreScanOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str, int width, int height, bool /*invert*/, bool /*interpolate*/, bool inlineImg)
176{
177 int i, j;
178
179 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
180 gdi = false;
181 if ((level == psLevel1 || level == psLevel1Sep) && (state->getFillColorSpace()->getMode() == csPattern || inTilingPatternFill > 0)) {
182 patternImgMask = true;
183 }
184
185 if (inlineImg) {
186 str->reset();
187 j = height * ((width + 7) / 8);
188 for (i = 0; i < j; ++i) {
189 str->getChar();
190 }
191 str->close();
192 }
193}
194
195void PreScanOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool /*interpolate*/, const int * /*maskColors*/, bool inlineImg)
196{
197 GfxColorSpace *colorSpace;
198 int i, j;
199
200 colorSpace = colorMap->getColorSpace();
201 if (colorSpace->getMode() == csIndexed) {
202 colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
203 }
204 if (colorSpace->getMode() == csDeviceGray || colorSpace->getMode() == csCalGray) {
205 if (colorMap->getBits() > 1) {
206 mono = false;
207 }
208 } else {
209 gray = false;
210 mono = false;
211 }
212 if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) {
213 transparency = true;
214 }
215 gdi = false;
216 if ((level == psLevel1 || level == psLevel1Sep) && inTilingPatternFill > 0) {
217 patternImgMask = true;
218 }
219
220 if (inlineImg) {
221 str->reset();
222 j = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8);
223 for (i = 0; i < j; ++i) {
224 str->getChar();
225 }
226 str->close();
227 }
228}
229
230void PreScanOutputDev::drawMaskedImage(GfxState *state, Object * /*ref*/, Stream * /*str*/, int /*width*/, int /*height*/, GfxImageColorMap *colorMap, bool /*interpolate*/, Stream * /*maskStr*/, int /*maskWidth*/, int /*maskHeight*/,
231 bool /*maskInvert*/, bool /*maskInterpolate*/)
232{
233 GfxColorSpace *colorSpace;
234
235 colorSpace = colorMap->getColorSpace();
236 if (colorSpace->getMode() == csIndexed) {
237 colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
238 }
239 if (colorSpace->getMode() == csDeviceGray || colorSpace->getMode() == csCalGray) {
240 if (colorMap->getBits() > 1) {
241 mono = false;
242 }
243 } else {
244 gray = false;
245 mono = false;
246 }
247 if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) {
248 transparency = true;
249 }
250 gdi = false;
251}
252
253void PreScanOutputDev::drawSoftMaskedImage(GfxState * /*state*/, Object * /*ref*/, Stream * /*str*/, int /*width*/, int /*height*/, GfxImageColorMap *colorMap, bool /*interpolate*/, Stream * /*maskStr*/, int /*maskWidth*/,
254 int /*maskHeight*/, GfxImageColorMap * /*maskColorMap*/, bool /*maskInterpolate*/)
255{
256 GfxColorSpace *colorSpace;
257
258 colorSpace = colorMap->getColorSpace();
259 if (colorSpace->getMode() == csIndexed) {
260 colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
261 }
262 if (colorSpace->getMode() != csDeviceGray && colorSpace->getMode() != csCalGray) {
263 gray = false;
264 }
265 mono = false;
266 transparency = true;
267 gdi = false;
268}
269
270void PreScanOutputDev::beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/)
271{
272 gdi = false;
273}
274
275void PreScanOutputDev::paintTransparencyGroup(GfxState *state, const double * /*bbox*/)
276{
277 check(colorSpace: state->getFillColorSpace(), color: state->getFillColor(), opacity: state->getFillOpacity(), blendMode: state->getBlendMode());
278}
279
280void PreScanOutputDev::setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/)
281{
282 transparency = true;
283}
284
285void PreScanOutputDev::check(GfxColorSpace *colorSpace, const GfxColor *color, double opacity, GfxBlendMode blendMode)
286{
287 GfxRGB rgb;
288
289 if (colorSpace->getMode() == csPattern) {
290 mono = false;
291 gray = false;
292 gdi = false;
293 } else {
294 colorSpace->getRGB(color, rgb: &rgb);
295 if (rgb.r != rgb.g || rgb.g != rgb.b || rgb.b != rgb.r) {
296 mono = false;
297 gray = false;
298 } else if (!((rgb.r == 0 && rgb.g == 0 && rgb.b == 0) || (rgb.r == gfxColorComp1 && rgb.g == gfxColorComp1 && rgb.b == gfxColorComp1))) {
299 mono = false;
300 }
301 }
302 if (opacity != 1 || blendMode != gfxBlendNormal) {
303 transparency = true;
304 }
305}
306
307void PreScanOutputDev::clearStats()
308{
309 mono = true;
310 gray = true;
311 transparency = false;
312 gdi = true;
313 patternImgMask = false;
314 inTilingPatternFill = 0;
315}
316

source code of poppler/poppler/PreScanOutputDev.cc