1 //========================================================================
3 // MarkedContentOutputDev.cc
5 // This file is licensed under the GPLv2 or later
7 // Copyright 2013 Igalia S.L.
9 //========================================================================
11 #include "MarkedContentOutputDev.h"
12 #include "GlobalParams.h"
13 #include "UnicodeMap.h"
20 MarkedContentOutputDev::MarkedContentOutputDev(int mcidA
):
28 currentColor
.r
= currentColor
.g
= currentColor
.b
= 0;
32 MarkedContentOutputDev::~MarkedContentOutputDev()
35 unicodeMap
->decRefCnt();
37 currentFont
->decRefCnt();
42 void MarkedContentOutputDev::endSpan()
44 if (currentText
&& currentText
->getLength()) {
45 // The TextSpan takes ownership of currentText and
46 // increases the reference count for currentFont.
47 textSpans
.push_back(TextSpan(currentText
,
55 void MarkedContentOutputDev::startPage(int pageNum
, GfxState
*state
, XRef
*xref
)
58 pageWidth
= state
->getPageWidth();
59 pageHeight
= state
->getPageHeight();
61 pageWidth
= pageHeight
= 0.0;
66 void MarkedContentOutputDev::endPage()
68 pageWidth
= pageHeight
= 0.0;
72 void MarkedContentOutputDev::beginMarkedContent(char *name
, Dict
*properties
)
76 properties
->lookupInt("MCID", NULL
, &id
);
81 // The stack keep track of MCIDs of nested marked content.
82 if (inMarkedContent() || id
== mcid
)
83 mcidStack
.push_back(id
);
87 void MarkedContentOutputDev::endMarkedContent(GfxState
*state
)
89 if (inMarkedContent()) {
91 // The outer marked content sequence MCID was popped, ensure
92 // that the last piece of text collected ends up in a TextSpan.
93 if (!inMarkedContent())
99 bool MarkedContentOutputDev::needFontChange(GfxFont
* font
) const
101 if (currentFont
== font
)
105 return font
!= NULL
&& font
->isOk();
110 // Two non-null valid fonts are the same if they point to the same Ref
111 if (currentFont
->getID()->num
== font
->getID()->num
&&
112 currentFont
->getID()->gen
== font
->getID()->gen
)
119 void MarkedContentOutputDev::drawChar(GfxState
*state
,
120 double xx
, double yy
,
121 double dx
, double dy
,
122 double ox
, double oy
,
123 CharCode c
, int nBytes
,
124 Unicode
*u
, int uLen
)
126 if (!inMarkedContent() || !uLen
)
130 // Color changes are tracked here so the color can be chosen depending on
131 // the render mode (for mode 1 stroke color is used), so there is no need
132 // to implement both updateFillColor() and updateStrokeColor().
133 GBool colorChange
= gFalse
;
135 if ((state
->getRender() & 3) == 1)
136 state
->getStrokeRGB(&color
);
138 state
->getFillRGB(&color
);
140 colorChange
= (color
.r
!= currentColor
.r
||
141 color
.g
!= currentColor
.g
||
142 color
.b
!= currentColor
.b
);
144 // Check also for font changes.
145 GBool fontChange
= needFontChange(state
->getFont());
147 // Save a span with the current changes.
148 if (colorChange
|| fontChange
) {
152 // Perform the color/font changes.
154 currentColor
= color
;
157 if (currentFont
!= NULL
) {
158 currentFont
->decRefCnt();
161 if (state
->getFont() != NULL
) {
162 currentFont
= state
->getFont();
163 currentFont
->incRefCnt();
168 double sp
, dx2
, dy2
, w1
, h1
, x1
, y1
;
170 // Subtract char and word spacing from the (dx,dy) values
171 sp
= state
->getCharSpace();
172 if (c
== (CharCode
) 0x20)
173 sp
+= state
->getWordSpace();
174 state
->textTransformDelta(sp
* state
->getHorizScaling(), 0, &dx2
, &dy2
);
177 state
->transformDelta(dx
, dy
, &w1
, &h1
);
178 state
->transform(xx
, yy
, &x1
, &y1
);
180 // Throw away characters that are not inside the page boundaries.
181 if (x1
+ w1
< 0 || x1
> pageWidth
|| y1
+ h1
< 0 || y1
> pageHeight
)
184 // Make a sanity check on character size. Note: (x != x) <-> isnan(x)
185 if (x1
!= x1
|| y1
!= y1
|| w1
!= w1
|| h1
!= h1
)
188 for (int i
= 0; i
< uLen
; i
++) {
189 // Soft hyphen markers are skipped, as they are invisible unless
190 // rendering is done to an actual device and the hyphenation hint
191 // used. MarkedContentOutputDev extracts the *visible* text content.
192 if (u
[i
] != 0x00AD) {
193 // Add the UTF-8 sequence to the current text span.
195 unicodeMap
= globalParams
->getTextEncoding();
198 int n
= unicodeMap
->mapUnicode(u
[i
], buf
, sizeof(buf
));
200 if (currentText
== NULL
)
201 currentText
= new GooString();
202 currentText
->append(buf
, n
);
209 const TextSpanArray
& MarkedContentOutputDev::getTextSpans() const