Rev 25123 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
22514 | jghali | 1 | /* |
2 | For general Scribus (>=1.3.2) copyright and licensing information please refer |
||
3 | to the COPYING file provided with the program. Following this notice may exist |
||
4 | a copyright and/or license notice that predates the release of Scribus 1.3.2 |
||
5 | for which a new license (GPL+exception) is in place. |
||
6 | */ |
||
7 | #ifndef SLAOUTPUT_H |
||
8 | #define SLAOUTPUT_H |
||
9 | |||
10 | #include <QBuffer> |
||
11 | #include <QColor> |
||
12 | #include <QBrush> |
||
13 | #include <QDebug> |
||
14 | #include <QImage> |
||
15 | #include <QPen> |
||
16 | #include <QList> |
||
17 | #include <QSizeF> |
||
18 | #include <QStack> |
||
19 | #include <QString> |
||
20 | #include <QTextStream> |
||
21 | #include <QTransform> |
||
22 | |||
23478 | jghali | 23 | #include <memory> |
24 | |||
22514 | jghali | 25 | #include "fpointarray.h" |
26 | #include "importpdfconfig.h" |
||
27 | #include "pageitem.h" |
||
28 | #include "scribusdoc.h" |
||
29 | #include "scribusview.h" |
||
30 | #include "selection.h" |
||
31 | #include "vgradient.h" |
||
32 | |||
33 | #include <poppler/Object.h> |
||
34 | #include <poppler/OutputDev.h> |
||
35 | #include <poppler/Gfx.h> |
||
36 | #include <poppler/GfxState.h> |
||
37 | #include <poppler/Stream.h> |
||
38 | #include <poppler/GfxFont.h> |
||
39 | #include <poppler/Link.h> |
||
40 | #include <poppler/PDFDoc.h> |
||
41 | #include <poppler/Error.h> |
||
42 | #include <poppler/Form.h> |
||
43 | #include <poppler/Page.h> |
||
44 | #include <poppler/Catalog.h> |
||
45 | #include <poppler/CharCodeToUnicode.h> |
||
46 | #include <poppler/FontEncodingTables.h> |
||
47 | #include <poppler/splash/SplashFontFileID.h> |
||
48 | #include <poppler/splash/SplashFontFile.h> |
||
49 | #include <poppler/splash/SplashFontEngine.h> |
||
50 | #include <poppler/splash/SplashFont.h> |
||
51 | #include <poppler/splash/SplashMath.h> |
||
52 | #include <poppler/splash/SplashPath.h> |
||
53 | #include <poppler/splash/SplashGlyphBitmap.h> |
||
54 | |||
55 | //------------------------------------------------------------------------ |
||
56 | // LinkSubmitData |
||
57 | //------------------------------------------------------------------------ |
||
58 | |||
59 | class LinkSubmitForm: public LinkAction |
||
60 | { |
||
61 | public: |
||
62 | // Build a LinkImportData from an action dictionary. |
||
63 | LinkSubmitForm(Object *actionObj); |
||
64 | // Destructor. |
||
65 | virtual ~LinkSubmitForm(); |
||
22918 | jghali | 66 | |
22514 | jghali | 67 | // Was the LinkImportData created successfully? |
25123 | jghali | 68 | bool isOk() const override { return fileName != nullptr; } |
22514 | jghali | 69 | // Accessors. |
25123 | jghali | 70 | LinkActionKind getKind() const override { return actionUnknown; } |
22514 | jghali | 71 | GooString *getFileName() { return fileName; } |
72 | int getFlags() { return m_flags; } |
||
22918 | jghali | 73 | |
22514 | jghali | 74 | private: |
23478 | jghali | 75 | GooString *fileName {nullptr}; // file name |
76 | int m_flags {0}; |
||
22514 | jghali | 77 | }; |
78 | |||
79 | //------------------------------------------------------------------------ |
||
80 | // LinkImportData |
||
81 | //------------------------------------------------------------------------ |
||
82 | |||
83 | class LinkImportData: public LinkAction |
||
84 | { |
||
85 | public: |
||
86 | // Build a LinkImportData from an action dictionary. |
||
87 | LinkImportData(Object *actionObj); |
||
88 | // Destructor. |
||
89 | virtual ~LinkImportData(); |
||
22918 | jghali | 90 | |
22514 | jghali | 91 | // Was the LinkImportData created successfully? |
25123 | jghali | 92 | bool isOk() const override { return fileName != nullptr; } |
22514 | jghali | 93 | // Accessors. |
25123 | jghali | 94 | LinkActionKind getKind() const override { return actionUnknown; } |
22514 | jghali | 95 | GooString *getFileName() { return fileName; } |
22918 | jghali | 96 | |
22514 | jghali | 97 | private: |
23478 | jghali | 98 | GooString *fileName {nullptr}; // file name |
22514 | jghali | 99 | }; |
24181 | jghali | 100 | |
22514 | jghali | 101 | //------------------------------------------------------------------------ |
24181 | jghali | 102 | // SlaOutFontFileID |
22514 | jghali | 103 | //------------------------------------------------------------------------ |
104 | |||
24181 | jghali | 105 | class SlaOutFontFileID: public SplashFontFileID |
22514 | jghali | 106 | { |
107 | public: |
||
24181 | jghali | 108 | SlaOutFontFileID(const Ref *rA) { r = *rA; } |
109 | ~SlaOutFontFileID() {} |
||
22514 | jghali | 110 | |
25123 | jghali | 111 | bool matches(SplashFontFileID *id) override |
22514 | jghali | 112 | { |
24181 | jghali | 113 | return ((SlaOutFontFileID*) id)->r.num == r.num && ((SlaOutFontFileID *) id)->r.gen == r.gen; |
22514 | jghali | 114 | } |
115 | |||
116 | private: |
||
117 | Ref r; |
||
118 | }; |
||
119 | |||
120 | |||
121 | class AnoOutputDev : public OutputDev |
||
122 | { |
||
123 | public: |
||
124 | AnoOutputDev(ScribusDoc* doc, QStringList *importedColors); |
||
125 | virtual ~AnoOutputDev(); |
||
22916 | jghali | 126 | |
25123 | jghali | 127 | bool isOk() { return true; } |
128 | bool upsideDown() override { return true; } |
||
129 | bool useDrawChar() override { return false; } |
||
130 | bool interpretType3Chars() override { return false; } |
||
131 | bool useTilingPatternFill() override { return false; } |
||
132 | bool useShadedFills(int type) override { return false; } |
||
133 | bool useFillColorStop() override { return false; } |
||
134 | bool useDrawForm() override { return false; } |
||
22514 | jghali | 135 | |
22916 | jghali | 136 | void stroke(GfxState *state) override; |
137 | void eoFill(GfxState *state) override; |
||
138 | void fill(GfxState *state) override; |
||
25123 | jghali | 139 | void drawString(GfxState *state, const GooString *s) override; |
22916 | jghali | 140 | |
24374 | jghali | 141 | QString currColorText; |
142 | QString currColorFill; |
||
143 | QString currColorStroke; |
||
144 | double fontSize {12}; |
||
145 | GooString *fontName {nullptr}; |
||
146 | GooString *itemText {nullptr}; |
||
22918 | jghali | 147 | |
22514 | jghali | 148 | private: |
25123 | jghali | 149 | QString getColor(GfxColorSpace *color_space, const GfxColor *color, int *shade); |
22514 | jghali | 150 | ScribusDoc* m_doc; |
151 | QStringList *m_importedColors; |
||
152 | }; |
||
153 | |||
154 | |||
24374 | jghali | 155 | |
22514 | jghali | 156 | class SlaOutputDev : public OutputDev |
157 | { |
||
158 | public: |
||
159 | SlaOutputDev(ScribusDoc* doc, QList<PageItem*> *Elements, QStringList *importedColors, int flags); |
||
160 | virtual ~SlaOutputDev(); |
||
161 | |||
162 | LinkAction* SC_getAction(AnnotWidget *ano); |
||
23478 | jghali | 163 | std::unique_ptr<LinkAction> SC_getAdditionalAction(const char *key, AnnotWidget *ano); |
25123 | jghali | 164 | static bool annotations_callback(Annot *annota, void *user_data); |
22514 | jghali | 165 | bool handleTextAnnot(Annot* annota, double xCoor, double yCoor, double width, double height); |
166 | bool handleLinkAnnot(Annot* annota, double xCoor, double yCoor, double width, double height); |
||
167 | bool handleWidgetAnnot(Annot* annota, double xCoor, double yCoor, double width, double height); |
||
22609 | craig | 168 | void applyTextStyle(PageItem* ite, const QString& fontName, const QString& textColor, double fontSize); |
22514 | jghali | 169 | void handleActions(PageItem* ite, AnnotWidget *ano); |
170 | void startDoc(PDFDoc *doc, XRef *xrefA, Catalog *catA); |
||
171 | |||
25123 | jghali | 172 | bool isOk() { return true; } |
173 | bool upsideDown() override { return true; } |
||
174 | bool useDrawChar() override { return true; } |
||
175 | bool interpretType3Chars() override { return true; } |
||
176 | bool useTilingPatternFill() override { return true; } |
||
177 | bool useShadedFills(int type) override { return type <= 7; } |
||
178 | bool useFillColorStop() override { return true; } |
||
179 | bool useDrawForm() override { return false; } |
||
22916 | jghali | 180 | |
25123 | jghali | 181 | // virtual bool needClipToCropBox() { return true; } |
22916 | jghali | 182 | void startPage(int pageNum, GfxState *, XRef *) override; |
183 | void endPage() override; |
||
22917 | jghali | 184 | |
22514 | jghali | 185 | // graphics state |
22917 | jghali | 186 | void saveState(GfxState *state) override; |
187 | void restoreState(GfxState *state) override; |
||
22514 | jghali | 188 | |
189 | //----- path painting |
||
22916 | jghali | 190 | void stroke(GfxState *state) override; |
191 | void fill(GfxState *state) override; |
||
192 | void eoFill(GfxState *state) override; |
||
24537 | jghali | 193 | bool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep) override; |
25123 | jghali | 194 | bool functionShadedFill(GfxState * /*state*/, GfxFunctionShading * /*shading*/) override { qDebug() << "Function Shaded Fill"; return false; } |
195 | bool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) override; |
||
196 | bool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading) override { return (shading->getExtend0() == shading->getExtend1()); } |
||
197 | bool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) override; |
||
198 | bool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading) override { return (shading->getExtend0() == shading->getExtend1()); } |
||
199 | bool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) override; |
||
200 | bool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading) override; |
||
22916 | jghali | 201 | |
22514 | jghali | 202 | //----- path clipping |
22916 | jghali | 203 | void clip(GfxState *state) override; |
204 | void eoClip(GfxState *state) override; |
||
205 | void clipToStrokePath(GfxState * /*state*/) override { qDebug() << "Clip to StrokePath"; } |
||
25123 | jghali | 206 | virtual bool deviceHasTextClip(GfxState *state) { return false; } |
22514 | jghali | 207 | |
208 | // If current colorspace is pattern, |
||
209 | // does this device support text in pattern colorspace? |
||
25123 | jghali | 210 | virtual bool supportTextCSPattern(GfxState *state) |
22514 | jghali | 211 | { |
212 | return state->getFillColorSpace()->getMode() == csPattern; |
||
213 | } |
||
214 | |||
215 | // If current colorspace is pattern, |
||
216 | // need this device special handling for masks in pattern colorspace? |
||
25123 | jghali | 217 | virtual bool fillMaskCSPattern(GfxState * state) |
22514 | jghali | 218 | { |
219 | return state->getFillColorSpace()->getMode() == csPattern; |
||
220 | } |
||
221 | |||
222 | virtual void endMaskClip(GfxState *state) { qDebug() << "End Mask Clip"; } |
||
223 | |||
224 | //----- grouping operators |
||
25123 | jghali | 225 | void beginMarkedContent(const char *name, Dict *properties) override; |
226 | virtual void beginMarkedContent(const char *name, Object *dictRef); |
||
22916 | jghali | 227 | void endMarkedContent(GfxState *state) override; |
25123 | jghali | 228 | void markPoint(const char *name) override; |
229 | void markPoint(const char *name, Dict *properties) override; |
||
22916 | jghali | 230 | |
22514 | jghali | 231 | //----- image drawing |
25123 | jghali | 232 | void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) override; |
233 | void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) override; |
||
22916 | jghali | 234 | void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, |
22514 | jghali | 235 | int width, int height, |
236 | GfxImageColorMap *colorMap, |
||
25123 | jghali | 237 | bool interpolate, |
22514 | jghali | 238 | Stream *maskStr, |
239 | int maskWidth, int maskHeight, |
||
240 | GfxImageColorMap *maskColorMap, |
||
25123 | jghali | 241 | bool maskInterpolate) override; |
22514 | jghali | 242 | |
22916 | jghali | 243 | void drawMaskedImage(GfxState *state, Object *ref, Stream *str, |
22514 | jghali | 244 | int width, int height, |
245 | GfxImageColorMap *colorMap, |
||
25123 | jghali | 246 | bool interpolate, |
22514 | jghali | 247 | Stream *maskStr, |
248 | int maskWidth, int maskHeight, |
||
25123 | jghali | 249 | bool maskInvert, bool maskInterpolate) override; // { qDebug() << "Draw Masked Image"; } |
22514 | jghali | 250 | |
251 | //----- transparency groups and soft masks |
||
25123 | jghali | 252 | void beginTransparencyGroup(GfxState *state, const double *bbox, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) override; |
253 | void paintTransparencyGroup(GfxState *state, const double *bbox) override; |
||
22916 | jghali | 254 | void endTransparencyGroup(GfxState *state) override; |
25123 | jghali | 255 | void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) override; |
22916 | jghali | 256 | void clearSoftMask(GfxState * /*state*/) override; |
22514 | jghali | 257 | |
22916 | jghali | 258 | void updateFillColor(GfxState *state) override; |
259 | void updateStrokeColor(GfxState *state) override; |
||
24374 | jghali | 260 | void updateFont(GfxState* state) override; |
22916 | jghali | 261 | |
22514 | jghali | 262 | //----- text drawing |
22916 | jghali | 263 | void beginTextObject(GfxState *state) override; |
264 | void endTextObject(GfxState *state) override; |
||
25123 | jghali | 265 | void drawChar(GfxState *state, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/, double /*originX*/, double /*originY*/, CharCode /*code*/, int /*nBytes*/, const Unicode * /*u*/, int /*uLen*/) override; |
266 | bool beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/, CharCode /*code*/, const Unicode * /*u*/, int /*uLen*/) override; |
||
22916 | jghali | 267 | void endType3Char(GfxState * /*state*/) override; |
268 | void type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) override; |
||
269 | void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/, double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) override; |
||
270 | |||
22514 | jghali | 271 | //----- form XObjects |
22916 | jghali | 272 | void drawForm(Ref /*id*/) override { qDebug() << "Draw Form"; } |
273 | |||
22514 | jghali | 274 | //----- links |
22916 | jghali | 275 | void processLink(AnnotLink * /*link*/) override { qDebug() << "Draw Link"; } |
276 | |||
24605 | jghali | 277 | bool layersSetByOCG { false }; |
278 | double cropOffsetX { 0.0 }; |
||
279 | double cropOffsetY { 0.0 }; |
||
280 | int rotate { 0 }; |
||
22514 | jghali | 281 | |
24374 | jghali | 282 | protected: |
283 | void setItemFillAndStroke(GfxState* state, PageItem* textNode); |
||
284 | void applyMask(PageItem* ite); |
||
25123 | jghali | 285 | void pushGroup(const QString& maskName = "", bool forSoftMask = false, bool alpha = false, bool inverted = false); |
24374 | jghali | 286 | |
287 | ScribusDoc* m_doc; |
||
24605 | jghali | 288 | Qt::PenCapStyle m_lineEnd { Qt::FlatCap }; |
289 | Qt::PenJoinStyle m_lineJoin { Qt::MiterJoin }; |
||
24374 | jghali | 290 | QList<PageItem*>* m_Elements; |
291 | |||
25120 | jghali | 292 | class GraphicState |
293 | { |
||
294 | public: |
||
295 | QString fillColor { "Black" }; |
||
296 | int fillShade { 100 }; |
||
297 | QString strokeColor { "Black "}; |
||
298 | int strokeShade { 100 }; |
||
299 | |||
300 | // The currently visible area. If it is empty, everything is visible. |
||
301 | // QPainterPath has the drawback that it sometimes approximates Bezier curves |
||
302 | // by line segments for numerical stability. If available, a better class |
||
303 | // should be used. However, it is important that the used class knows which |
||
304 | // areas are covered and does not rely on external information about the fill |
||
305 | // rule to use. |
||
306 | QPainterPath clipPath; |
||
307 | }; |
||
308 | |||
309 | class GraphicStack |
||
310 | { |
||
311 | public: |
||
312 | GraphicStack() |
||
313 | { |
||
314 | m_stack.push(GraphicState()); |
||
315 | } |
||
316 | |||
317 | void clear() |
||
318 | { |
||
319 | m_stack.clear(); |
||
320 | m_stack.push(GraphicState()); |
||
321 | } |
||
322 | |||
323 | void save() |
||
324 | { |
||
325 | m_stack.push(m_stack.top()); |
||
326 | } |
||
327 | |||
328 | void restore() |
||
329 | { |
||
330 | if (m_stack.count() > 0) |
||
331 | m_stack.pop(); |
||
332 | if (m_stack.count() == 0) |
||
333 | m_stack.push(GraphicState()); |
||
334 | } |
||
335 | |||
336 | GraphicState& top() { return m_stack.top(); } |
||
337 | const GraphicState& top() const { return m_stack.top(); } |
||
338 | |||
339 | private: |
||
340 | QStack<GraphicState> m_stack; |
||
341 | }; |
||
342 | |||
24374 | jghali | 343 | struct groupEntry |
344 | { |
||
345 | QList<PageItem*> Items; |
||
25123 | jghali | 346 | bool forSoftMask { false }; |
347 | bool isolated { false }; |
||
348 | bool alpha { false }; |
||
24374 | jghali | 349 | QString maskName; |
350 | QPointF maskPos; |
||
24605 | jghali | 351 | bool inverted { false }; |
24374 | jghali | 352 | }; |
353 | |||
354 | QStack<groupEntry> m_groupStack; |
||
25120 | jghali | 355 | GraphicStack m_graphicStack; |
24374 | jghali | 356 | |
22514 | jghali | 357 | private: |
358 | void getPenState(GfxState *state); |
||
25123 | jghali | 359 | QString getColor(GfxColorSpace *color_space, const GfxColor *color, int *shade); |
22514 | jghali | 360 | QString getAnnotationColor(const AnnotColor *color); |
25123 | jghali | 361 | QString convertPath(const GfxPath *path); |
22514 | jghali | 362 | int getBlendMode(GfxState *state); |
25123 | jghali | 363 | QString UnicodeParsedString(const GooString *s1); |
23478 | jghali | 364 | QString UnicodeParsedString(const std::string& s1); |
22514 | jghali | 365 | bool checkClip(); |
23525 | jghali | 366 | |
23536 | jghali | 367 | // Intersect the current clip path with the new path in state where filled areas |
368 | // are interpreted according to fillRule. |
||
369 | void adjustClip(GfxState *state, Qt::FillRule fillRule); |
||
370 | |||
371 | // Take the current path of state and interpret it according to fillRule, |
||
372 | // intersect it with the clipping path and create a new pageitem for it. |
||
373 | void createFillItem(GfxState *state, Qt::FillRule fillRule); |
||
374 | |||
23525 | jghali | 375 | void createImageFrame(QImage& image, GfxState *state, int numColorComponents); |
376 | |||
25123 | jghali | 377 | bool m_pathIsClosed { false }; |
25122 | jghali | 378 | QVector<double> m_dashValues; |
379 | double m_dashOffset { 0.0 }; |
||
380 | QString m_coords; |
||
25120 | jghali | 381 | |
23588 | jghali | 382 | // Collect the paths of character glyphs for clipping of a whole text group. |
383 | QPainterPath m_clipTextPath; |
||
23536 | jghali | 384 | |
22514 | jghali | 385 | QString m_currentMask; |
23550 | jghali | 386 | QPointF m_currentMaskPosition; |
25122 | jghali | 387 | Selection* m_tmpSel { nullptr }; |
22514 | jghali | 388 | QStringList *m_importedColors; |
389 | QTransform m_ctm; |
||
390 | struct F3Entry |
||
391 | { |
||
392 | bool colored; |
||
393 | }; |
||
394 | QStack<F3Entry> m_F3Stack; |
||
395 | struct mContent |
||
396 | { |
||
397 | QString name; |
||
398 | QString ocgName; |
||
399 | }; |
||
400 | QStack<mContent> m_mcStack; |
||
25122 | jghali | 401 | int m_inPattern {0}; |
402 | int m_layerNum {1}; |
||
403 | int m_currentLayer { 0 }; |
||
404 | bool m_firstLayer {true}; |
||
405 | int m_importerFlags; |
||
406 | int m_updateGUICounter {0}; |
||
407 | XRef *m_xref {nullptr}; // xref table for current document |
||
408 | PDFDoc *m_pdfDoc {nullptr}; |
||
409 | Catalog *m_catalog {nullptr}; |
||
23377 | craig | 410 | SplashFontEngine *m_fontEngine {nullptr}; |
411 | SplashFont *m_font {nullptr}; |
||
24599 | jghali | 412 | #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 4, 0) |
413 | std::unique_ptr<FormPageWidgets> m_formWidgets; |
||
414 | #else |
||
23377 | craig | 415 | FormPageWidgets *m_formWidgets {nullptr}; |
24599 | jghali | 416 | #endif |
22514 | jghali | 417 | QHash<QString, QList<int> > m_radioMap; |
418 | QHash<int, PageItem*> m_radioButtons; |
||
24605 | jghali | 419 | int m_actPage { 1 }; |
22514 | jghali | 420 | }; |
421 | #endif |