beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / MarkedContentOutputDev.cc
blob7fdd8f54c539a1221a6c77eaf37dffc12471ef1d
1 //========================================================================
2 //
3 // MarkedContentOutputDev.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2013 Igalia S.L.
8 //
9 //========================================================================
11 #include "MarkedContentOutputDev.h"
12 #include "GlobalParams.h"
13 #include "UnicodeMap.h"
14 #include "GfxState.h"
15 #include "GfxFont.h"
16 #include "Annot.h"
17 #include <vector>
20 MarkedContentOutputDev::MarkedContentOutputDev(int mcidA):
21 currentFont(NULL),
22 currentText(NULL),
23 mcid(mcidA),
24 pageWidth(0.0),
25 pageHeight(0.0),
26 unicodeMap(NULL)
28 currentColor.r = currentColor.g = currentColor.b = 0;
32 MarkedContentOutputDev::~MarkedContentOutputDev()
34 if (unicodeMap)
35 unicodeMap->decRefCnt();
36 if (currentFont)
37 currentFont->decRefCnt();
38 delete currentText;
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,
48 currentFont,
49 currentColor));
51 currentText = NULL;
55 void MarkedContentOutputDev::startPage(int pageNum, GfxState *state, XRef *xref)
57 if (state) {
58 pageWidth = state->getPageWidth();
59 pageHeight = state->getPageHeight();
60 } else {
61 pageWidth = pageHeight = 0.0;
66 void MarkedContentOutputDev::endPage()
68 pageWidth = pageHeight = 0.0;
72 void MarkedContentOutputDev::beginMarkedContent(char *name, Dict *properties)
74 int id = -1;
75 if (properties)
76 properties->lookupInt("MCID", NULL, &id);
78 if (id == -1)
79 return;
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()) {
90 mcidStack.pop_back();
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())
94 endSpan();
99 bool MarkedContentOutputDev::needFontChange(GfxFont* font) const
101 if (currentFont == font)
102 return gFalse;
104 if (!currentFont)
105 return font != NULL && font->isOk();
107 if (font == NULL)
108 return gTrue;
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)
113 return gFalse;
115 return gTrue;
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)
127 return;
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;
134 GfxRGB color;
135 if ((state->getRender() & 3) == 1)
136 state->getStrokeRGB(&color);
137 else
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) {
149 endSpan();
152 // Perform the color/font changes.
153 if (colorChange)
154 currentColor = color;
156 if (fontChange) {
157 if (currentFont != NULL) {
158 currentFont->decRefCnt();
159 currentFont = NULL;
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);
175 dx -= dx2;
176 dy -= 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)
182 return;
184 // Make a sanity check on character size. Note: (x != x) <-> isnan(x)
185 if (x1 != x1 || y1 != y1 || w1 != w1 || h1 != h1)
186 return;
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.
194 if (!unicodeMap)
195 unicodeMap = globalParams->getTextEncoding();
197 char buf[8];
198 int n = unicodeMap->mapUnicode(u[i], buf, sizeof(buf));
199 if (n > 0) {
200 if (currentText == NULL)
201 currentText = new GooString();
202 currentText->append(buf, n);
209 const TextSpanArray& MarkedContentOutputDev::getTextSpans() const
211 return textSpans;