From 261aba67c3547c02c441b7f3d03210d5476a86b3 Mon Sep 17 00:00:00 2001 From: Lu Wang Date: Wed, 18 Sep 2013 16:16:40 +0800 Subject: [PATCH] option ENABLE_SVG in cmake --- CMakeLists.txt | 44 +- src/BackgroundRenderer/BackgroundRenderer.h | 4 +- .../BackgroundRenderer_forward.h | 4 +- .../CairoBackgroundRenderer.cc | 4 +- .../CairoBackgroundRenderer.h | 2 +- .../CairoOutputDev/CairoFontEngine.cc | 45 +- .../CairoOutputDev/CairoFontEngine.h | 14 +- .../CairoOutputDev/CairoOutputDev.cc | 565 +-- .../CairoOutputDev/CairoOutputDev.h | 21 +- .../CairoOutputDev/CairoRescaleBox.cc | 175 +- .../CairoOutputDev/CairoRescaleBox.h | 59 +- src/CairoOutputDev/CairoFontEngine.cc | 829 ----- src/CairoOutputDev/CairoFontEngine.h | 132 - src/CairoOutputDev/CairoOutputDev.cc | 3190 ----------------- src/CairoOutputDev/CairoOutputDev.h | 507 --- src/CairoOutputDev/CairoRescaleBox.cc | 377 -- src/CairoOutputDev/CairoRescaleBox.h | 61 - src/pdf2htmlEX-config.h.in | 2 +- 18 files changed, 560 insertions(+), 5475 deletions(-) delete mode 100644 src/CairoOutputDev/CairoFontEngine.cc delete mode 100644 src/CairoOutputDev/CairoFontEngine.h delete mode 100644 src/CairoOutputDev/CairoOutputDev.cc delete mode 100644 src/CairoOutputDev/CairoOutputDev.h delete mode 100644 src/CairoOutputDev/CairoRescaleBox.cc delete mode 100644 src/CairoOutputDev/CairoRescaleBox.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 65e954e..78229bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build configuration (Debug, Release, project(pdf2htmlEX) cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) +option(ENABLE_SVG "Enable SVG backend" OFF) + include_directories(${CMAKE_SOURCE_DIR}/src) set(PDF2HTMLEX_VERSION "0.10") @@ -26,14 +28,27 @@ include_directories(${POPPLER_INCLUDE_DIRS}) link_directories(${POPPLER_LIBRARY_DIRS}) set(PDF2HTMLEX_LIBS ${PDF2HTMLEX_LIBS} ${POPPLER_LIBRARIES}) -# for SVG -set(HAVE_CAIRO 1) - -# for Cairo* files -pkg_check_modules(CAIRO REQUIRED cairo>=1.10.0) -include_directories(${CAIRO_INCLUDE_DIRS}) -link_directories(${CAIRO_LIBRARY_DIRS}) -set(PDF2HTMLEX_LIBS ${PDF2HTMLEX_LIBS} ${CAIRO_LIBRARIES}) +if(ENABLE_SVG) + pkg_check_modules(CAIRO REQUIRED cairo>=1.10.0) + message("Trying to locate cairo-svg...") + find_path(CAIRO_SVG_INCLUDE_PATH cairo-svg.h PATHS ${CAIRO_INCLUDE_DIRS} NO_DEFAULT_PATH) + if(CAIRO_SVG_INCLUDE_PATH) + include_directories(${CAIRO_INCLUDE_DIRS}) + link_directories(${CAIRO_LIBRARY_DIRS}) + set(PDF2HTMLEX_LIBS ${PDF2HTMLEX_LIBS} ${CAIRO_LIBRARIES}) + set(ENABLE_SVG 1) + set(PDF2HTMLEX_SRC ${PDF2HTMLEX_SRC} + src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.h + src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.cc + src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.h + src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.cc + src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.h + src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.cc + ) + else() + message(FATAL_ERROR "Error: no SVG support found in Cairo") + endif() +endif() find_package(Freetype REQUIRED) include_directories(${FREETYPE_INCLUDE_DIRS}) @@ -66,8 +81,7 @@ else() else() message(FATAL_ERROR "Error: cannot locate fontforge.h") endif() - find_path(FF_CONFIG_INCLUDE_PATH config.h PATHS - ${FONTFORGE_INCLUDE_DIRS} NO_DEFAULT_PATH) + find_path(FF_CONFIG_INCLUDE_PATH config.h PATHS ${FONTFORGE_INCLUDE_DIRS} NO_DEFAULT_PATH) if(FF_CONFIG_INCLUDE_PATH) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -include ${FF_CONFIG_INCLUDE_PATH}/config.h") message("Found config.h: ${FF_CONFIG_INCLUDE_PATH}/config.h") @@ -153,7 +167,7 @@ configure_file (${CMAKE_SOURCE_DIR}/share/base.css.in ${CMAKE_SOURCE_DIR}/share/ configure_file (${CMAKE_SOURCE_DIR}/share/fancy.css.in ${CMAKE_SOURCE_DIR}/share/fancy.css) configure_file (${CMAKE_SOURCE_DIR}/share/pdf2htmlEX.js.in ${CMAKE_SOURCE_DIR}/share/pdf2htmlEX.js) -add_executable(pdf2htmlEX +set(PDF2HTMLEX_SRC ${PDF2HTMLEX_SRC} src/Param.h src/pdf2htmlEX-config.h src/pdf2htmlEX.cc @@ -171,12 +185,6 @@ add_executable(pdf2htmlEX src/BackgroundRenderer/SplashBackgroundRenderer.cc src/BackgroundRenderer/CairoBackgroundRenderer.h src/BackgroundRenderer/CairoBackgroundRenderer.cc - src/CairoOutputDev/CairoFontEngine.h - src/CairoOutputDev/CairoFontEngine.cc - src/CairoOutputDev/CairoRescaleBox.h - src/CairoOutputDev/CairoRescaleBox.cc - src/CairoOutputDev/CairoOutputDev.h - src/CairoOutputDev/CairoOutputDev.cc src/util/const.h src/util/const.cc src/util/css_const.h @@ -211,6 +219,8 @@ add_executable(pdf2htmlEX src/TmpFiles.h src/TmpFiles.cc ) + +add_executable(pdf2htmlEX ${PDF2HTMLEX_SRC}) target_link_libraries(pdf2htmlEX ${PDF2HTMLEX_LIBS}) install (TARGETS pdf2htmlEX DESTINATION bin) diff --git a/src/BackgroundRenderer/BackgroundRenderer.h b/src/BackgroundRenderer/BackgroundRenderer.h index b3cd623..ab3d9aa 100644 --- a/src/BackgroundRenderer/BackgroundRenderer.h +++ b/src/BackgroundRenderer/BackgroundRenderer.h @@ -11,7 +11,7 @@ #include "pdf2htmlEX-config.h" -#if HAVE_CAIRO +#if ENABLE_SVG #include "CairoBackgroundRenderer.h" @@ -27,6 +27,6 @@ namespace pdf2htmlEX { typedef SplashBackgroundRenderer BackgroundRenderer; } -#endif // HAVE_CAIRO +#endif // ENABLE_SVG #endif //BACKGROUND_RENDERER_H__ diff --git a/src/BackgroundRenderer/BackgroundRenderer_forward.h b/src/BackgroundRenderer/BackgroundRenderer_forward.h index 4db0e81..15f1ccb 100644 --- a/src/BackgroundRenderer/BackgroundRenderer_forward.h +++ b/src/BackgroundRenderer/BackgroundRenderer_forward.h @@ -16,13 +16,13 @@ #include "pdf2htmlEX-config.h" namespace pdf2htmlEX { -#if HAVE_CAIRO +#if ENABLE_SVG class CairoBackgroundRenderer; typedef CairoBackgroundRenderer BackgroundRenderer; #else class SplashBackgroundRenderer; typedef SplashBackgroundRenderer BackgroundRenderer; -#endif // HAVE_CAIRO +#endif // ENABLE_SVG } diff --git a/src/BackgroundRenderer/CairoBackgroundRenderer.cc b/src/BackgroundRenderer/CairoBackgroundRenderer.cc index 7da06d3..4bfe5e2 100644 --- a/src/BackgroundRenderer/CairoBackgroundRenderer.cc +++ b/src/BackgroundRenderer/CairoBackgroundRenderer.cc @@ -12,7 +12,7 @@ #include "Base64Stream.h" -#if HAVE_CAIRO +#if ENABLE_SVG #include "CairoBackgroundRenderer.h" @@ -121,5 +121,5 @@ void CairoBackgroundRenderer::embed_image(int pageno) } // namespace pdf2htmlEX -#endif // HAVE_CAIRO +#endif // ENABLE_SVG diff --git a/src/BackgroundRenderer/CairoBackgroundRenderer.h b/src/BackgroundRenderer/CairoBackgroundRenderer.h index 2fa2d6a..e63c0b9 100644 --- a/src/BackgroundRenderer/CairoBackgroundRenderer.h +++ b/src/BackgroundRenderer/CairoBackgroundRenderer.h @@ -9,7 +9,7 @@ #ifndef CAIRO_BACKGROUND_RENDERER_H__ #define CAIRO_BACKGROUND_RENDERER_H__ -#include +#include #include #include diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.cc b/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.cc index c4493e8..229a86c 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.cc +++ b/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.cc @@ -17,7 +17,7 @@ // Copyright (C) 2005-2007 Jeff Muizelaar // Copyright (C) 2005, 2006 Kristian Høgsberg // Copyright (C) 2005 Martin Kretzschmar -// Copyright (C) 2005, 2009, 2012 Albert Astals Cid +// Copyright (C) 2005, 2009, 2012, 2013 Albert Astals Cid // Copyright (C) 2006, 2007, 2010, 2011 Carlos Garcia Campos // Copyright (C) 2007 Koji Otani // Copyright (C) 2008, 2009 Chris Wilson @@ -26,15 +26,15 @@ // Copyright (C) 2010 Suzuki Toshiya // Copyright (C) 2010 Jan Kümmel // Copyright (C) 2012 Hib Eris +// Copyright (C) 2013 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git // //======================================================================== -#include +#include -#include "config.h" #include #include "CairoFontEngine.h" #include "CairoOutputDev.h" @@ -58,6 +58,16 @@ #pragma implementation #endif +/* + * multi thread disabled by WangLu +#if MULTITHREADED +# define fontEngineLocker() MutexLocker locker(&mutex) +#else +*/ +# define fontEngineLocker() +/* +#endif +*/ //------------------------------------------------------------------------ // CairoFont @@ -558,6 +568,7 @@ typedef struct _type3_font_info { PDFDoc *doc; CairoFontEngine *fontEngine; GBool printing; + XRef *xref; } type3_font_info_t; static void @@ -645,7 +656,7 @@ _render_type3_glyph (cairo_scaled_font_t *scaled_font, box.y2 = mat[3]; gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL); output_dev->startDoc(info->doc, info->fontEngine); - output_dev->startPage (1, gfx->getState()); + output_dev->startPage (1, gfx->getState(), gfx->getXRef()); output_dev->setInType3Char(gTrue); gfx->display(charProcs->getVal(glyph, &charProc)); @@ -674,7 +685,7 @@ _render_type3_glyph (cairo_scaled_font_t *scaled_font, CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc, CairoFontEngine *fontEngine, - GBool printing) { + GBool printing, XRef *xref) { Object refObj, strObj; type3_font_info_t *info; cairo_font_face_t *font_face; @@ -697,6 +708,7 @@ CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc, info->doc = doc; info->fontEngine = fontEngine; info->printing = printing; + info->xref = xref; cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info); @@ -714,7 +726,7 @@ CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc, } } - return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing); + return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing, xref); } CairoType3Font::CairoType3Font(Ref ref, @@ -722,7 +734,7 @@ CairoType3Font::CairoType3Font(Ref ref, cairo_font_face_t *cairo_font_face, int *codeToGID, Guint codeToGIDLen, - GBool printing) : CairoFont(ref, + GBool printing, XRef *xref) : CairoFont(ref, cairo_font_face, codeToGID, codeToGIDLen, @@ -755,6 +767,12 @@ CairoFontEngine::CairoFontEngine(FT_Library libA) { FT_Library_Version(lib, &major, &minor, &patch); useCIDs = major > 2 || (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); +/* + * multi thread disabled by WangLu +#if MULTITHREADED + gInitMutex(&mutex); +#endif +*/ } CairoFontEngine::~CairoFontEngine() { @@ -764,15 +782,22 @@ CairoFontEngine::~CairoFontEngine() { if (fontCache[i]) delete fontCache[i]; } +/* + * multi thread disabled by WangLu +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +*/ } CairoFont * -CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing) { +CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref) { int i, j; Ref ref; CairoFont *font; GfxFontType fontType; + fontEngineLocker(); ref = *gfxFont->getID(); for (i = 0; i < cairoFontCacheSize; ++i) { @@ -788,9 +813,9 @@ CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing) { fontType = gfxFont->getType(); if (fontType == fontType3) - font = CairoType3Font::create (gfxFont, doc, this, printing); + font = CairoType3Font::create (gfxFont, doc, this, printing, xref); else - font = CairoFreeTypeFont::create (gfxFont, doc->getXRef(), lib, useCIDs); + font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs); //XXX: if font is null should we still insert it into the cache? if (fontCache[cairoFontCacheSize - 1]) { diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.h b/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.h index 6335348..432f107 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.h +++ b/src/BackgroundRenderer/CairoOutputDev/CairoFontEngine.h @@ -19,6 +19,7 @@ // Copyright (C) 2006, 2007 Jeff Muizelaar // Copyright (C) 2006, 2010 Carlos Garcia Campos // Copyright (C) 2008 Adrian Johnson +// Copyright (C) 2013 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -32,6 +33,7 @@ #pragma interface #endif +#include "poppler-config.h" #include "goo/gtypes.h" #include @@ -85,7 +87,7 @@ class CairoType3Font : public CairoFont { public: static CairoType3Font *create(GfxFont *gfxFont, PDFDoc *doc, CairoFontEngine *fontEngine, - GBool printing); + GBool printing, XRef *xref); virtual ~CairoType3Font(); virtual GBool matches(Ref &other, GBool printing); @@ -94,7 +96,7 @@ private: CairoType3Font(Ref ref, PDFDoc *doc, cairo_font_face_t *cairo_font_face, int *codeToGID, Guint codeToGIDLen, - GBool printing); + GBool printing, XRef *xref); PDFDoc *doc; }; @@ -113,12 +115,18 @@ public: CairoFontEngine(FT_Library libA); ~CairoFontEngine(); - CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing); + CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref); private: CairoFont *fontCache[cairoFontCacheSize]; FT_Library lib; GBool useCIDs; +/* + * multi thread disabled by WangLu +#if MULTITHREADED + GooMutex mutex; +#endif +*/ }; #endif diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.cc b/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.cc index d8f78d7..1eb001c 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.cc +++ b/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.cc @@ -18,22 +18,23 @@ // Copyright (C) 2005, 2006 Kristian Høgsberg // Copyright (C) 2005, 2009, 2012 Albert Astals Cid // Copyright (C) 2005 Nickolay V. Shmyrev -// Copyright (C) 2006-2011 Carlos Garcia Campos +// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos // Copyright (C) 2008 Carl Worth -// Copyright (C) 2008-2012 Adrian Johnson +// Copyright (C) 2008-2013 Adrian Johnson // Copyright (C) 2008 Michael Vrable // Copyright (C) 2008, 2009 Chris Wilson -// Copyright (C) 2008 Hib Eris +// Copyright (C) 2008, 2012 Hib Eris // Copyright (C) 2009, 2010 David Benjamin -// Copyright (C) 2011, 2012 Thomas Freitag +// Copyright (C) 2011-2013 Thomas Freitag // Copyright (C) 2012 Patrick Pfeifer +// Copyright (C) 2012 Jason Crain // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git // //======================================================================== -#include +#include #ifdef USE_GCC_PRAGMAS #pragma implementation @@ -43,9 +44,9 @@ #include #include #include +#include #include "goo/gfile.h" -#include "goo/gtypes_p.h" #include "GlobalParams.h" #include "Error.h" #include "Object.h" @@ -61,7 +62,7 @@ #include "CairoOutputDev.h" #include "CairoFontEngine.h" #include "CairoRescaleBox.h" -#include "UTF.h" +#include "UnicodeMap.h" //------------------------------------------------------------------------ // #define LOG_CAIRO @@ -143,6 +144,7 @@ CairoOutputDev::CairoOutputDev() { prescaleImages = gTrue; printing = gTrue; use_show_text_glyphs = gFalse; + inUncoloredPattern = gFalse; inType3Char = gFalse; t3_glyph_has_bbox = gFalse; @@ -162,6 +164,7 @@ CairoOutputDev::CairoOutputDev() { stroke_adjust = globalParams->getStrokeAdjust(); align_stroke_coords = gFalse; adjusted_stroke_width = gFalse; + xref = NULL; } CairoOutputDev::~CairoOutputDev() { @@ -234,18 +237,24 @@ void CairoOutputDev::startDoc(PDFDoc *docA, fontEngine = new CairoFontEngine(ft_lib); fontEngine_owner = gTrue; } + xref = doc->getXRef(); } -void CairoOutputDev::startPage(int pageNum, GfxState *state) { +void CairoOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) { /* set up some per page defaults */ cairo_pattern_destroy(fill_pattern); cairo_pattern_destroy(stroke_pattern); fill_pattern = cairo_pattern_create_rgb(0., 0., 0.); + fill_color.r = fill_color.g = fill_color.b = 0; stroke_pattern = cairo_pattern_reference(fill_pattern); + stroke_color.r = stroke_color.g = stroke_color.b = 0; if (text) text->startPage(state); + if (xrefA != NULL) { + xref = xrefA; + } } void CairoOutputDev::endPage() { @@ -453,6 +462,9 @@ void CairoOutputDev::updateLineWidth(GfxState *state) { void CairoOutputDev::updateFillColor(GfxState *state) { GfxRGB color = fill_color; + if (inUncoloredPattern) + return; + state->getFillRGB(&fill_color); if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID || color.r != fill_color.r || @@ -473,6 +485,9 @@ void CairoOutputDev::updateFillColor(GfxState *state) { void CairoOutputDev::updateStrokeColor(GfxState *state) { GfxRGB color = stroke_color; + if (inUncoloredPattern) + return; + state->getStrokeRGB(&stroke_color); if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID || color.r != stroke_color.r || @@ -493,6 +508,9 @@ void CairoOutputDev::updateStrokeColor(GfxState *state) { void CairoOutputDev::updateFillOpacity(GfxState *state) { double opacity = fill_opacity; + if (inUncoloredPattern) + return; + fill_opacity = state->getFillOpacity(); if (opacity != fill_opacity) { cairo_pattern_destroy(fill_pattern); @@ -508,6 +526,9 @@ void CairoOutputDev::updateFillOpacity(GfxState *state) { void CairoOutputDev::updateStrokeOpacity(GfxState *state) { double opacity = stroke_opacity; + if (inUncoloredPattern) + return; + stroke_opacity = state->getStrokeOpacity(); if (opacity != stroke_opacity) { cairo_pattern_destroy(stroke_pattern); @@ -521,6 +542,9 @@ void CairoOutputDev::updateStrokeOpacity(GfxState *state) { } void CairoOutputDev::updateFillColorStop(GfxState *state, double offset) { + if (inUncoloredPattern) + return; + state->getFillRGB(&fill_color); cairo_pattern_add_color_stop_rgba(fill_pattern, offset, @@ -599,7 +623,7 @@ void CairoOutputDev::updateFont(GfxState *state) { if (text) text->updateFont(state); - currentFont = fontEngine->getFont (state->getFont(), doc, printing); + currentFont = fontEngine->getFont (state->getFont(), doc, printing, xref); if (!currentFont) return; @@ -802,7 +826,7 @@ void CairoOutputDev::eoFill(GfxState *state) { } -GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat, Object *str, +GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str, double *pmat, int paintType, int /*tilingType*/, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, @@ -843,8 +867,12 @@ GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat box.x2 = bbox[2]; box.y2 = bbox[3]; strokePathTmp = strokePathClip; strokePathClip = NULL; - gfx = new Gfx(doc, this, resDict, &box, NULL); + gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef()); + if (paintType == 2) + inUncoloredPattern = gTrue; gfx->display(str); + if (paintType == 2) + inUncoloredPattern = gFalse; delete gfx; strokePathClip = strokePathTmp; @@ -945,10 +973,21 @@ GBool CairoOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTrian fill_pattern = cairo_pattern_create_mesh (); for (i = 0; i < shading->getNTriangles(); i++) { - shading->getTriangle(i, - &x0, &y0, &color[0], - &x1, &y1, &color[1], - &x2, &y2, &color[2]); + if (shading->isParameterized()) { + double color0, color1, color2; + shading->getTriangle(i, &x0, &y0, &color0, + &x1, &y1, &color1, + &x2, &y2, &color2); + shading->getParameterizedColor(color0, &color[0]); + shading->getParameterizedColor(color1, &color[1]); + shading->getParameterizedColor(color2, &color[2]); + } else { + shading->getTriangle(i, + &x0, &y0, &color[0], + &x1, &y1, &color[1], + &x2, &y2, &color[2]); + + } cairo_mesh_pattern_begin_patch (fill_pattern); @@ -1169,6 +1208,8 @@ void CairoOutputDev::drawChar(GfxState *state, double x, double y, glyphs[glyphCount].y = y - originY; glyphCount++; if (use_show_text_glyphs) { + GooString enc("UTF-8"); + UnicodeMap *utf8Map = globalParams->getUnicodeMap(&enc); if (utf8Max - utf8Count < uLen*6) { // utf8 encoded characters can be up to 6 bytes if (utf8Max > uLen*6) @@ -1179,7 +1220,7 @@ void CairoOutputDev::drawChar(GfxState *state, double x, double y, } clusters[clusterCount].num_bytes = 0; for (int i = 0; i < uLen; i++) { - int size = mapUTF8 (u[i], utf8 + utf8Count, utf8Max - utf8Count); + int size = utf8Map->mapUnicode(u[i], utf8 + utf8Count, utf8Max - utf8Count); utf8Count += size; clusters[clusterCount].num_bytes += size; } @@ -1536,7 +1577,7 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, LOG(printf ("set softMask\n")); - if (alpha == false) { + if (!alpha || transferFunc) { /* We need to mask according to the luminocity of the group. * So we paint the group to an image surface convert it to a luminocity map * and then use that as the mask. */ @@ -1579,13 +1620,15 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, cairo_t *maskCtx = cairo_create(source); //XXX: hopefully this uses the correct color space */ - GfxRGB backdropColorRGB; - groupColorSpaceStack->cs->getRGB(backdropColor, &backdropColorRGB); - /* paint the backdrop */ - cairo_set_source_rgb(maskCtx, - colToDbl(backdropColorRGB.r), - colToDbl(backdropColorRGB.g), - colToDbl(backdropColorRGB.b)); + if (!alpha) { + GfxRGB backdropColorRGB; + groupColorSpaceStack->cs->getRGB(backdropColor, &backdropColorRGB); + /* paint the backdrop */ + cairo_set_source_rgb(maskCtx, + colToDbl(backdropColorRGB.r), + colToDbl(backdropColorRGB.g), + colToDbl(backdropColorRGB.b)); + } cairo_paint(maskCtx); /* Copy source ctm to mask ctm and translate origin so that the @@ -1612,15 +1655,14 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, int stride = cairo_image_surface_get_stride(source)/4; for (int y=0; ytransform(&lum_in, &lum_out); - lum = (int)(lum_out * 255.0 + 0.5); - } - source_data[y*stride + x] = lum << 24; + int lum = alpha ? fill_opacity : luminocity(source_data[y*stride + x]); + if (transferFunc) { + double lum_in, lum_out; + lum_in = lum/256.0; + transferFunc->transform(&lum_in, &lum_out); + lum = (int)(lum_out * 255.0 + 0.5); + } + source_data[y*stride + x] = lum << 24; } } cairo_surface_mark_dirty (source); @@ -1640,7 +1682,7 @@ void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, } cairo_surface_destroy(source); - } else { + } else if (alpha) { mask = cairo_pattern_reference(group); cairo_get_matrix(cairo, &mask_matrix); } @@ -1694,27 +1736,26 @@ get_singular_values (const cairo_matrix_t *matrix, *minor = sqrt (f - delta); } -void CairoOutputDev::getScaledSize(int orig_width, - int orig_height, - int *scaledWidth, - int *scaledHeight) { - cairo_matrix_t matrix; - cairo_get_matrix(cairo, &matrix); - +void CairoOutputDev::getScaledSize(const cairo_matrix_t *matrix, + int orig_width, + int orig_height, + int *scaledWidth, + int *scaledHeight) +{ double xScale; double yScale; if (orig_width > orig_height) - get_singular_values (&matrix, &xScale, &yScale); + get_singular_values (matrix, &xScale, &yScale); else - get_singular_values (&matrix, &yScale, &xScale); + get_singular_values (matrix, &yScale, &xScale); int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */ if (xScale >= 0) { - tx = splashRound(matrix.x0 - 0.01); - tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1; + tx = splashRound(matrix->x0 - 0.01); + tx2 = splashRound(matrix->x0 + xScale + 0.01) - 1; } else { - tx = splashRound(matrix.x0 + 0.01) - 1; - tx2 = splashRound(matrix.x0 + xScale - 0.01); + tx = splashRound(matrix->x0 + 0.01) - 1; + tx2 = splashRound(matrix->x0 + xScale - 0.01); } *scaledWidth = abs(tx2 - tx) + 1; //scaledWidth = splashRound(fabs(xScale)); @@ -1725,11 +1766,11 @@ void CairoOutputDev::getScaledSize(int orig_width, *scaledWidth = 1; } if (yScale >= 0) { - ty = splashFloor(matrix.y0 + 0.01); - ty2 = splashCeil(matrix.y0 + yScale - 0.01); + ty = splashFloor(matrix->y0 + 0.01); + ty2 = splashCeil(matrix->y0 + yScale - 0.01); } else { - ty = splashCeil(matrix.y0 - 0.01); - ty2 = splashFloor(matrix.y0 + yScale + 0.01); + ty = splashCeil(matrix->y0 - 0.01); + ty2 = splashFloor(matrix->y0 + yScale + 0.01); } *scaledHeight = abs(ty2 - ty); if (*scaledHeight == 0) { @@ -1737,49 +1778,6 @@ void CairoOutputDev::getScaledSize(int orig_width, } } -cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) { - cairo_surface_t *dest_surface; - unsigned char *dest_buffer; - int dest_stride; - unsigned char *orig_buffer; - int orig_width, orig_height; - int orig_stride; - int scaledHeight; - int scaledWidth; - GBool res; - - if (printing) - return NULL; - - orig_width = cairo_image_surface_get_width (orig_surface); - orig_height = cairo_image_surface_get_height (orig_surface); - getScaledSize (orig_width, orig_height, &scaledWidth, &scaledHeight); - if (scaledWidth >= orig_width || scaledHeight >= orig_height) - return NULL; - - dest_surface = cairo_surface_create_similar (orig_surface, - cairo_surface_get_content (orig_surface), - scaledWidth, scaledHeight); - dest_buffer = cairo_image_surface_get_data (dest_surface); - dest_stride = cairo_image_surface_get_stride (dest_surface); - - orig_buffer = cairo_image_surface_get_data (orig_surface); - orig_stride = cairo_image_surface_get_stride (orig_surface); - - res = downscale_box_filter((uint32_t *)orig_buffer, - orig_stride, orig_width, orig_height, - scaledWidth, scaledHeight, 0, 0, - scaledWidth, scaledHeight, - (uint32_t *)dest_buffer, dest_stride); - if (!res) { - cairo_surface_destroy (dest_surface); - return NULL; - } - - return dest_surface; - -} - cairo_filter_t CairoOutputDev::getFilterForSurface(cairo_surface_t *image, GBool interpolate) @@ -1792,8 +1790,14 @@ CairoOutputDev::getFilterForSurface(cairo_surface_t *image, if (orig_width == 0 || orig_height == 0) return CAIRO_FILTER_NEAREST; + /* When printing, don't change the interpolation. */ + if (printing) + return CAIRO_FILTER_NEAREST; + + cairo_matrix_t matrix; + cairo_get_matrix(cairo, &matrix); int scaled_width, scaled_height; - getScaledSize (orig_width, orig_height, &scaled_width, &scaled_height); + getScaledSize (&matrix, orig_width, orig_height, &scaled_width, &scaled_height); /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */ if (scaled_width / orig_width >= 4 || scaled_height / orig_height >= 4) @@ -2611,9 +2615,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s cairo_set_source (cairo, pattern); if (!printing) { - cairo_rectangle (cairo, 0., 0., - MIN (width, maskWidth) / (double)width, - MIN (height, maskHeight) / (double)height); + cairo_rectangle (cairo, 0., 0., 1., 1.); cairo_clip (cairo); } cairo_mask (cairo, maskPattern); @@ -2622,9 +2624,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s cairo_pop_group_to_source (cairo); cairo_save (cairo); if (!printing) { - cairo_rectangle (cairo, 0., 0., - MIN (width, maskWidth) / (double)width, - MIN (height, maskHeight) / (double)height); + cairo_rectangle (cairo, 0., 0., 1., 1.); cairo_clip (cairo); } cairo_paint_with_alpha (cairo, fill_opacity); @@ -2635,9 +2635,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s cairo_save (cairo_shape); cairo_set_source (cairo_shape, pattern); if (!printing) { - cairo_rectangle (cairo_shape, 0., 0., - MIN (width, maskWidth) / (double)width, - MIN (height, maskHeight) / (double)height); + cairo_rectangle (cairo_shape, 0., 0., 1., 1.); cairo_fill (cairo_shape); } else { cairo_mask (cairo_shape, pattern); @@ -2725,63 +2723,119 @@ void CairoOutputDev::setMimeData(Stream *str, Object *ref, cairo_surface_t *imag } } -void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - int *maskColors, GBool inlineImg) -{ - cairo_surface_t *image; - cairo_pattern_t *pattern, *maskPattern; +class RescaleDrawImage : public CairoRescaleBox { +private: ImageStream *imgStr; - cairo_matrix_t matrix; - unsigned char *buffer; - int stride, i; - GfxRGB *lookup = NULL; - cairo_filter_t filter = CAIRO_FILTER_BILINEAR; + GfxRGB *lookup; + int width; + GfxImageColorMap *colorMap; + int *maskColors; + int current_row; - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); +public: + cairo_surface_t *getSourceImage(Stream *str, + int widthA, int height, + int scaledWidth, int scaledHeight, + GBool printing, + GfxImageColorMap *colorMapA, + int *maskColorsA) { + cairo_surface_t *image = NULL; + int i; + + lookup = NULL; + colorMap = colorMapA; + maskColors = maskColorsA; + width = widthA; + current_row = -1; + + /* TODO: Do we want to cache these? */ + imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); #if 0 - /* ICCBased color space doesn't do any color correction - * so check its underlying color space as well */ - int is_identity_transform; - is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || - (colorMap->getColorSpace()->getMode() == csICCBased && - ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB); + /* ICCBased color space doesn't do any color correction + * so check its underlying color space as well */ + int is_identity_transform; + is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || + (colorMap->getColorSpace()->getMode() == csICCBased && + ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB); #endif - image = cairo_image_surface_create (maskColors ? - CAIRO_FORMAT_ARGB32 : - CAIRO_FORMAT_RGB24, - width, height); - if (cairo_surface_status (image)) - goto cleanup; + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + if (colorMap->getNumPixelComps() == 1) { + int n; + Guchar pix; - // special case for one-channel (monochrome/gray/separation) images: - // build a lookup table here - if (colorMap->getNumPixelComps() == 1) { - int n; - Guchar pix; + n = 1 << colorMap->getBits(); + lookup = (GfxRGB *)gmallocn(n, sizeof(GfxRGB)); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; - n = 1 << colorMap->getBits(); - lookup = (GfxRGB *)gmallocn(n, sizeof(GfxRGB)); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - - colorMap->getRGB(&pix, &lookup[i]); + colorMap->getRGB(&pix, &lookup[i]); + } } + + if (printing || scaledWidth >= width || scaledHeight >= height) { + // No downscaling. Create cairo image containing the source image data. + unsigned char *buffer; + int stride; + + image = cairo_image_surface_create (maskColors ? + CAIRO_FORMAT_ARGB32 : + CAIRO_FORMAT_RGB24, + width, height); + if (cairo_surface_status (image)) + goto cleanup; + + buffer = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + for (int y = 0; y < height; y++) { + uint32_t *dest = (uint32_t *) (buffer + y * stride); + getRow(y, dest); + } + } else { + // // Downscaling required. Create cairo image the size of the + // rescaled image and // downscale the source image data into + // the cairo image. downScaleImage() will call getRow() to read + // source image data from the image stream. This avoids having + // to create an image the size of the source image which may + // exceed cairo's 32676x32767 image size limit (and also saves a + // lot of memory). + image = cairo_image_surface_create (maskColors ? + CAIRO_FORMAT_ARGB32 : + CAIRO_FORMAT_RGB24, + scaledWidth, scaledHeight); + if (cairo_surface_status (image)) + goto cleanup; + + downScaleImage(width, height, + scaledWidth, scaledHeight, + 0, 0, scaledWidth, scaledHeight, + image); + } + cairo_surface_mark_dirty (image); + + cleanup: + gfree(lookup); + imgStr->close(); + delete imgStr; + return image; } - buffer = cairo_image_surface_get_data (image); - stride = cairo_image_surface_get_stride (image); - for (int y = 0; y < height; y++) { - uint32_t *dest = (uint32_t *) (buffer + y * stride); - Guchar *pix = imgStr->getLine(); + void getRow(int row_num, uint32_t *row_data) { + int i; + Guchar *pix; + + if (row_num <= current_row) + return; + + while (current_row < row_num) { + pix = imgStr->getLine(); + current_row++; + } if (lookup) { Guchar *p = pix; @@ -2789,54 +2843,64 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, for (i = 0; i < width; i++) { rgb = lookup[*p]; - dest[i] = - ((int) colToByte(rgb.r) << 16) | - ((int) colToByte(rgb.g) << 8) | - ((int) colToByte(rgb.b) << 0); - p++; + row_data[i] = + ((int) colToByte(rgb.r) << 16) | + ((int) colToByte(rgb.g) << 8) | + ((int) colToByte(rgb.b) << 0); + p++; } } else { - colorMap->getRGBLine (pix, dest, width); + colorMap->getRGBLine (pix, row_data, width); } if (maskColors) { for (int x = 0; x < width; x++) { - bool is_opaque = false; - for (int i = 0; i < colorMap->getNumPixelComps(); ++i) { - if (pix[i] < maskColors[2*i] || - pix[i] > maskColors[2*i+1]) { - is_opaque = true; - break; - } - } - if (is_opaque) - *dest |= 0xff000000; - else - *dest = 0; - dest++; - pix += colorMap->getNumPixelComps(); + bool is_opaque = false; + for (int i = 0; i < colorMap->getNumPixelComps(); ++i) { + if (pix[i] < maskColors[2*i] || + pix[i] > maskColors[2*i+1]) { + is_opaque = true; + break; + } + } + if (is_opaque) + *row_data |= 0xff000000; + else + *row_data = 0; + row_data++; + pix += colorMap->getNumPixelComps(); } } } - gfree(lookup); - LOG (printf ("drawImage %dx%d\n", width, height)); +}; - cairo_surface_t *scaled_surface; +void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int widthA, int heightA, + GfxImageColorMap *colorMap, + GBool interpolate, + int *maskColors, GBool inlineImg) +{ + cairo_surface_t *image; + cairo_pattern_t *pattern, *maskPattern; + cairo_matrix_t matrix; + int width, height; + int scaledWidth, scaledHeight; + cairo_filter_t filter = CAIRO_FILTER_BILINEAR; + RescaleDrawImage rescale; - scaled_surface = downscaleSurface (image); - if (scaled_surface) { - if (cairo_surface_status (scaled_surface)) - goto cleanup; - cairo_surface_destroy (image); - image = scaled_surface; - width = cairo_image_surface_get_width (image); - height = cairo_image_surface_get_height (image); - } else { + LOG (printf ("drawImage %dx%d\n", widthA, heightA)); + + cairo_get_matrix(cairo, &matrix); + getScaledSize (&matrix, widthA, heightA, &scaledWidth, &scaledHeight); + image = rescale.getSourceImage(str, widthA, heightA, scaledWidth, scaledHeight, printing, colorMap, maskColors); + if (!image) + return; + + width = cairo_image_surface_get_width (image); + height = cairo_image_surface_get_height (image); + if (width == widthA && height == heightA) filter = getFilterForSurface (image, interpolate); - } - - cairo_surface_mark_dirty (image); if (!inlineImg) /* don't read stream twice if it is an inline image */ setMimeData(str, ref, image); @@ -2844,7 +2908,7 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, pattern = cairo_pattern_create_for_surface (image); cairo_surface_destroy (image); if (cairo_pattern_status (pattern)) - goto cleanup; + return; cairo_pattern_set_filter (pattern, filter); @@ -2856,7 +2920,7 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, cairo_pattern_set_matrix (pattern, &matrix); if (cairo_pattern_status (pattern)) { cairo_pattern_destroy (pattern); - goto cleanup; + return; } if (!mask && fill_opacity != 1.0) { @@ -2899,10 +2963,6 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, } cairo_pattern_destroy (pattern); - -cleanup: - imgStr->close(); - delete imgStr; } @@ -2935,7 +2995,35 @@ void CairoImageOutputDev::saveImage(CairoImage *image) images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *)); } images[numImages++] = image; -} +} + +void CairoImageOutputDev::getBBox(GfxState *state, int width, int height, + double *x1, double *y1, double *x2, double *y2) +{ + double *ctm = state->getCTM(); + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, + ctm[0], ctm[1], + -ctm[2], -ctm[3], + ctm[2] + ctm[4], ctm[3] + ctm[5]); + + int scaledWidth, scaledHeight; + getScaledSize (&matrix, width, height, &scaledWidth, &scaledHeight); + + if (matrix.xx >= 0) { + *x1 = matrix.x0; + } else { + *x1 = matrix.x0 - scaledWidth; + } + *x2 = *x1 + scaledWidth; + + if (matrix.yy >= 0) { + *y1 = matrix.y0; + } else { + *y1 = matrix.y0 - scaledHeight; + } + *y2 = *y1 + scaledHeight; +} void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, @@ -2944,22 +3032,9 @@ void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *st cairo_t *cr; cairo_surface_t *surface; double x1, y1, x2, y2; - double *ctm; - double mat[6]; CairoImage *image; - ctm = state->getCTM(); - - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - x1 = mat[4]; - y1 = mat[5]; - x2 = x1 + width; - y2 = y1 + height; + getBBox(state, width, height, &x1, &y1, &x2, &y2); image = new CairoImage (x1, y1, x2, y2); saveImage (image); @@ -2980,6 +3055,39 @@ void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *st } } +void CairoImageOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg, double *baseMatrix) +{ + cairo_t *cr; + cairo_surface_t *surface; + double x1, y1, x2, y2; + CairoImage *image; + + getBBox(state, width, height, &x1, &y1, &x2, &y2); + + image = new CairoImage (x1, y1, x2, y2); + saveImage (image); + + if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + setCairo (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, width, -height); + + CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, inlineImg, gFalse); + if (state->getFillColorSpace()->getMode() == csPattern) { + cairo_mask (cairo, mask); + } + image->setImage (surface); + + setCairo (NULL); + cairo_surface_destroy (surface); + cairo_destroy (cr); + } +} + void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, int *maskColors, GBool inlineImg) @@ -2987,22 +3095,9 @@ void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, cairo_t *cr; cairo_surface_t *surface; double x1, y1, x2, y2; - double *ctm; - double mat[6]; CairoImage *image; - ctm = state->getCTM(); - - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - x1 = mat[4]; - y1 = mat[5]; - x2 = x1 + width; - y2 = y1 + height; + getBBox(state, width, height, &x1, &y1, &x2, &y2); image = new CairoImage (x1, y1, x2, y2); saveImage (image); @@ -3035,22 +3130,9 @@ void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stre cairo_t *cr; cairo_surface_t *surface; double x1, y1, x2, y2; - double *ctm; - double mat[6]; CairoImage *image; - ctm = state->getCTM(); - - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - x1 = mat[4]; - y1 = mat[5]; - x2 = x1 + width; - y2 = y1 + height; + getBBox(state, width, height, &x1, &y1, &x2, &y2); image = new CairoImage (x1, y1, x2, y2); saveImage (image); @@ -3083,22 +3165,9 @@ void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream * cairo_t *cr; cairo_surface_t *surface; double x1, y1, x2, y2; - double *ctm; - double mat[6]; CairoImage *image; - ctm = state->getCTM(); - - mat[0] = ctm[0]; - mat[1] = ctm[1]; - mat[2] = -ctm[2]; - mat[3] = -ctm[3]; - mat[4] = ctm[2] + ctm[4]; - mat[5] = ctm[3] + ctm[5]; - x1 = mat[4]; - y1 = mat[5]; - x2 = x1 + width; - y2 = y1 + height; + getBBox(state, width, height, &x1, &y1, &x2, &y2); image = new CairoImage (x1, y1, x2, y2); saveImage (image); diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.h b/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.h index df76975..c9ae33d 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.h +++ b/src/BackgroundRenderer/CairoOutputDev/CairoOutputDev.h @@ -17,10 +17,10 @@ // Copyright (C) 2005-2008 Jeff Muizelaar // Copyright (C) 2005, 2006 Kristian Høgsberg // Copyright (C) 2005 Nickolay V. Shmyrev -// Copyright (C) 2006-2011 Carlos Garcia Campos -// Copyright (C) 2008, 2009, 2011, 2012 Adrian Johnson +// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos +// Copyright (C) 2008, 2009, 2011-2013 Adrian Johnson // Copyright (C) 2008 Michael Vrable -// Copyright (C) 2010-2012 Thomas Freitag +// Copyright (C) 2010-2013 Thomas Freitag // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -124,7 +124,7 @@ public: //----- initialization and control // Start a page. - virtual void startPage(int pageNum, GfxState *state); + virtual void startPage(int pageNum, GfxState *state, XRef *xref); // End a page. virtual void endPage(); @@ -192,7 +192,6 @@ public: CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); virtual void beginTextObject(GfxState *state); - virtual GBool deviceHasTextClip(GfxState *state) { return textClipPath; } virtual void endTextObject(GfxState *state); //----- image drawing @@ -267,7 +266,8 @@ public: protected: void doPath(cairo_t *cairo, GfxState *state, GfxPath *path); cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface); - void getScaledSize(int orig_width, int orig_height, + void getScaledSize(const cairo_matrix_t *matrix, + int orig_width, int orig_height, int *scaledWidth, int *scaledHeight); cairo_filter_t getFilterForSurface(cairo_surface_t *image, GBool interpolate); @@ -284,6 +284,7 @@ protected: GBool adjusted_stroke_width; GBool align_stroke_coords; CairoFont *currentFont; + XRef *xref; struct StrokePathClip { GfxPath *path; @@ -319,6 +320,7 @@ protected: int utf8Count; int utf8Max; cairo_path_t *textClipPath; + GBool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2) GBool inType3Char; // inside a Type 3 CharProc double t3_glyph_wx, t3_glyph_wy; GBool t3_glyph_has_bbox; @@ -465,6 +467,11 @@ public: Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GBool maskInterpolate); + virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg, double *baseMatrix); + virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {} + //----- transparency groups and soft masks virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/, @@ -487,6 +494,8 @@ public: private: void saveImage(CairoImage *image); + void getBBox(GfxState *state, int width, int height, + double *x1, double *y1, double *x2, double *y2); CairoImage **images; int numImages; diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.cc b/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.cc index 68a0c4c..3d19689 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.cc +++ b/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.cc @@ -31,6 +31,7 @@ // under GPL version 2 or later // // Copyright (C) 2012 Hib Eris +// Copyright (C) 2012 Adrian Johnson // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git @@ -50,13 +51,13 @@ #include #include #include "goo/gmem.h" -#include "goo/gtypes_p.h" #include "CairoRescaleBox.h" /* we work in fixed point where 1. == 1 << 24 */ #define FIXED_SHIFT 24 + static void downsample_row_box_filter ( int start, int width, uint32_t *src, uint32_t *dest, @@ -261,106 +262,116 @@ static int compute_coverage (int coverage[], int src_length, int dest_length) return ratio; } -GBool downscale_box_filter(uint32_t *orig, int orig_stride, unsigned orig_width, unsigned orig_height, - signed scaled_width, signed scaled_height, - uint16_t start_column, uint16_t start_row, - uint16_t width, uint16_t height, - uint32_t *dest, int dst_stride) -{ - int pixel_coverage_x, pixel_coverage_y; - int dest_y; - int src_y = 0; - uint32_t *scanline = orig; - int *x_coverage = NULL; - int *y_coverage = NULL; - uint32_t *temp_buf = NULL; - GBool retval = gFalse; - x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int)); - y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int)); +GBool CairoRescaleBox::downScaleImage(unsigned orig_width, unsigned orig_height, + signed scaled_width, signed scaled_height, + unsigned short int start_column, unsigned short int start_row, + unsigned short int width, unsigned short int height, + cairo_surface_t *dest_surface) { + int pixel_coverage_x, pixel_coverage_y; + int dest_y; + int src_y = 0; + uint32_t *scanline; + int *x_coverage = NULL; + int *y_coverage = NULL; + uint32_t *temp_buf = NULL; + GBool retval = gFalse; + unsigned int *dest; + int dst_stride; - /* we need to allocate enough room for ceil(src_height/dest_height)+1 - Example: - src_height = 140 - dest_height = 50 - src_height/dest_height = 2.8 + dest = (unsigned int *)cairo_image_surface_get_data (dest_surface); + dst_stride = cairo_image_surface_get_stride (dest_surface); - |-------------| 2.8 pixels - |----|----|----|----| 4 pixels - need to sample 3 pixels + scanline = (uint32_t*)gmallocn3 (orig_width, 1, sizeof(int)); - |-------------| 2.8 pixels - |----|----|----|----| 4 pixels - need to sample 4 pixels - */ + x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int)); + y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int)); - temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t)); + /* we need to allocate enough room for ceil(src_height/dest_height)+1 + Example: + src_height = 140 + dest_height = 50 + src_height/dest_height = 2.8 - if (!x_coverage || !y_coverage || !scanline || !temp_buf) - goto cleanup; + |-------------| 2.8 pixels + |----|----|----|----| 4 pixels + need to sample 3 pixels - pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width); - pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height); + |-------------| 2.8 pixels + |----|----|----|----| 4 pixels + need to sample 4 pixels + */ - assert (width + start_column <= scaled_width); + temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t)); - /* skip the rows at the beginning */ - for (dest_y = 0; dest_y < start_row; dest_y++) + if (!x_coverage || !y_coverage || !scanline || !temp_buf) + goto cleanup; + + pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width); + pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height); + + assert (width + start_column <= scaled_width); + + + + /* skip the rows at the beginning */ + for (dest_y = 0; dest_y < start_row; dest_y++) + { + int box = 1 << FIXED_SHIFT; + int start_coverage_y = y_coverage[dest_y]; + box -= start_coverage_y; + src_y++; + while (box >= pixel_coverage_y) { - int box = 1 << FIXED_SHIFT; - int start_coverage_y = y_coverage[dest_y]; - box -= start_coverage_y; - src_y++; - while (box >= pixel_coverage_y) - { - box -= pixel_coverage_y; - src_y++; - } + box -= pixel_coverage_y; + src_y++; + } + } + + for (; dest_y < start_row + height; dest_y++) + { + int columns = 0; + int box = 1 << FIXED_SHIFT; + int start_coverage_y = y_coverage[dest_y]; + + getRow(src_y, scanline); + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); + columns++; + src_y++; + box -= start_coverage_y; + + while (box >= pixel_coverage_y) + { + getRow(src_y, scanline); + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); + columns++; + src_y++; + box -= pixel_coverage_y; } - for (; dest_y < start_row + height; dest_y++) + /* downsample any leftovers */ + if (box > 0) { - int columns = 0; - int box = 1 << FIXED_SHIFT; - int start_coverage_y = y_coverage[dest_y]; + getRow(src_y, scanline); + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); + columns++; + } - scanline = orig + src_y * orig_stride / 4; - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - src_y++; - box -= start_coverage_y; - - while (box >= pixel_coverage_y) - { - scanline = orig + src_y * orig_stride / 4; - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - src_y++; - box -= pixel_coverage_y; - } - - /* downsample any leftovers */ - if (box > 0) - { - scanline = orig + src_y * orig_stride / 4; - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - } - - /* now scale the rows we just downsampled in the y direction */ - downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest); - dest += dst_stride / 4; + /* now scale the rows we just downsampled in the y direction */ + downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest); + dest += dst_stride / 4; // assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width); - } + } // assert (src_y<=orig_height); - retval = gTrue; + retval = gTrue; cleanup: - free (x_coverage); - free (y_coverage); - free (temp_buf); + free (x_coverage); + free (y_coverage); + free (temp_buf); + free (scanline); - return retval; + return retval; } diff --git a/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.h b/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.h index 5349c87..072e8a9 100644 --- a/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.h +++ b/src/BackgroundRenderer/CairoOutputDev/CairoRescaleBox.h @@ -1,12 +1,61 @@ +/* + * Copyright © 2009 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Mozilla Corporation not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Mozilla Corporation makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT + * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Author: Jeff Muizelaar, Mozilla Corp. + */ + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2012 Adrian Johnson +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + #ifndef CAIRO_RESCALE_BOX_H #define CAIRO_RESCALE_BOX_H #include "goo/gtypes.h" +#include -GBool downscale_box_filter(unsigned int *orig, int orig_stride, unsigned orig_width, unsigned orig_height, - signed scaled_width, signed scaled_height, - unsigned short int start_column, unsigned short int start_row, - unsigned short int width, unsigned short int height, - unsigned int *dest, int dst_stride); +class CairoRescaleBox { +public: + + CairoRescaleBox() {}; + virtual ~CairoRescaleBox() {}; + + virtual GBool downScaleImage(unsigned orig_width, unsigned orig_height, + signed scaled_width, signed scaled_height, + unsigned short int start_column, unsigned short int start_row, + unsigned short int width, unsigned short int height, + cairo_surface_t *dest_surface); + + virtual void getRow(int row_num, uint32_t *row_data) = 0; + +}; #endif /* CAIRO_RESCALE_BOX_H */ diff --git a/src/CairoOutputDev/CairoFontEngine.cc b/src/CairoOutputDev/CairoFontEngine.cc deleted file mode 100644 index 229a86c..0000000 --- a/src/CairoOutputDev/CairoFontEngine.cc +++ /dev/null @@ -1,829 +0,0 @@ -//======================================================================== -// -// CairoFontEngine.cc -// -// Copyright 2003 Glyph & Cog, LLC -// Copyright 2004 Red Hat, Inc -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005-2007 Jeff Muizelaar -// Copyright (C) 2005, 2006 Kristian Høgsberg -// Copyright (C) 2005 Martin Kretzschmar -// Copyright (C) 2005, 2009, 2012, 2013 Albert Astals Cid -// Copyright (C) 2006, 2007, 2010, 2011 Carlos Garcia Campos -// Copyright (C) 2007 Koji Otani -// Copyright (C) 2008, 2009 Chris Wilson -// Copyright (C) 2008, 2012 Adrian Johnson -// Copyright (C) 2009 Darren Kenny -// Copyright (C) 2010 Suzuki Toshiya -// Copyright (C) 2010 Jan Kümmel -// Copyright (C) 2012 Hib Eris -// Copyright (C) 2013 Thomas Freitag -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include - -#include -#include "CairoFontEngine.h" -#include "CairoOutputDev.h" -#include "GlobalParams.h" -#include -#include -#include "goo/gfile.h" -#include "Error.h" -#include "XRef.h" -#include "Gfx.h" -#include "Page.h" - -#if HAVE_FCNTL_H && HAVE_SYS_MMAN_H && HAVE_SYS_STAT_H -#include -#include -#include -#define CAN_CHECK_OPEN_FACES 1 -#endif - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -/* - * multi thread disabled by WangLu -#if MULTITHREADED -# define fontEngineLocker() MutexLocker locker(&mutex) -#else -*/ -# define fontEngineLocker() -/* -#endif -*/ - -//------------------------------------------------------------------------ -// CairoFont -//------------------------------------------------------------------------ - -CairoFont::CairoFont(Ref ref, - cairo_font_face_t *cairo_font_face, - int *codeToGID, - Guint codeToGIDLen, - GBool substitute, - GBool printing) : ref(ref), - cairo_font_face(cairo_font_face), - codeToGID(codeToGID), - codeToGIDLen(codeToGIDLen), - substitute(substitute), - printing(printing) { } - -CairoFont::~CairoFont() { - cairo_font_face_destroy (cairo_font_face); - gfree(codeToGID); -} - -GBool -CairoFont::matches(Ref &other, GBool printingA) { - return (other.num == ref.num && other.gen == ref.gen); -} - -cairo_font_face_t * -CairoFont::getFontFace(void) { - return cairo_font_face; -} - -unsigned long -CairoFont::getGlyph(CharCode code, - Unicode *u, int uLen) { - FT_UInt gid; - - if (codeToGID && code < codeToGIDLen) { - gid = (FT_UInt)codeToGID[code]; - } else { - gid = (FT_UInt)code; - } - return gid; -} - -double -CairoFont::getSubstitutionCorrection(GfxFont *gfxFont) -{ - double w1, w2; - CharCode code; - char *name; - - // for substituted fonts: adjust the font matrix -- compare the - // width of 'm' in the original font and the substituted font - if (isSubstitute() && !gfxFont->isCIDFont()) { - for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; - } - } - if (code < 256) { - w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); - { - cairo_matrix_t m; - cairo_matrix_init_identity(&m); - cairo_font_options_t *options = cairo_font_options_create(); - cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); - cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF); - cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options); - - cairo_text_extents_t extents; - cairo_scaled_font_text_extents(scaled_font, "m", &extents); - - cairo_scaled_font_destroy(scaled_font); - cairo_font_options_destroy(options); - w2 = extents.x_advance; - } - if (!gfxFont->isSymbolic()) { - // if real font is substantially narrower than substituted - // font, reduce the font size accordingly - if (w1 > 0.01 && w1 < 0.9 * w2) { - w1 /= w2; - return w1; - } - } - } - } - return 1.0; -} - -//------------------------------------------------------------------------ -// CairoFreeTypeFont -//------------------------------------------------------------------------ - -static cairo_user_data_key_t _ft_cairo_key; - -static void -_ft_done_face_uncached (void *closure) -{ - FT_Face face = (FT_Face) closure; - FT_Done_Face (face); -} - -static GBool -_ft_new_face_uncached (FT_Library lib, - const char *filename, - char *font_data, - int font_data_len, - FT_Face *face_out, - cairo_font_face_t **font_face_out) -{ - FT_Face face; - cairo_font_face_t *font_face; - - if (font_data == NULL) { - if (FT_New_Face (lib, filename, 0, &face)) - return gFalse; - } else { - if (FT_New_Memory_Face (lib, (unsigned char *)font_data, font_data_len, 0, &face)) - return gFalse; - } - - font_face = cairo_ft_font_face_create_for_ft_face (face, - FT_LOAD_NO_HINTING | - FT_LOAD_NO_BITMAP); - if (cairo_font_face_set_user_data (font_face, - &_ft_cairo_key, - face, - _ft_done_face_uncached)) - { - _ft_done_face_uncached (face); - cairo_font_face_destroy (font_face); - return gFalse; - } - - *face_out = face; - *font_face_out = font_face; - return gTrue; -} - -#if CAN_CHECK_OPEN_FACES -static struct _ft_face_data { - struct _ft_face_data *prev, *next, **head; - - int fd; - unsigned long hash; - size_t size; - unsigned char *bytes; - - FT_Library lib; - FT_Face face; - cairo_font_face_t *font_face; -} *_ft_open_faces; - -static unsigned long -_djb_hash (const unsigned char *bytes, size_t len) -{ - unsigned long hash = 5381; - while (len--) { - unsigned char c = *bytes++; - hash *= 33; - hash ^= c; - } - return hash; -} - -static GBool -_ft_face_data_equal (struct _ft_face_data *a, struct _ft_face_data *b) -{ - if (a->lib != b->lib) - return gFalse; - if (a->size != b->size) - return gFalse; - if (a->hash != b->hash) - return gFalse; - - return memcmp (a->bytes, b->bytes, a->size) == 0; -} - -static void -_ft_done_face (void *closure) -{ - struct _ft_face_data *data = (struct _ft_face_data *) closure; - - if (data->next) - data->next->prev = data->prev; - if (data->prev) - data->prev->next = data->next; - else - _ft_open_faces = data->next; - -#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4) - munmap ((char*)data->bytes, data->size); -#else - munmap (data->bytes, data->size); -#endif - close (data->fd); - - FT_Done_Face (data->face); - gfree (data); -} - -static GBool -_ft_new_face (FT_Library lib, - const char *filename, - char *font_data, - int font_data_len, - FT_Face *face_out, - cairo_font_face_t **font_face_out) -{ - struct _ft_face_data *l; - struct stat st; - struct _ft_face_data tmpl; - - tmpl.fd = -1; - - if (font_data == NULL) { - /* if we fail to mmap the file, just pass it to FreeType instead */ - tmpl.fd = open (filename, O_RDONLY); - if (tmpl.fd == -1) - return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out); - - if (fstat (tmpl.fd, &st) == -1) { - close (tmpl.fd); - return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out); - } - - tmpl.bytes = (unsigned char *) mmap (NULL, st.st_size, - PROT_READ, MAP_PRIVATE, - tmpl.fd, 0); - if (tmpl.bytes == MAP_FAILED) { - close (tmpl.fd); - return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out); - } - tmpl.size = st.st_size; - } else { - tmpl.bytes = (unsigned char*) font_data; - tmpl.size = font_data_len; - } - - /* check to see if this is a duplicate of any of the currently open fonts */ - tmpl.lib = lib; - tmpl.hash = _djb_hash (tmpl.bytes, tmpl.size); - - for (l = _ft_open_faces; l; l = l->next) { - if (_ft_face_data_equal (l, &tmpl)) { - if (tmpl.fd != -1) { -#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4) - munmap ((char*)tmpl.bytes, tmpl.size); -#else - munmap (tmpl.bytes, tmpl.size); -#endif - close (tmpl.fd); - } - *face_out = l->face; - *font_face_out = cairo_font_face_reference (l->font_face); - return gTrue; - } - } - - /* not a dup, open and insert into list */ - if (FT_New_Memory_Face (lib, - (FT_Byte *) tmpl.bytes, tmpl.size, - 0, &tmpl.face)) - { - if (tmpl.fd != -1) { -#if defined(__SUNPRO_CC) && defined(__sun) && defined(__SVR4) - munmap ((char*)tmpl.bytes, tmpl.size); -#else - munmap (tmpl.bytes, tmpl.size); -#endif - - close (tmpl.fd); - } - return gFalse; - } - - l = (struct _ft_face_data *) gmallocn (1, sizeof (struct _ft_face_data)); - *l = tmpl; - l->prev = NULL; - l->next = _ft_open_faces; - if (_ft_open_faces) - _ft_open_faces->prev = l; - _ft_open_faces = l; - - l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face, - FT_LOAD_NO_HINTING | - FT_LOAD_NO_BITMAP); - if (cairo_font_face_set_user_data (l->font_face, - &_ft_cairo_key, - l, - _ft_done_face)) - { - cairo_font_face_destroy (l->font_face); - _ft_done_face (l); - return gFalse; - } - - *face_out = l->face; - *font_face_out = l->font_face; - return gTrue; -} -#else -#define _ft_new_face _ft_new_face_uncached -#endif - -CairoFreeTypeFont::CairoFreeTypeFont(Ref ref, - cairo_font_face_t *cairo_font_face, - int *codeToGID, - Guint codeToGIDLen, - GBool substitute) : CairoFont(ref, - cairo_font_face, - codeToGID, - codeToGIDLen, - substitute, - gTrue) { } - -CairoFreeTypeFont::~CairoFreeTypeFont() { } - -CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, - FT_Library lib, GBool useCIDs) { - Object refObj, strObj; - GooString *fileName; - char *fileNameC; - char *font_data; - int font_data_len; - int i, n; - GfxFontType fontType; - GfxFontLoc *fontLoc; - char **enc; - char *name; - FoFiTrueType *ff; - FoFiType1C *ff1c; - Ref ref; - FT_Face face; - cairo_font_face_t *font_face; - - int *codeToGID; - Guint codeToGIDLen; - - codeToGID = NULL; - codeToGIDLen = 0; - font_data = NULL; - font_data_len = 0; - fileName = NULL; - fileNameC = NULL; - - GBool substitute = gFalse; - - ref = *gfxFont->getID(); - fontType = gfxFont->getType(); - - if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) { - error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->getCString() - : "(unnamed)"); - goto err2; - } - - // embedded font - if (fontLoc->locType == gfxFontLocEmbedded) { - font_data = gfxFont->readEmbFontFile(xref, &font_data_len); - if (NULL == font_data) - goto err2; - - // external font - } else { // gfxFontLocExternal - fileName = fontLoc->path; - fontType = fontLoc->fontType; - substitute = gTrue; - } - - if (fileName != NULL) { - fileNameC = fileName->getCString(); - } - - switch (fontType) { - case fontType1: - case fontType1C: - case fontType1COT: - if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) { - error(errSyntaxError, -1, "could not create type1 face"); - goto err2; - } - - enc = ((Gfx8BitFont *)gfxFont)->getEncoding(); - - codeToGID = (int *)gmallocn(256, sizeof(int)); - codeToGIDLen = 256; - for (i = 0; i < 256; ++i) { - codeToGID[i] = 0; - if ((name = enc[i])) { - codeToGID[i] = FT_Get_Name_Index(face, name); - } - } - break; - case fontCIDType2: - case fontCIDType2OT: - codeToGID = NULL; - n = 0; - if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { - n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - if (n) { - codeToGID = (int *)gmallocn(n, sizeof(int)); - memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - n * sizeof(int)); - } - } else { - if (font_data != NULL) { - ff = FoFiTrueType::make(font_data, font_data_len); - } else { - ff = FoFiTrueType::load(fileNameC); - } - if (! ff) - goto err2; - codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n); - delete ff; - } - codeToGIDLen = n; - /* Fall through */ - case fontTrueType: - if (font_data != NULL) { - ff = FoFiTrueType::make(font_data, font_data_len); - } else { - ff = FoFiTrueType::load(fileNameC); - } - if (! ff) { - error(errSyntaxError, -1, "failed to load truetype font\n"); - goto err2; - } - /* This might be set already for the CIDType2 case */ - if (fontType == fontTrueType) { - codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); - codeToGIDLen = 256; - } - delete ff; - if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) { - error(errSyntaxError, -1, "could not create truetype face\n"); - goto err2; - } - break; - - case fontCIDType0: - case fontCIDType0C: - - codeToGID = NULL; - codeToGIDLen = 0; - - if (!useCIDs) - { - if (font_data != NULL) { - ff1c = FoFiType1C::make(font_data, font_data_len); - } else { - ff1c = FoFiType1C::load(fileNameC); - } - if (ff1c) { - codeToGID = ff1c->getCIDToGIDMap((int *)&codeToGIDLen); - delete ff1c; - } - } - - if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) { - gfree(codeToGID); - codeToGID = NULL; - error(errSyntaxError, -1, "could not create cid face\n"); - goto err2; - } - break; - - default: - fprintf (stderr, "font type %d not handled\n", (int)fontType); - goto err2; - break; - } - - delete fontLoc; - return new CairoFreeTypeFont(ref, - font_face, - codeToGID, codeToGIDLen, - substitute); - - err2: - /* hmm? */ - delete fontLoc; - fprintf (stderr, "some font thing failed\n"); - return NULL; -} - -//------------------------------------------------------------------------ -// CairoType3Font -//------------------------------------------------------------------------ - -static const cairo_user_data_key_t type3_font_key = {0}; - -typedef struct _type3_font_info { - GfxFont *font; - PDFDoc *doc; - CairoFontEngine *fontEngine; - GBool printing; - XRef *xref; -} type3_font_info_t; - -static void -_free_type3_font_info(void *closure) -{ - type3_font_info_t *info = (type3_font_info_t *) closure; - - info->font->decRefCnt(); - free (info); -} - -static cairo_status_t -_init_type3_glyph (cairo_scaled_font_t *scaled_font, - cairo_t *cr, - cairo_font_extents_t *extents) -{ - type3_font_info_t *info; - GfxFont *font; - double *mat; - - info = (type3_font_info_t *) - cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), - &type3_font_key); - font = info->font; - mat = font->getFontBBox(); - extents->ascent = mat[3]; /* y2 */ - extents->descent = -mat[3]; /* -y1 */ - extents->height = extents->ascent + extents->descent; - extents->max_x_advance = mat[2] - mat[1]; /* x2 - x1 */ - extents->max_y_advance = 0; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_render_type3_glyph (cairo_scaled_font_t *scaled_font, - unsigned long glyph, - cairo_t *cr, - cairo_text_extents_t *metrics) -{ - Dict *charProcs; - Object charProc; - CairoOutputDev *output_dev; - cairo_matrix_t matrix, invert_y_axis; - double *mat; - double wx, wy; - PDFRectangle box; - type3_font_info_t *info; - GfxFont *font; - Dict *resDict; - Gfx *gfx; - - info = (type3_font_info_t *) - cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), - &type3_font_key); - - font = info->font; - resDict = ((Gfx8BitFont *)font)->getResources(); - charProcs = ((Gfx8BitFont *)(info->font))->getCharProcs(); - if (!charProcs) - return CAIRO_STATUS_USER_FONT_ERROR; - - if ((int)glyph >= charProcs->getLength()) - return CAIRO_STATUS_USER_FONT_ERROR; - - mat = font->getFontMatrix(); - matrix.xx = mat[0]; - matrix.yx = mat[1]; - matrix.xy = mat[2]; - matrix.yy = mat[3]; - matrix.x0 = mat[4]; - matrix.y0 = mat[5]; - cairo_matrix_init_scale (&invert_y_axis, 1, -1); - cairo_matrix_multiply (&matrix, &matrix, &invert_y_axis); - cairo_transform (cr, &matrix); - - output_dev = new CairoOutputDev(); - output_dev->setCairo(cr); - output_dev->setPrinting(info->printing); - - mat = font->getFontBBox(); - box.x1 = mat[0]; - box.y1 = mat[1]; - box.x2 = mat[2]; - box.y2 = mat[3]; - gfx = new Gfx(info->doc, output_dev, resDict, &box, NULL); - output_dev->startDoc(info->doc, info->fontEngine); - output_dev->startPage (1, gfx->getState(), gfx->getXRef()); - output_dev->setInType3Char(gTrue); - gfx->display(charProcs->getVal(glyph, &charProc)); - - output_dev->getType3GlyphWidth (&wx, &wy); - cairo_matrix_transform_distance (&matrix, &wx, &wy); - metrics->x_advance = wx; - metrics->y_advance = wy; - if (output_dev->hasType3GlyphBBox()) { - double *bbox = output_dev->getType3GlyphBBox(); - - cairo_matrix_transform_point (&matrix, &bbox[0], &bbox[1]); - cairo_matrix_transform_point (&matrix, &bbox[2], &bbox[3]); - metrics->x_bearing = bbox[0]; - metrics->y_bearing = bbox[1]; - metrics->width = bbox[2] - bbox[0]; - metrics->height = bbox[3] - bbox[1]; - } - - delete gfx; - delete output_dev; - charProc.free(); - - return CAIRO_STATUS_SUCCESS; -} - - -CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, PDFDoc *doc, - CairoFontEngine *fontEngine, - GBool printing, XRef *xref) { - Object refObj, strObj; - type3_font_info_t *info; - cairo_font_face_t *font_face; - Ref ref; - int *codeToGID; - Guint codeToGIDLen; - int i, j; - char **enc; - Dict *charProcs; - char *name; - - charProcs = ((Gfx8BitFont *)gfxFont)->getCharProcs(); - info = (type3_font_info_t *) malloc(sizeof(*info)); - ref = *gfxFont->getID(); - font_face = cairo_user_font_face_create(); - cairo_user_font_face_set_init_func (font_face, _init_type3_glyph); - cairo_user_font_face_set_render_glyph_func (font_face, _render_type3_glyph); - gfxFont->incRefCnt(); - info->font = gfxFont; - info->doc = doc; - info->fontEngine = fontEngine; - info->printing = printing; - info->xref = xref; - - cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info); - - enc = ((Gfx8BitFont *)gfxFont)->getEncoding(); - codeToGID = (int *)gmallocn(256, sizeof(int)); - codeToGIDLen = 256; - for (i = 0; i < 256; ++i) { - codeToGID[i] = 0; - if (charProcs && (name = enc[i])) { - for (j = 0; j < charProcs->getLength(); j++) { - if (strcmp(name, charProcs->getKey(j)) == 0) { - codeToGID[i] = j; - } - } - } - } - - return new CairoType3Font(ref, doc, font_face, codeToGID, codeToGIDLen, printing, xref); -} - -CairoType3Font::CairoType3Font(Ref ref, - PDFDoc *doc, - cairo_font_face_t *cairo_font_face, - int *codeToGID, - Guint codeToGIDLen, - GBool printing, XRef *xref) : CairoFont(ref, - cairo_font_face, - codeToGID, - codeToGIDLen, - gFalse, - printing), - doc(doc) { } - -CairoType3Font::~CairoType3Font() { } - -GBool -CairoType3Font::matches(Ref &other, GBool printingA) { - return (other.num == ref.num && other.gen == ref.gen && printing == printingA); -} - - -//------------------------------------------------------------------------ -// CairoFontEngine -//------------------------------------------------------------------------ - -CairoFontEngine::CairoFontEngine(FT_Library libA) { - int i; - - lib = libA; - for (i = 0; i < cairoFontCacheSize; ++i) { - fontCache[i] = NULL; - } - - FT_Int major, minor, patch; - // as of FT 2.1.8, CID fonts are indexed by CID instead of GID - FT_Library_Version(lib, &major, &minor, &patch); - useCIDs = major > 2 || - (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); -/* - * multi thread disabled by WangLu -#if MULTITHREADED - gInitMutex(&mutex); -#endif -*/ -} - -CairoFontEngine::~CairoFontEngine() { - int i; - - for (i = 0; i < cairoFontCacheSize; ++i) { - if (fontCache[i]) - delete fontCache[i]; - } -/* - * multi thread disabled by WangLu -#if MULTITHREADED - gDestroyMutex(&mutex); -#endif -*/ -} - -CairoFont * -CairoFontEngine::getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref) { - int i, j; - Ref ref; - CairoFont *font; - GfxFontType fontType; - - fontEngineLocker(); - ref = *gfxFont->getID(); - - for (i = 0; i < cairoFontCacheSize; ++i) { - font = fontCache[i]; - if (font && font->matches(ref, printing)) { - for (j = i; j > 0; --j) { - fontCache[j] = fontCache[j-1]; - } - fontCache[0] = font; - return font; - } - } - - fontType = gfxFont->getType(); - if (fontType == fontType3) - font = CairoType3Font::create (gfxFont, doc, this, printing, xref); - else - font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs); - - //XXX: if font is null should we still insert it into the cache? - if (fontCache[cairoFontCacheSize - 1]) { - delete fontCache[cairoFontCacheSize - 1]; - } - for (j = cairoFontCacheSize - 1; j > 0; --j) { - fontCache[j] = fontCache[j-1]; - } - fontCache[0] = font; - return font; -} diff --git a/src/CairoOutputDev/CairoFontEngine.h b/src/CairoOutputDev/CairoFontEngine.h deleted file mode 100644 index 432f107..0000000 --- a/src/CairoOutputDev/CairoFontEngine.h +++ /dev/null @@ -1,132 +0,0 @@ -//======================================================================== -// -// CairoFontEngine.h -// -// Copyright 2003 Glyph & Cog, LLC -// Copyright 2004 Red Hat, Inc -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005, 2006 Kristian Høgsberg -// Copyright (C) 2005 Albert Astals Cid -// Copyright (C) 2006, 2007 Jeff Muizelaar -// Copyright (C) 2006, 2010 Carlos Garcia Campos -// Copyright (C) 2008 Adrian Johnson -// Copyright (C) 2013 Thomas Freitag -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef CAIROFONTENGINE_H -#define CAIROFONTENGINE_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "poppler-config.h" -#include "goo/gtypes.h" -#include - -#include "GfxFont.h" -#include "PDFDoc.h" - -class CairoFontEngine; - -class CairoFont { -public: - CairoFont(Ref ref, - cairo_font_face_t *face, - int *codeToGID, - Guint codeToGIDLen, - GBool substitute, - GBool printing); - virtual ~CairoFont(); - - virtual GBool matches(Ref &other, GBool printing); - cairo_font_face_t *getFontFace(void); - unsigned long getGlyph(CharCode code, Unicode *u, int uLen); - double getSubstitutionCorrection(GfxFont *gfxFont); - - GBool isSubstitute() { return substitute; } -protected: - Ref ref; - cairo_font_face_t *cairo_font_face; - - int *codeToGID; - Guint codeToGIDLen; - - GBool substitute; - GBool printing; -}; - -//------------------------------------------------------------------------ - -class CairoFreeTypeFont : public CairoFont { -public: - static CairoFreeTypeFont *create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs); - virtual ~CairoFreeTypeFont(); - -private: - CairoFreeTypeFont(Ref ref, cairo_font_face_t *cairo_font_face, - int *codeToGID, Guint codeToGIDLen, GBool substitute); -}; - -//------------------------------------------------------------------------ - -class CairoType3Font : public CairoFont { -public: - static CairoType3Font *create(GfxFont *gfxFont, PDFDoc *doc, - CairoFontEngine *fontEngine, - GBool printing, XRef *xref); - virtual ~CairoType3Font(); - - virtual GBool matches(Ref &other, GBool printing); - -private: - CairoType3Font(Ref ref, PDFDoc *doc, - cairo_font_face_t *cairo_font_face, - int *codeToGID, Guint codeToGIDLen, - GBool printing, XRef *xref); - PDFDoc *doc; -}; - -//------------------------------------------------------------------------ - -#define cairoFontCacheSize 64 - -//------------------------------------------------------------------------ -// CairoFontEngine -//------------------------------------------------------------------------ - -class CairoFontEngine { -public: - - // Create a font engine. - CairoFontEngine(FT_Library libA); - ~CairoFontEngine(); - - CairoFont *getFont(GfxFont *gfxFont, PDFDoc *doc, GBool printing, XRef *xref); - -private: - CairoFont *fontCache[cairoFontCacheSize]; - FT_Library lib; - GBool useCIDs; -/* - * multi thread disabled by WangLu -#if MULTITHREADED - GooMutex mutex; -#endif -*/ -}; - -#endif diff --git a/src/CairoOutputDev/CairoOutputDev.cc b/src/CairoOutputDev/CairoOutputDev.cc deleted file mode 100644 index 1eb001c..0000000 --- a/src/CairoOutputDev/CairoOutputDev.cc +++ /dev/null @@ -1,3190 +0,0 @@ -//======================================================================== -// -// CairoOutputDev.cc -// -// Copyright 2003 Glyph & Cog, LLC -// Copyright 2004 Red Hat, Inc -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005-2008 Jeff Muizelaar -// Copyright (C) 2005, 2006 Kristian Høgsberg -// Copyright (C) 2005, 2009, 2012 Albert Astals Cid -// Copyright (C) 2005 Nickolay V. Shmyrev -// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos -// Copyright (C) 2008 Carl Worth -// Copyright (C) 2008-2013 Adrian Johnson -// Copyright (C) 2008 Michael Vrable -// Copyright (C) 2008, 2009 Chris Wilson -// Copyright (C) 2008, 2012 Hib Eris -// Copyright (C) 2009, 2010 David Benjamin -// Copyright (C) 2011-2013 Thomas Freitag -// Copyright (C) 2012 Patrick Pfeifer -// Copyright (C) 2012 Jason Crain -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include - -#include "goo/gfile.h" -#include "GlobalParams.h" -#include "Error.h" -#include "Object.h" -#include "Gfx.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "Page.h" -#include "Link.h" -#include "FontEncodingTables.h" -#include "PDFDocEncoding.h" -#include -#include -#include "CairoOutputDev.h" -#include "CairoFontEngine.h" -#include "CairoRescaleBox.h" -#include "UnicodeMap.h" -//------------------------------------------------------------------------ - -// #define LOG_CAIRO - -#ifdef LOG_CAIRO -#define LOG(x) (x) -#else -#define LOG(x) -#endif - -static inline void printMatrix(cairo_matrix_t *matrix){ - printf("%f %f, %f %f (%f %f)\n", matrix->xx, matrix->yx, - matrix->xy, matrix->yy, - matrix->x0, matrix->y0); -} - - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) - - -//------------------------------------------------------------------------ -// CairoImage -//------------------------------------------------------------------------ - -CairoImage::CairoImage (double x1, double y1, double x2, double y2) { - this->image = NULL; - this->x1 = x1; - this->y1 = y1; - this->x2 = x2; - this->y2 = y2; -} - -CairoImage::~CairoImage () { - if (image) - cairo_surface_destroy (image); -} - -void CairoImage::setImage (cairo_surface_t *image) { - if (this->image) - cairo_surface_destroy (this->image); - this->image = cairo_surface_reference (image); -} - -//------------------------------------------------------------------------ -// CairoOutputDev -//------------------------------------------------------------------------ - -// We cannot tie the lifetime of an FT_Library object to that of -// CairoOutputDev, since any FT_Faces created with it may end up with a -// reference by Cairo which can be held long after the CairoOutputDev is -// deleted. The simplest way to avoid problems is to never tear down the -// FT_Library instance; to avoid leaks, just use a single global instance -// initialized the first time it is needed. -FT_Library CairoOutputDev::ft_lib; -GBool CairoOutputDev::ft_lib_initialized = gFalse; - -CairoOutputDev::CairoOutputDev() { - doc = NULL; - - if (!ft_lib_initialized) { - FT_Init_FreeType(&ft_lib); - ft_lib_initialized = gTrue; - } - - fontEngine = NULL; - fontEngine_owner = gFalse; - glyphs = NULL; - fill_pattern = NULL; - fill_color.r = fill_color.g = fill_color.b = 0; - stroke_pattern = NULL; - stroke_color.r = stroke_color.g = stroke_color.b = 0; - stroke_opacity = 1.0; - fill_opacity = 1.0; - textClipPath = NULL; - strokePathClip = NULL; - cairo = NULL; - currentFont = NULL; - prescaleImages = gTrue; - printing = gTrue; - use_show_text_glyphs = gFalse; - inUncoloredPattern = gFalse; - inType3Char = gFalse; - t3_glyph_has_bbox = gFalse; - - groupColorSpaceStack = NULL; - maskStack = NULL; - group = NULL; - mask = NULL; - shape = NULL; - cairo_shape = NULL; - knockoutCount = 0; - - text = NULL; - actualText = NULL; - - // the SA parameter supposedly defaults to false, but Acrobat - // apparently hardwires it to true - stroke_adjust = globalParams->getStrokeAdjust(); - align_stroke_coords = gFalse; - adjusted_stroke_width = gFalse; - xref = NULL; -} - -CairoOutputDev::~CairoOutputDev() { - if (fontEngine_owner && fontEngine) { - delete fontEngine; - } - - if (cairo) - cairo_destroy (cairo); - cairo_pattern_destroy (stroke_pattern); - cairo_pattern_destroy (fill_pattern); - if (group) - cairo_pattern_destroy (group); - if (mask) - cairo_pattern_destroy (mask); - if (shape) - cairo_pattern_destroy (shape); - if (text) - text->decRefCnt(); - if (actualText) - delete actualText; -} - -void CairoOutputDev::setCairo(cairo_t *cairo) -{ - if (this->cairo != NULL) { - cairo_status_t status = cairo_status (this->cairo); - if (status) { - error(errInternal, -1, "cairo context error: {0:s}\n", cairo_status_to_string(status)); - } - cairo_destroy (this->cairo); - assert(!cairo_shape); - } - if (cairo != NULL) { - this->cairo = cairo_reference (cairo); - /* save the initial matrix so that we can use it for type3 fonts. */ - //XXX: is this sufficient? could we miss changes to the matrix somehow? - cairo_get_matrix(cairo, &orig_matrix); - } else { - this->cairo = NULL; - this->cairo_shape = NULL; - } -} - -void CairoOutputDev::setTextPage(TextPage *text) -{ - if (this->text) - this->text->decRefCnt(); - if (actualText) - delete actualText; - if (text) { - this->text = text; - this->text->incRefCnt(); - actualText = new ActualText(text); - } else { - this->text = NULL; - actualText = NULL; - } -} - -void CairoOutputDev::startDoc(PDFDoc *docA, - CairoFontEngine *parentFontEngine) { - doc = docA; - if (parentFontEngine) { - fontEngine = parentFontEngine; - } else { - if (fontEngine) { - delete fontEngine; - } - fontEngine = new CairoFontEngine(ft_lib); - fontEngine_owner = gTrue; - } - xref = doc->getXRef(); -} - -void CairoOutputDev::startPage(int pageNum, GfxState *state, XRef *xrefA) { - /* set up some per page defaults */ - cairo_pattern_destroy(fill_pattern); - cairo_pattern_destroy(stroke_pattern); - - fill_pattern = cairo_pattern_create_rgb(0., 0., 0.); - fill_color.r = fill_color.g = fill_color.b = 0; - stroke_pattern = cairo_pattern_reference(fill_pattern); - stroke_color.r = stroke_color.g = stroke_color.b = 0; - - if (text) - text->startPage(state); - if (xrefA != NULL) { - xref = xrefA; - } -} - -void CairoOutputDev::endPage() { - if (text) { - text->endPage(); - text->coalesce(gTrue, 0, gFalse); - } -} - -void CairoOutputDev::saveState(GfxState *state) { - LOG(printf ("save\n")); - cairo_save (cairo); - if (cairo_shape) - cairo_save (cairo_shape); - - MaskStack *ms = new MaskStack; - ms->mask = cairo_pattern_reference(mask); - ms->mask_matrix = mask_matrix; - ms->next = maskStack; - maskStack = ms; -} - -void CairoOutputDev::restoreState(GfxState *state) { - LOG(printf ("restore\n")); - cairo_restore (cairo); - if (cairo_shape) - cairo_restore (cairo_shape); - - /* These aren't restored by cairo_restore() since we keep them in - * the output device. */ - updateFillColor(state); - updateStrokeColor(state); - updateFillOpacity(state); - updateStrokeOpacity(state); - updateBlendMode(state); - - MaskStack* ms = maskStack; - if (ms) { - if (mask) - cairo_pattern_destroy(mask); - mask = ms->mask; - mask_matrix = ms->mask_matrix; - maskStack = ms->next; - delete ms; - } -} - -void CairoOutputDev::updateAll(GfxState *state) { - updateLineDash(state); - updateLineJoin(state); - updateLineCap(state); - updateLineWidth(state); - updateFlatness(state); - updateMiterLimit(state); - updateFillColor(state); - updateStrokeColor(state); - updateFillOpacity(state); - updateStrokeOpacity(state); - updateBlendMode(state); - needFontUpdate = gTrue; - if (text) - text->updateFont(state); -} - -void CairoOutputDev::setDefaultCTM(double *ctm) { - cairo_matrix_t matrix; - matrix.xx = ctm[0]; - matrix.yx = ctm[1]; - matrix.xy = ctm[2]; - matrix.yy = ctm[3]; - matrix.x0 = ctm[4]; - matrix.y0 = ctm[5]; - - cairo_transform (cairo, &matrix); - if (cairo_shape) - cairo_transform (cairo_shape, &matrix); - - OutputDev::setDefaultCTM(ctm); -} - -void CairoOutputDev::updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, - double m31, double m32) { - cairo_matrix_t matrix, invert_matrix; - matrix.xx = m11; - matrix.yx = m12; - matrix.xy = m21; - matrix.yy = m22; - matrix.x0 = m31; - matrix.y0 = m32; - - /* Make sure the matrix is invertible before setting it. - * cairo will blow up if we give it a matrix that's not - * invertible, so we need to check before passing it - * to cairo_transform. Ignoring it is likely to give better - * results than not rendering anything at all. See #14398 - * - * Ideally, we could do the cairo_transform - * and then check if anything went wrong and fix it then - * instead of having to invert the matrix. */ - invert_matrix = matrix; - if (cairo_matrix_invert(&invert_matrix)) { - error(errSyntaxWarning, -1, "matrix not invertible\n"); - return; - } - - cairo_transform (cairo, &matrix); - if (cairo_shape) - cairo_transform (cairo_shape, &matrix); - updateLineDash(state); - updateLineJoin(state); - updateLineCap(state); - updateLineWidth(state); -} - -void CairoOutputDev::updateLineDash(GfxState *state) { - double *dashPattern; - int dashLength; - double dashStart; - - state->getLineDash(&dashPattern, &dashLength, &dashStart); - cairo_set_dash (cairo, dashPattern, dashLength, dashStart); - if (cairo_shape) - cairo_set_dash (cairo_shape, dashPattern, dashLength, dashStart); -} - -void CairoOutputDev::updateFlatness(GfxState *state) { - // cairo_set_tolerance (cairo, state->getFlatness()); -} - -void CairoOutputDev::updateLineJoin(GfxState *state) { - switch (state->getLineJoin()) { - case 0: - cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER); - break; - case 1: - cairo_set_line_join (cairo, CAIRO_LINE_JOIN_ROUND); - break; - case 2: - cairo_set_line_join (cairo, CAIRO_LINE_JOIN_BEVEL); - break; - } - if (cairo_shape) - cairo_set_line_join (cairo_shape, cairo_get_line_join(cairo)); -} - -void CairoOutputDev::updateLineCap(GfxState *state) { - switch (state->getLineCap()) { - case 0: - cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT); - break; - case 1: - cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND); - break; - case 2: - cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE); - break; - } - if (cairo_shape) - cairo_set_line_cap (cairo_shape, cairo_get_line_cap(cairo)); -} - -void CairoOutputDev::updateMiterLimit(GfxState *state) { - cairo_set_miter_limit (cairo, state->getMiterLimit()); - if (cairo_shape) - cairo_set_miter_limit (cairo_shape, state->getMiterLimit()); -} - -void CairoOutputDev::updateLineWidth(GfxState *state) { - LOG(printf ("line width: %f\n", state->getLineWidth())); - adjusted_stroke_width = gFalse; - double width = state->getLineWidth(); - if (stroke_adjust && !printing) { - double x, y; - x = y = width; - - /* find out line width in device units */ - cairo_user_to_device_distance(cairo, &x, &y); - if (fabs(x) <= 1.0 && fabs(y) <= 1.0) { - /* adjust width to at least one device pixel */ - x = y = 1.0; - cairo_device_to_user_distance(cairo, &x, &y); - width = MIN(fabs(x),fabs(y)); - adjusted_stroke_width = gTrue; - } - } else if (width == 0.0) { - /* Cairo does not support 0 line width == 1 device pixel. Find out - * how big pixels (device unit) are in the x and y - * directions. Choose the smaller of the two as our line width. - */ - double x = 1.0, y = 1.0; - if (printing) { - // assume printer pixel size is 1/600 inch - x = 72.0/600; - y = 72.0/600; - } - cairo_device_to_user_distance(cairo, &x, &y); - width = MIN(fabs(x),fabs(y)); - } - cairo_set_line_width (cairo, width); - if (cairo_shape) - cairo_set_line_width (cairo_shape, cairo_get_line_width (cairo)); -} - -void CairoOutputDev::updateFillColor(GfxState *state) { - GfxRGB color = fill_color; - - if (inUncoloredPattern) - return; - - state->getFillRGB(&fill_color); - if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID || - color.r != fill_color.r || - color.g != fill_color.g || - color.b != fill_color.b) - { - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r), - colToDbl(fill_color.g), - colToDbl(fill_color.b), - fill_opacity); - - LOG(printf ("fill color: %d %d %d\n", - fill_color.r, fill_color.g, fill_color.b)); - } -} - -void CairoOutputDev::updateStrokeColor(GfxState *state) { - GfxRGB color = stroke_color; - - if (inUncoloredPattern) - return; - - state->getStrokeRGB(&stroke_color); - if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID || - color.r != stroke_color.r || - color.g != stroke_color.g || - color.b != stroke_color.b) - { - cairo_pattern_destroy(stroke_pattern); - stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r), - colToDbl(stroke_color.g), - colToDbl(stroke_color.b), - stroke_opacity); - - LOG(printf ("stroke color: %d %d %d\n", - stroke_color.r, stroke_color.g, stroke_color.b)); - } -} - -void CairoOutputDev::updateFillOpacity(GfxState *state) { - double opacity = fill_opacity; - - if (inUncoloredPattern) - return; - - fill_opacity = state->getFillOpacity(); - if (opacity != fill_opacity) { - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r), - colToDbl(fill_color.g), - colToDbl(fill_color.b), - fill_opacity); - - LOG(printf ("fill opacity: %f\n", fill_opacity)); - } -} - -void CairoOutputDev::updateStrokeOpacity(GfxState *state) { - double opacity = stroke_opacity; - - if (inUncoloredPattern) - return; - - stroke_opacity = state->getStrokeOpacity(); - if (opacity != stroke_opacity) { - cairo_pattern_destroy(stroke_pattern); - stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r), - colToDbl(stroke_color.g), - colToDbl(stroke_color.b), - stroke_opacity); - - LOG(printf ("stroke opacity: %f\n", stroke_opacity)); - } -} - -void CairoOutputDev::updateFillColorStop(GfxState *state, double offset) { - if (inUncoloredPattern) - return; - - state->getFillRGB(&fill_color); - - cairo_pattern_add_color_stop_rgba(fill_pattern, offset, - colToDbl(fill_color.r), - colToDbl(fill_color.g), - colToDbl(fill_color.b), - fill_opacity); - LOG(printf ("fill color stop: %f (%d, %d, %d)\n", - offset, fill_color.r, fill_color.g, fill_color.b)); -} - -void CairoOutputDev::updateBlendMode(GfxState *state) { - switch (state->getBlendMode()) { - default: - case gfxBlendNormal: - cairo_set_operator (cairo, CAIRO_OPERATOR_OVER); - break; - case gfxBlendMultiply: - cairo_set_operator (cairo, CAIRO_OPERATOR_MULTIPLY); - break; - case gfxBlendScreen: - cairo_set_operator (cairo, CAIRO_OPERATOR_SCREEN); - break; - case gfxBlendOverlay: - cairo_set_operator (cairo, CAIRO_OPERATOR_OVERLAY); - break; - case gfxBlendDarken: - cairo_set_operator (cairo, CAIRO_OPERATOR_DARKEN); - break; - case gfxBlendLighten: - cairo_set_operator (cairo, CAIRO_OPERATOR_LIGHTEN); - break; - case gfxBlendColorDodge: - cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_DODGE); - break; - case gfxBlendColorBurn: - cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_BURN); - break; - case gfxBlendHardLight: - cairo_set_operator (cairo, CAIRO_OPERATOR_HARD_LIGHT); - break; - case gfxBlendSoftLight: - cairo_set_operator (cairo, CAIRO_OPERATOR_SOFT_LIGHT); - break; - case gfxBlendDifference: - cairo_set_operator (cairo, CAIRO_OPERATOR_DIFFERENCE); - break; - case gfxBlendExclusion: - cairo_set_operator (cairo, CAIRO_OPERATOR_EXCLUSION); - break; - case gfxBlendHue: - cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_HUE); - break; - case gfxBlendSaturation: - cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_SATURATION); - break; - case gfxBlendColor: - cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_COLOR); - break; - case gfxBlendLuminosity: - cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_LUMINOSITY); - break; - } - LOG(printf ("blend mode: %d\n", (int)state->getBlendMode())); -} - -void CairoOutputDev::updateFont(GfxState *state) { - cairo_font_face_t *font_face; - cairo_matrix_t matrix, invert_matrix; - - LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString())); - - needFontUpdate = gFalse; - - //FIXME: use cairo font engine? - if (text) - text->updateFont(state); - - currentFont = fontEngine->getFont (state->getFont(), doc, printing, xref); - - if (!currentFont) - return; - - font_face = currentFont->getFontFace(); - cairo_set_font_face (cairo, font_face); - - use_show_text_glyphs = state->getFont()->hasToUnicodeCMap() && - cairo_surface_has_show_text_glyphs (cairo_get_target (cairo)); - - double fontSize = state->getFontSize(); - double *m = state->getTextMat(); - /* NOTE: adjusting by a constant is hack. The correct solution - * is probably to use user-fonts and compute the scale on a per - * glyph basis instead of for the entire font */ - double w = currentFont->getSubstitutionCorrection(state->getFont()); - matrix.xx = m[0] * fontSize * state->getHorizScaling() * w; - matrix.yx = m[1] * fontSize * state->getHorizScaling() * w; - matrix.xy = -m[2] * fontSize; - matrix.yy = -m[3] * fontSize; - matrix.x0 = 0; - matrix.y0 = 0; - - LOG(printf ("font matrix: %f %f %f %f\n", matrix.xx, matrix.yx, matrix.xy, matrix.yy)); - - /* Make sure the font matrix is invertible before setting it. cairo - * will blow up if we give it a matrix that's not invertible, so we - * need to check before passing it to cairo_set_font_matrix. Ignoring it - * is likely to give better results than not rendering anything at - * all. See #18254. - */ - invert_matrix = matrix; - if (cairo_matrix_invert(&invert_matrix)) { - error(errSyntaxWarning, -1, "font matrix not invertible\n"); - return; - } - - cairo_set_font_matrix (cairo, &matrix); -} - -/* Tolerance in pixels for checking if strokes are horizontal or vertical - * lines in device space */ -#define STROKE_COORD_TOLERANCE 0.5 - -/* Align stroke coordinate i if the point is the start or end of a - * horizontal or vertical line */ -void CairoOutputDev::alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y) -{ - double x1, y1, x2, y2; - GBool align = gFalse; - - x1 = subpath->getX(i); - y1 = subpath->getY(i); - cairo_user_to_device (cairo, &x1, &y1); - - // Does the current coord and prev coord form a horiz or vert line? - if (i > 0 && !subpath->getCurve(i - 1)) { - x2 = subpath->getX(i - 1); - y2 = subpath->getY(i - 1); - cairo_user_to_device (cairo, &x2, &y2); - if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE) - align = gTrue; - } - - // Does the current coord and next coord form a horiz or vert line? - if (i < subpath->getNumPoints() - 1 && !subpath->getCurve(i + 1)) { - x2 = subpath->getX(i + 1); - y2 = subpath->getY(i + 1); - cairo_user_to_device (cairo, &x2, &y2); - if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE) - align = gTrue; - } - - *x = subpath->getX(i); - *y = subpath->getY(i); - if (align) { - /* see http://www.cairographics.org/FAQ/#sharp_lines */ - cairo_user_to_device (cairo, x, y); - *x = floor(*x) + 0.5; - *y = floor(*y) + 0.5; - cairo_device_to_user (cairo, x, y); - } -} - -#undef STROKE_COORD_TOLERANCE - -void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) { - GfxSubpath *subpath; - int i, j; - double x, y; - cairo_new_path (cairo); - for (i = 0; i < path->getNumSubpaths(); ++i) { - subpath = path->getSubpath(i); - if (subpath->getNumPoints() > 0) { - if (align_stroke_coords) { - alignStrokeCoords(subpath, 0, &x, &y); - } else { - x = subpath->getX(0); - y = subpath->getY(0); - } - cairo_move_to (cairo, x, y); - j = 1; - while (j < subpath->getNumPoints()) { - if (subpath->getCurve(j)) { - if (align_stroke_coords) { - alignStrokeCoords(subpath, j + 2, &x, &y); - } else { - x = subpath->getX(j+2); - y = subpath->getY(j+2); - } - cairo_curve_to( cairo, - subpath->getX(j), subpath->getY(j), - subpath->getX(j+1), subpath->getY(j+1), - x, y); - - j += 3; - } else { - if (align_stroke_coords) { - alignStrokeCoords(subpath, j, &x, &y); - } else { - x = subpath->getX(j); - y = subpath->getY(j); - } - cairo_line_to (cairo, x, y); - ++j; - } - } - if (subpath->isClosed()) { - LOG (printf ("close\n")); - cairo_close_path (cairo); - } - } - } -} - -void CairoOutputDev::stroke(GfxState *state) { - if (inType3Char) { - GfxGray gray; - state->getFillGray(&gray); - if (colToDbl(gray) > 0.5) - return; - } - - if (adjusted_stroke_width) - align_stroke_coords = gTrue; - doPath (cairo, state, state->getPath()); - align_stroke_coords = gFalse; - cairo_set_source (cairo, stroke_pattern); - LOG(printf ("stroke\n")); - cairo_stroke (cairo); - if (cairo_shape) { - doPath (cairo_shape, state, state->getPath()); - cairo_stroke (cairo_shape); - } -} - -void CairoOutputDev::fill(GfxState *state) { - if (inType3Char) { - GfxGray gray; - state->getFillGray(&gray); - if (colToDbl(gray) > 0.5) - return; - } - - doPath (cairo, state, state->getPath()); - cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING); - cairo_set_source (cairo, fill_pattern); - LOG(printf ("fill\n")); - //XXX: how do we get the path - if (mask) { - cairo_save (cairo); - cairo_clip (cairo); - cairo_set_matrix (cairo, &mask_matrix); - cairo_mask (cairo, mask); - cairo_restore (cairo); - } else if (strokePathClip) { - fillToStrokePathClip(state); - } else { - cairo_fill (cairo); - } - if (cairo_shape) { - cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING); - doPath (cairo_shape, state, state->getPath()); - cairo_fill (cairo_shape); - } -} - -void CairoOutputDev::eoFill(GfxState *state) { - doPath (cairo, state, state->getPath()); - cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD); - cairo_set_source (cairo, fill_pattern); - LOG(printf ("fill-eo\n")); - cairo_fill (cairo); - - if (cairo_shape) { - cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD); - doPath (cairo_shape, state, state->getPath()); - cairo_fill (cairo_shape); - } - -} - -GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfxA, Catalog *cat, Object *str, - double *pmat, int paintType, int /*tilingType*/, Dict *resDict, - double *mat, double *bbox, - int x0, int y0, int x1, int y1, - double xStep, double yStep) -{ - PDFRectangle box; - Gfx *gfx; - cairo_pattern_t *pattern; - cairo_surface_t *surface; - cairo_matrix_t matrix; - cairo_t *old_cairo; - double xMin, yMin, xMax, yMax; - double width, height; - int surface_width, surface_height; - StrokePathClip *strokePathTmp; - - width = bbox[2] - bbox[0]; - height = bbox[3] - bbox[1]; - - if (xStep != width || yStep != height) - return gFalse; - /* TODO: implement the other cases here too */ - - surface_width = (int) ceil (width); - surface_height = (int) ceil (height); - - surface = cairo_surface_create_similar (cairo_get_target (cairo), - CAIRO_CONTENT_COLOR_ALPHA, - surface_width, surface_height); - if (cairo_surface_status (surface)) - return gFalse; - - old_cairo = cairo; - cairo = cairo_create (surface); - cairo_surface_destroy (surface); - - box.x1 = bbox[0]; box.y1 = bbox[1]; - box.x2 = bbox[2]; box.y2 = bbox[3]; - strokePathTmp = strokePathClip; - strokePathClip = NULL; - gfx = new Gfx(doc, this, resDict, &box, NULL, NULL, NULL, gfxA->getXRef()); - if (paintType == 2) - inUncoloredPattern = gTrue; - gfx->display(str); - if (paintType == 2) - inUncoloredPattern = gFalse; - delete gfx; - strokePathClip = strokePathTmp; - - pattern = cairo_pattern_create_for_surface (cairo_get_target (cairo)); - cairo_destroy (cairo); - cairo = old_cairo; - if (cairo_pattern_status (pattern)) - return gFalse; - - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - cairo_rectangle (cairo, xMin, yMin, xMax - xMin, yMax - yMin); - - cairo_matrix_init_scale (&matrix, surface_width / width, surface_height / height); - cairo_pattern_set_matrix (pattern, &matrix); - - cairo_matrix_init (&matrix, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); - cairo_transform (cairo, &matrix); - cairo_set_source (cairo, pattern); - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); - if (strokePathClip) { - fillToStrokePathClip(state); - } else { - cairo_fill (cairo); - } - - cairo_pattern_destroy (pattern); - - return gTrue; -} - -GBool CairoOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) { - double x0, y0, x1, y1; - double dx, dy; - - shading->getCoords(&x0, &y0, &x1, &y1); - dx = x1 - x0; - dy = y1 - y0; - - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_linear (x0 + tMin * dx, y0 + tMin * dy, - x0 + tMax * dx, y0 + tMax * dy); - if (!shading->getExtend0() && !shading->getExtend1()) - cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE); - else - cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD); - - LOG (printf ("axial-sh\n")); - - // TODO: use the actual stops in the shading in the case - // of linear interpolation (Type 2 Exponential functions with N=1) - return gFalse; -} - -GBool CairoOutputDev::axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading) -{ - return (shading->getExtend0() == shading->getExtend1()); -} - -GBool CairoOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) { - double x0, y0, r0, x1, y1, r1; - double dx, dy, dr; - - shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); - dx = x1 - x0; - dy = y1 - y0; - dr = r1 - r0; - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_radial (x0 + sMin * dx, - y0 + sMin * dy, - r0 + sMin * dr, - x0 + sMax * dx, - y0 + sMax * dy, - r0 + sMax * dr); - if (shading->getExtend0() && shading->getExtend1()) - cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD); - else - cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE); - - LOG (printf ("radial-sh\n")); - - return gFalse; -} - -GBool CairoOutputDev::radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading) -{ - return (shading->getExtend0() == shading->getExtend1()); -} - -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) -GBool CairoOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) -{ - double x0, y0, x1, y1, x2, y2; - GfxColor color[3]; - int i, j; - GfxRGB rgb; - - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_mesh (); - - for (i = 0; i < shading->getNTriangles(); i++) { - if (shading->isParameterized()) { - double color0, color1, color2; - shading->getTriangle(i, &x0, &y0, &color0, - &x1, &y1, &color1, - &x2, &y2, &color2); - shading->getParameterizedColor(color0, &color[0]); - shading->getParameterizedColor(color1, &color[1]); - shading->getParameterizedColor(color2, &color[2]); - } else { - shading->getTriangle(i, - &x0, &y0, &color[0], - &x1, &y1, &color[1], - &x2, &y2, &color[2]); - - } - - cairo_mesh_pattern_begin_patch (fill_pattern); - - cairo_mesh_pattern_move_to (fill_pattern, x0, y0); - cairo_mesh_pattern_line_to (fill_pattern, x1, y1); - cairo_mesh_pattern_line_to (fill_pattern, x2, y2); - - for (j = 0; j < 3; j++) { - shading->getColorSpace()->getRGB(&color[j], &rgb); - cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j, - colToDbl(rgb.r), - colToDbl(rgb.g), - colToDbl(rgb.b)); - } - - cairo_mesh_pattern_end_patch (fill_pattern); - } - - double xMin, yMin, xMax, yMax; - // get the clip region bbox - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - state->moveTo(xMin, yMin); - state->lineTo(xMin, yMax); - state->lineTo(xMax, yMax); - state->lineTo(xMax, yMin); - state->closePath(); - fill(state); - state->clearPath(); - - return gTrue; -} - -GBool CairoOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading) -{ - int i, j, k; - - cairo_pattern_destroy(fill_pattern); - fill_pattern = cairo_pattern_create_mesh (); - - for (i = 0; i < shading->getNPatches(); i++) { - GfxPatch *patch = shading->getPatch(i); - GfxColor color; - GfxRGB rgb; - - cairo_mesh_pattern_begin_patch (fill_pattern); - - cairo_mesh_pattern_move_to (fill_pattern, patch->x[0][0], patch->y[0][0]); - cairo_mesh_pattern_curve_to (fill_pattern, - patch->x[0][1], patch->y[0][1], - patch->x[0][2], patch->y[0][2], - patch->x[0][3], patch->y[0][3]); - - cairo_mesh_pattern_curve_to (fill_pattern, - patch->x[1][3], patch->y[1][3], - patch->x[2][3], patch->y[2][3], - patch->x[3][3], patch->y[3][3]); - - cairo_mesh_pattern_curve_to (fill_pattern, - patch->x[3][2], patch->y[3][2], - patch->x[3][1], patch->y[3][1], - patch->x[3][0], patch->y[3][0]); - - cairo_mesh_pattern_curve_to (fill_pattern, - patch->x[2][0], patch->y[2][0], - patch->x[1][0], patch->y[1][0], - patch->x[0][0], patch->y[0][0]); - - cairo_mesh_pattern_set_control_point (fill_pattern, 0, patch->x[1][1], patch->y[1][1]); - cairo_mesh_pattern_set_control_point (fill_pattern, 1, patch->x[1][2], patch->y[1][2]); - cairo_mesh_pattern_set_control_point (fill_pattern, 2, patch->x[2][2], patch->y[2][2]); - cairo_mesh_pattern_set_control_point (fill_pattern, 3, patch->x[2][1], patch->y[2][1]); - - for (j = 0; j < 4; j++) { - int u, v; - - switch (j) { - case 0: - u = 0; v = 0; - break; - case 1: - u = 0; v = 1; - break; - case 2: - u = 1; v = 1; - break; - case 3: - u = 1; v = 0; - break; - } - - if (shading->isParameterized()) { - shading->getParameterizedColor (patch->color[u][v].c[0], &color); - } else { - for (k = 0; k < shading->getColorSpace()->getNComps(); k++) { - // simply cast to the desired type; that's all what is needed. - color.c[k] = GfxColorComp (patch->color[u][v].c[k]); - } - } - - shading->getColorSpace()->getRGB(&color, &rgb); - cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j, - colToDbl(rgb.r), - colToDbl(rgb.g), - colToDbl(rgb.b)); - } - cairo_mesh_pattern_end_patch (fill_pattern); - } - - double xMin, yMin, xMax, yMax; - // get the clip region bbox - state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); - state->moveTo(xMin, yMin); - state->lineTo(xMin, yMax); - state->lineTo(xMax, yMax); - state->lineTo(xMax, yMin); - state->closePath(); - fill(state); - state->clearPath(); - - return gTrue; -} -#endif /* CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) */ - -void CairoOutputDev::clip(GfxState *state) { - doPath (cairo, state, state->getPath()); - cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING); - cairo_clip (cairo); - LOG (printf ("clip\n")); - if (cairo_shape) { - doPath (cairo_shape, state, state->getPath()); - cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING); - cairo_clip (cairo_shape); - } -} - -void CairoOutputDev::eoClip(GfxState *state) { - doPath (cairo, state, state->getPath()); - cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD); - cairo_clip (cairo); - LOG (printf ("clip-eo\n")); - if (cairo_shape) { - doPath (cairo_shape, state, state->getPath()); - cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD); - cairo_clip (cairo_shape); - } - -} - -void CairoOutputDev::clipToStrokePath(GfxState *state) { - LOG(printf("clip-to-stroke-path\n")); - strokePathClip = (StrokePathClip*)gmalloc (sizeof(*strokePathClip)); - strokePathClip->path = state->getPath()->copy(); - cairo_get_matrix (cairo, &strokePathClip->ctm); - strokePathClip->line_width = cairo_get_line_width (cairo); - strokePathClip->dash_count = cairo_get_dash_count (cairo); - if (strokePathClip->dash_count) { - strokePathClip->dashes = (double*) gmallocn (sizeof(double), strokePathClip->dash_count); - cairo_get_dash (cairo, strokePathClip->dashes, &strokePathClip->dash_offset); - } else { - strokePathClip->dashes = NULL; - } - strokePathClip->cap = cairo_get_line_cap (cairo); - strokePathClip->join = cairo_get_line_join (cairo); - strokePathClip->miter = cairo_get_miter_limit (cairo); -} - -void CairoOutputDev::fillToStrokePathClip(GfxState *state) { - cairo_save (cairo); - - cairo_set_matrix (cairo, &strokePathClip->ctm); - cairo_set_line_width (cairo, strokePathClip->line_width); - strokePathClip->dash_count = cairo_get_dash_count (cairo); - cairo_set_dash (cairo, strokePathClip->dashes, strokePathClip->dash_count, strokePathClip->dash_offset); - cairo_set_line_cap (cairo, strokePathClip->cap); - cairo_set_line_join (cairo, strokePathClip->join); - cairo_set_miter_limit (cairo, strokePathClip->miter); - doPath (cairo, state, strokePathClip->path); - cairo_stroke (cairo); - - cairo_restore (cairo); - - delete strokePathClip->path; - if (strokePathClip->dashes) - gfree (strokePathClip->dashes); - gfree (strokePathClip); - strokePathClip = NULL; -} - -void CairoOutputDev::beginString(GfxState *state, GooString *s) -{ - int len = s->getLength(); - - if (needFontUpdate) - updateFont(state); - - if (!currentFont) - return; - - glyphs = (cairo_glyph_t *) gmallocn (len, sizeof (cairo_glyph_t)); - glyphCount = 0; - if (use_show_text_glyphs) { - clusters = (cairo_text_cluster_t *) gmallocn (len, sizeof (cairo_text_cluster_t)); - clusterCount = 0; - utf8Max = len*2; // start with twice the number of glyphs. we will realloc if we need more. - utf8 = (char *) gmalloc (utf8Max); - utf8Count = 0; - } -} - -void CairoOutputDev::drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, int nBytes, Unicode *u, int uLen) -{ - if (currentFont) { - glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen); - glyphs[glyphCount].x = x - originX; - glyphs[glyphCount].y = y - originY; - glyphCount++; - if (use_show_text_glyphs) { - GooString enc("UTF-8"); - UnicodeMap *utf8Map = globalParams->getUnicodeMap(&enc); - if (utf8Max - utf8Count < uLen*6) { - // utf8 encoded characters can be up to 6 bytes - if (utf8Max > uLen*6) - utf8Max *= 2; - else - utf8Max += 2*uLen*6; - utf8 = (char *) grealloc (utf8, utf8Max); - } - clusters[clusterCount].num_bytes = 0; - for (int i = 0; i < uLen; i++) { - int size = utf8Map->mapUnicode(u[i], utf8 + utf8Count, utf8Max - utf8Count); - utf8Count += size; - clusters[clusterCount].num_bytes += size; - } - clusters[clusterCount].num_glyphs = 1; - clusterCount++; - } - } - - if (!text) - return; - actualText->addChar (state, x, y, dx, dy, code, nBytes, u, uLen); -} - -void CairoOutputDev::endString(GfxState *state) -{ - int render; - - if (!currentFont) - return; - - // endString can be called without a corresponding beginString. If this - // happens glyphs will be null so don't draw anything, just return. - // XXX: OutputDevs should probably not have to deal with this... - if (!glyphs) - return; - - // ignore empty strings and invisible text -- this is used by - // Acrobat Capture - render = state->getRender(); - if (render == 3 || glyphCount == 0) { - gfree(glyphs); - glyphs = NULL; - return; - } - - if (!(render & 1)) { - LOG (printf ("fill string\n")); - cairo_set_source (cairo, fill_pattern); - if (use_show_text_glyphs) - cairo_show_text_glyphs (cairo, utf8, utf8Count, glyphs, glyphCount, clusters, clusterCount, (cairo_text_cluster_flags_t)0); - else - cairo_show_glyphs (cairo, glyphs, glyphCount); - if (cairo_shape) - cairo_show_glyphs (cairo_shape, glyphs, glyphCount); - } - - // stroke - if ((render & 3) == 1 || (render & 3) == 2) { - LOG (printf ("stroke string\n")); - cairo_set_source (cairo, stroke_pattern); - cairo_glyph_path (cairo, glyphs, glyphCount); - cairo_stroke (cairo); - if (cairo_shape) { - cairo_glyph_path (cairo_shape, glyphs, glyphCount); - cairo_stroke (cairo_shape); - } - } - - // clip - if ((render & 4)) { - LOG (printf ("clip string\n")); - // append the glyph path to textClipPath. - - // set textClipPath as the currentPath - if (textClipPath) { - cairo_append_path (cairo, textClipPath); - if (cairo_shape) { - cairo_append_path (cairo_shape, textClipPath); - } - cairo_path_destroy (textClipPath); - } - - // append the glyph path - cairo_glyph_path (cairo, glyphs, glyphCount); - - // move the path back into textClipPath - // and clear the current path - textClipPath = cairo_copy_path (cairo); - cairo_new_path (cairo); - if (cairo_shape) { - cairo_new_path (cairo_shape); - } - } - - gfree (glyphs); - glyphs = NULL; - if (use_show_text_glyphs) { - gfree (clusters); - clusters = NULL; - gfree (utf8); - utf8 = NULL; - } -} - - -GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen) { - - cairo_save (cairo); - double *ctm; - cairo_matrix_t matrix; - - ctm = state->getCTM(); - matrix.xx = ctm[0]; - matrix.yx = ctm[1]; - matrix.xy = ctm[2]; - matrix.yy = ctm[3]; - matrix.x0 = ctm[4]; - matrix.y0 = ctm[5]; - /* Restore the original matrix and then transform to matrix needed for the - * type3 font. This is ugly but seems to work. Perhaps there is a better way to do it?*/ - cairo_set_matrix(cairo, &orig_matrix); - cairo_transform(cairo, &matrix); - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_set_matrix(cairo_shape, &orig_matrix); - cairo_transform(cairo_shape, &matrix); - } - cairo_pattern_destroy(stroke_pattern); - cairo_pattern_reference(fill_pattern); - stroke_pattern = fill_pattern; - return gFalse; -} - -void CairoOutputDev::endType3Char(GfxState *state) { - cairo_restore (cairo); - if (cairo_shape) { - cairo_restore (cairo_shape); - } -} - -void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) { - t3_glyph_wx = wx; - t3_glyph_wy = wy; -} - -void CairoOutputDev::type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury) { - t3_glyph_wx = wx; - t3_glyph_wy = wy; - t3_glyph_bbox[0] = llx; - t3_glyph_bbox[1] = lly; - t3_glyph_bbox[2] = urx; - t3_glyph_bbox[3] = ury; - t3_glyph_has_bbox = gTrue; -} - -void CairoOutputDev::beginTextObject(GfxState *state) { -} - -void CairoOutputDev::endTextObject(GfxState *state) { - if (textClipPath) { - // clip the accumulated text path - cairo_append_path (cairo, textClipPath); - cairo_clip (cairo); - if (cairo_shape) { - cairo_append_path (cairo_shape, textClipPath); - cairo_clip (cairo_shape); - } - cairo_path_destroy (textClipPath); - textClipPath = NULL; - } -} - -void CairoOutputDev::beginActualText(GfxState *state, GooString *text) -{ - if (this->text) - actualText->begin(state, text); -} - -void CairoOutputDev::endActualText(GfxState *state) -{ - if (text) - actualText->end(state); -} - -static inline int splashRound(SplashCoord x) { - return (int)floor(x + 0.5); -} - -static inline int splashCeil(SplashCoord x) { - return (int)ceil(x); -} - -static inline int splashFloor(SplashCoord x) { - return (int)floor(x); -} - -static -cairo_surface_t *cairo_surface_create_similar_clip (cairo_t *cairo, cairo_content_t content) -{ - double x1, y1, x2, y2; - int width, height; - cairo_clip_extents (cairo, &x1, &y1, &x2, &y2); - cairo_matrix_t matrix; - cairo_get_matrix (cairo, &matrix); - //cairo_matrix_transform_point(&matrix, &x1, &y1); - //cairo_matrix_transform_point(&matrix, &x2, &y2);*/ - cairo_user_to_device(cairo, &x1, &y1); - cairo_user_to_device(cairo, &x2, &y2); - width = splashCeil(x2) - splashFloor(x1); - //XXX: negative matrix - ////height = splashCeil(y2) - splashFloor(y1); - height = splashFloor(y1) - splashCeil(y2); - cairo_surface_t *target = cairo_get_target (cairo); - cairo_surface_t *result; - - result = cairo_surface_create_similar (target, content, width, height); - double x_offset, y_offset; - cairo_surface_get_device_offset(target, &x_offset, &y_offset); - cairo_surface_set_device_offset(result, x_offset, y_offset); - - - return result; -} - - - -void CairoOutputDev::beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/, - GfxColorSpace * blendingColorSpace, - GBool /*isolated*/, GBool knockout, - GBool forSoftMask) { - /* push color space */ - ColorSpaceStack* css = new ColorSpaceStack; - css->cs = blendingColorSpace; - css->knockout = knockout; - cairo_get_matrix(cairo, &css->group_matrix); - css->next = groupColorSpaceStack; - groupColorSpaceStack = css; - - LOG(printf ("begin transparency group. knockout: %s\n", knockout ? "yes":"no")); - - if (knockout) { - knockoutCount++; - if (!cairo_shape) { - /* create a surface for tracking the shape */ - cairo_surface_t *cairo_shape_surface = cairo_surface_create_similar_clip (cairo, CAIRO_CONTENT_ALPHA); - cairo_shape = cairo_create (cairo_shape_surface); - cairo_surface_destroy (cairo_shape_surface); - - /* the color doesn't matter as long as it is opaque */ - cairo_set_source_rgb (cairo_shape, 0, 0, 0); - cairo_matrix_t matrix; - cairo_get_matrix (cairo, &matrix); - //printMatrix(&matrix); - cairo_set_matrix (cairo_shape, &matrix); - } else { - cairo_reference (cairo_shape); - } - } - if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) { - /* we need to track the shape */ - cairo_push_group (cairo_shape); - } - if (0 && forSoftMask) - cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA); - else - cairo_push_group (cairo); - - /* push_group has an implicit cairo_save() */ - if (knockout) { - /*XXX: let's hope this matches the semantics needed */ - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - } else { - cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); - } -} - -void CairoOutputDev::endTransparencyGroup(GfxState * /*state*/) { - if (group) - cairo_pattern_destroy(group); - group = cairo_pop_group (cairo); - - LOG(printf ("end transparency group\n")); - - if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) { - if (shape) - cairo_pattern_destroy(shape); - shape = cairo_pop_group (cairo_shape); - } -} - -void CairoOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) { - LOG(printf ("paint transparency group\n")); - - cairo_save (cairo); - cairo_set_matrix (cairo, &groupColorSpaceStack->group_matrix); - cairo_set_source (cairo, group); - - if (!mask) { - //XXX: deal with mask && shape case - if (shape) { - cairo_save (cairo); - - /* OPERATOR_SOURCE w/ a mask is defined as (src IN mask) ADD (dest OUT mask) - * however our source has already been clipped to mask so we only need to - * do ADD and OUT */ - - /* clear the shape mask */ - cairo_set_source (cairo, shape); - cairo_set_operator (cairo, CAIRO_OPERATOR_DEST_OUT); - cairo_paint (cairo); - - cairo_set_operator (cairo, CAIRO_OPERATOR_ADD); - cairo_set_source (cairo, group); - cairo_paint (cairo); - - cairo_restore (cairo); - - cairo_pattern_destroy (shape); - shape = NULL; - } else { - cairo_paint_with_alpha (cairo, fill_opacity); - } - cairo_status_t status = cairo_status(cairo); - if (status) - printf("BAD status: %s\n", cairo_status_to_string(status)); - } else { - if (fill_opacity < 1.0) { - cairo_push_group(cairo); - } - cairo_save(cairo); - cairo_set_matrix(cairo, &mask_matrix); - cairo_mask(cairo, mask); - cairo_restore(cairo); - if (fill_opacity < 1.0) { - cairo_pop_group_to_source(cairo); - cairo_paint_with_alpha (cairo, fill_opacity); - } - cairo_pattern_destroy(mask); - mask = NULL; - } - - popTransparencyGroup(); - cairo_restore(cairo); -} - -static int luminocity(uint32_t x) -{ - int r = (x >> 16) & 0xff; - int g = (x >> 8) & 0xff; - int b = (x >> 0) & 0xff; - // an arbitrary integer approximation of .3*r + .59*g + .11*b - int y = (r*19661+g*38666+b*7209 + 32829)>>16; - return y; -} - - -/* XXX: do we need to deal with shape here? */ -void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha, - Function * transferFunc, GfxColor * backdropColor) { - cairo_pattern_destroy(mask); - - LOG(printf ("set softMask\n")); - - if (!alpha || transferFunc) { - /* We need to mask according to the luminocity of the group. - * So we paint the group to an image surface convert it to a luminocity map - * and then use that as the mask. */ - - /* Get clip extents in device space */ - double x1, y1, x2, y2, x_min, y_min, x_max, y_max; - cairo_clip_extents(cairo, &x1, &y1, &x2, &y2); - cairo_user_to_device(cairo, &x1, &y1); - cairo_user_to_device(cairo, &x2, &y2); - x_min = MIN(x1, x2); - y_min = MIN(y1, y2); - x_max = MAX(x1, x2); - y_max = MAX(y1, y2); - cairo_clip_extents(cairo, &x1, &y1, &x2, &y2); - cairo_user_to_device(cairo, &x1, &y2); - cairo_user_to_device(cairo, &x2, &y1); - x_min = MIN(x_min,MIN(x1, x2)); - y_min = MIN(y_min,MIN(y1, y2)); - x_max = MAX(x_max,MAX(x1, x2)); - y_max = MAX(y_max,MAX(y1, y2)); - - int width = (int)(ceil(x_max) - floor(x_min)); - int height = (int)(ceil(y_max) - floor(y_min)); - - /* Get group device offset */ - double x_offset, y_offset; - if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) { - cairo_surface_get_device_offset(cairo_get_group_target(cairo), &x_offset, &y_offset); - } else { - cairo_surface_t *pats; - cairo_pattern_get_surface(group, &pats); - cairo_surface_get_device_offset(pats, &x_offset, &y_offset); - } - - /* Adjust extents by group offset */ - x_min += x_offset; - y_min += y_offset; - - cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t *maskCtx = cairo_create(source); - - //XXX: hopefully this uses the correct color space */ - if (!alpha) { - GfxRGB backdropColorRGB; - groupColorSpaceStack->cs->getRGB(backdropColor, &backdropColorRGB); - /* paint the backdrop */ - cairo_set_source_rgb(maskCtx, - colToDbl(backdropColorRGB.r), - colToDbl(backdropColorRGB.g), - colToDbl(backdropColorRGB.b)); - } - cairo_paint(maskCtx); - - /* Copy source ctm to mask ctm and translate origin so that the - * mask appears it the same location on the source surface. */ - cairo_matrix_t mat, tmat; - cairo_matrix_init_translate(&tmat, -x_min, -y_min); - cairo_get_matrix(cairo, &mat); - cairo_matrix_multiply(&mat, &mat, &tmat); - cairo_set_matrix(maskCtx, &mat); - - /* make the device offset of the new mask match that of the group */ - cairo_surface_set_device_offset(source, x_offset, y_offset); - - /* paint the group */ - cairo_set_source(maskCtx, group); - cairo_paint(maskCtx); - - /* XXX status = cairo_status(maskCtx); */ - cairo_destroy(maskCtx); - - /* convert to a luminocity map */ - uint32_t *source_data = (uint32_t*)cairo_image_surface_get_data(source); - /* get stride in units of 32 bits */ - int stride = cairo_image_surface_get_stride(source)/4; - for (int y=0; ytransform(&lum_in, &lum_out); - lum = (int)(lum_out * 255.0 + 0.5); - } - source_data[y*stride + x] = lum << 24; - } - } - cairo_surface_mark_dirty (source); - - /* setup the new mask pattern */ - mask = cairo_pattern_create_for_surface(source); - cairo_get_matrix(cairo, &mask_matrix); - - if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) { - cairo_pattern_set_matrix(mask, &mat); - } else { - cairo_matrix_t patMatrix; - cairo_pattern_get_matrix(group, &patMatrix); - /* Apply x_min, y_min offset to it appears in the same location as source. */ - cairo_matrix_multiply(&patMatrix, &patMatrix, &tmat); - cairo_pattern_set_matrix(mask, &patMatrix); - } - - cairo_surface_destroy(source); - } else if (alpha) { - mask = cairo_pattern_reference(group); - cairo_get_matrix(cairo, &mask_matrix); - } - - popTransparencyGroup(); -} - -void CairoOutputDev::popTransparencyGroup() { - /* pop color space */ - ColorSpaceStack *css = groupColorSpaceStack; - if (css->knockout) { - knockoutCount--; - if (!knockoutCount) { - /* we don't need to track the shape anymore because - * we are not above any knockout groups */ - cairo_destroy(cairo_shape); - cairo_shape = NULL; - } - } - groupColorSpaceStack = css->next; - delete css; -} - - -void CairoOutputDev::clearSoftMask(GfxState * /*state*/) { - if (mask) - cairo_pattern_destroy(mask); - mask = NULL; -} - -/* Taken from cairo/doc/tutorial/src/singular.c */ -static void -get_singular_values (const cairo_matrix_t *matrix, - double *major, - double *minor) -{ - double xx = matrix->xx, xy = matrix->xy; - double yx = matrix->yx, yy = matrix->yy; - - double a = xx*xx+yx*yx; - double b = xy*xy+yy*yy; - double k = xx*xy+yx*yy; - - double f = (a+b) * .5; - double g = (a-b) * .5; - double delta = sqrt (g*g + k*k); - - if (major) - *major = sqrt (f + delta); - if (minor) - *minor = sqrt (f - delta); -} - -void CairoOutputDev::getScaledSize(const cairo_matrix_t *matrix, - int orig_width, - int orig_height, - int *scaledWidth, - int *scaledHeight) -{ - double xScale; - double yScale; - if (orig_width > orig_height) - get_singular_values (matrix, &xScale, &yScale); - else - get_singular_values (matrix, &yScale, &xScale); - - int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */ - if (xScale >= 0) { - tx = splashRound(matrix->x0 - 0.01); - tx2 = splashRound(matrix->x0 + xScale + 0.01) - 1; - } else { - tx = splashRound(matrix->x0 + 0.01) - 1; - tx2 = splashRound(matrix->x0 + xScale - 0.01); - } - *scaledWidth = abs(tx2 - tx) + 1; - //scaledWidth = splashRound(fabs(xScale)); - if (*scaledWidth == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - *scaledWidth = 1; - } - if (yScale >= 0) { - ty = splashFloor(matrix->y0 + 0.01); - ty2 = splashCeil(matrix->y0 + yScale - 0.01); - } else { - ty = splashCeil(matrix->y0 - 0.01); - ty2 = splashFloor(matrix->y0 + yScale + 0.01); - } - *scaledHeight = abs(ty2 - ty); - if (*scaledHeight == 0) { - *scaledHeight = 1; - } -} - -cairo_filter_t -CairoOutputDev::getFilterForSurface(cairo_surface_t *image, - GBool interpolate) -{ - if (interpolate) - return CAIRO_FILTER_BILINEAR; - - int orig_width = cairo_image_surface_get_width (image); - int orig_height = cairo_image_surface_get_height (image); - if (orig_width == 0 || orig_height == 0) - return CAIRO_FILTER_NEAREST; - - /* When printing, don't change the interpolation. */ - if (printing) - return CAIRO_FILTER_NEAREST; - - cairo_matrix_t matrix; - cairo_get_matrix(cairo, &matrix); - int scaled_width, scaled_height; - getScaledSize (&matrix, orig_width, orig_height, &scaled_width, &scaled_height); - - /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */ - if (scaled_width / orig_width >= 4 || scaled_height / orig_height >= 4) - return CAIRO_FILTER_NEAREST; - - return CAIRO_FILTER_BILINEAR; -} - -void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg) { - - /* FIXME: Doesn't the image mask support any colorspace? */ - cairo_set_source (cairo, fill_pattern); - - /* work around a cairo bug when scaling 1x1 surfaces */ - if (width == 1 && height == 1) { - ImageStream *imgStr; - Guchar pix; - int invert_bit; - - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - imgStr->getPixel(&pix); - imgStr->close(); - delete imgStr; - - invert_bit = invert ? 1 : 0; - if (pix ^ invert_bit) - return; - - cairo_save (cairo); - cairo_rectangle (cairo, 0., 0., width, height); - cairo_fill (cairo); - cairo_restore (cairo); - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_rectangle (cairo_shape, 0., 0., width, height); - cairo_fill (cairo_shape); - cairo_restore (cairo_shape); - } - return; - } - - /* shape is 1.0 for painted areas, 0.0 for unpainted ones */ - - cairo_matrix_t matrix; - cairo_get_matrix (cairo, &matrix); - //XXX: it is possible that we should only do sub pixel positioning if - // we are rendering fonts */ - if (!printing && prescaleImages - /* not rotated */ - && matrix.xy == 0 && matrix.yx == 0 - /* axes not flipped / not 180 deg rotated */ - && matrix.xx > 0 && (upsideDown() ? -1 : 1) * matrix.yy > 0) { - drawImageMaskPrescaled(state, ref, str, width, height, invert, interpolate, inlineImg); - } else { - drawImageMaskRegular(state, ref, str, width, height, invert, interpolate, inlineImg); - } - -} - -void CairoOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg, double *baseMatrix) { - - /* FIXME: Doesn't the image mask support any colorspace? */ - cairo_set_source (cairo, fill_pattern); - - /* work around a cairo bug when scaling 1x1 surfaces */ - if (width == 1 && height == 1) { - ImageStream *imgStr; - Guchar pix; - int invert_bit; - - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - imgStr->getPixel(&pix); - imgStr->close(); - delete imgStr; - - invert_bit = invert ? 1 : 0; - if (pix ^ invert_bit) - return; - - cairo_save (cairo); - cairo_rectangle (cairo, 0., 0., width, height); - cairo_fill (cairo); - cairo_restore (cairo); - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_rectangle (cairo_shape, 0., 0., width, height); - cairo_fill (cairo_shape); - cairo_restore (cairo_shape); - } - return; - } - - cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA); - - /* shape is 1.0 for painted areas, 0.0 for unpainted ones */ - - cairo_matrix_t matrix; - cairo_get_matrix (cairo, &matrix); - //XXX: it is possible that we should only do sub pixel positioning if - // we are rendering fonts */ - if (!printing && prescaleImages && matrix.xy == 0.0 && matrix.yx == 0.0) { - drawImageMaskPrescaled(state, ref, str, width, height, invert, gFalse, inlineImg); - } else { - drawImageMaskRegular(state, ref, str, width, height, invert, gFalse, inlineImg); - } - - if (state->getFillColorSpace()->getMode() == csPattern) { - cairo_set_source_rgb (cairo, 1, 1, 1); - cairo_set_matrix (cairo, &mask_matrix); - cairo_mask (cairo, mask); - } - - if (mask) - cairo_pattern_destroy (mask); - mask = cairo_pop_group (cairo); - - saveState(state); - double bbox[4] = {0,0,1,1}; // dummy - beginTransparencyGroup(state, bbox, state->getFillColorSpace(), - gTrue, gFalse, gFalse); -} - -void CairoOutputDev::unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) { - double bbox[4] = {0,0,1,1}; // dummy - - endTransparencyGroup(state); - restoreState(state); - paintTransparencyGroup(state, bbox); - clearSoftMask(state); -} - -void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg) { - unsigned char *buffer; - unsigned char *dest; - cairo_surface_t *image; - cairo_pattern_t *pattern; - int x, y, i, bit; - ImageStream *imgStr; - Guchar *pix; - cairo_matrix_t matrix; - int invert_bit; - int row_stride; - cairo_filter_t filter; - - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - - image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height); - if (cairo_surface_status (image)) - goto cleanup; - - buffer = cairo_image_surface_get_data (image); - row_stride = cairo_image_surface_get_stride (image); - - invert_bit = invert ? 1 : 0; - - for (y = 0; y < height; y++) { - pix = imgStr->getLine(); - dest = buffer + y * row_stride; - i = 0; - bit = 0; - for (x = 0; x < width; x++) { - if (bit == 0) - dest[i] = 0; - if (!(pix[x] ^ invert_bit)) { -#ifdef WORDS_BIGENDIAN - dest[i] |= (1 << (7 - bit)); -#else - dest[i] |= (1 << bit); -#endif - } - bit++; - if (bit > 7) { - bit = 0; - i++; - } - } - } - - filter = getFilterForSurface (image, interpolate); - - cairo_surface_mark_dirty (image); - pattern = cairo_pattern_create_for_surface (image); - cairo_surface_destroy (image); - if (cairo_pattern_status (pattern)) - goto cleanup; - - LOG (printf ("drawImageMask %dx%d\n", width, height)); - - cairo_pattern_set_filter (pattern, filter); - - if (!printing) - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - - cairo_matrix_init_translate (&matrix, 0, height); - cairo_matrix_scale (&matrix, width, -height); - cairo_pattern_set_matrix (pattern, &matrix); - if (cairo_pattern_status (pattern)) { - cairo_pattern_destroy (pattern); - goto cleanup; - } - - if (state->getFillColorSpace()->getMode() == csPattern) { - mask = cairo_pattern_reference (pattern); - cairo_get_matrix (cairo, &mask_matrix); - } else if (!printing) { - cairo_save (cairo); - cairo_rectangle (cairo, 0., 0., 1., 1.); - cairo_clip (cairo); - cairo_mask (cairo, pattern); - cairo_restore (cairo); - } else { - cairo_mask (cairo, pattern); - } - - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_set_source (cairo_shape, pattern); - if (!printing) { - cairo_rectangle (cairo_shape, 0., 0., 1., 1.); - cairo_fill (cairo_shape); - } else { - cairo_mask (cairo_shape, pattern); - } - cairo_restore (cairo_shape); - } - - cairo_pattern_destroy (pattern); - -cleanup: - imgStr->close(); - delete imgStr; -} - - -void CairoOutputDev::drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg) { - unsigned char *buffer; - cairo_surface_t *image; - cairo_pattern_t *pattern; - ImageStream *imgStr; - Guchar *pix; - cairo_matrix_t matrix; - int invert_bit; - int row_stride; - - /* cairo does a very poor job of scaling down images so we scale them ourselves */ - - LOG (printf ("drawImageMaskPrescaled %dx%d\n", width, height)); - - /* this scaling code is adopted from the splash image scaling code */ - cairo_get_matrix(cairo, &matrix); -#if 0 - printf("[%f %f], [%f %f], %f %f\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0); -#endif - /* this whole computation should be factored out */ - double xScale = matrix.xx; - double yScale = matrix.yy; - int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */ - int scaledHeight; - int scaledWidth; - if (xScale >= 0) { - tx = splashRound(matrix.x0 - 0.01); - tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1; - } else { - tx = splashRound(matrix.x0 + 0.01) - 1; - tx2 = splashRound(matrix.x0 + xScale - 0.01); - } - scaledWidth = abs(tx2 - tx) + 1; - //scaledWidth = splashRound(fabs(xScale)); - if (scaledWidth == 0) { - // technically, this should draw nothing, but it generally seems - // better to draw a one-pixel-wide stripe rather than throwing it - // away - scaledWidth = 1; - } - if (yScale >= 0) { - ty = splashFloor(matrix.y0 + 0.01); - ty2 = splashCeil(matrix.y0 + yScale - 0.01); - } else { - ty = splashCeil(matrix.y0 - 0.01); - ty2 = splashFloor(matrix.y0 + yScale + 0.01); - } - scaledHeight = abs(ty2 - ty); - if (scaledHeight == 0) { - scaledHeight = 1; - } -#if 0 - printf("xscale: %g, yscale: %g\n", xScale, yScale); - printf("width: %d, height: %d\n", width, height); - printf("scaledWidth: %d, scaledHeight: %d\n", scaledWidth, scaledHeight); -#endif - - /* compute the required padding */ - /* Padding is used to preserve the aspect ratio. - We compute total_pad to make (height+total_pad)/scaledHeight as close to height/yScale as possible */ - int head_pad = 0; - int tail_pad = 0; - int total_pad = splashRound(height*(scaledHeight/fabs(yScale)) - height); - - /* compute the two pieces of padding */ - if (total_pad > 0) { - //XXX: i'm not positive fabs() is correct - float tail_error = fabs(matrix.y0 - ty); - float head_error = fabs(ty2 - (matrix.y0 + yScale)); - float tail_fraction = tail_error/(tail_error + head_error); - tail_pad = splashRound(total_pad*tail_fraction); - head_pad = total_pad - tail_pad; - } else { - tail_pad = 0; - head_pad = 0; - } - int origHeight = height; - height += tail_pad; - height += head_pad; -#if 0 - printf("head_pad: %d tail_pad: %d\n", head_pad, tail_pad); - printf("origHeight: %d height: %d\n", origHeight, height); - printf("ty: %d, ty2: %d\n", ty, ty2); -#endif - - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - - invert_bit = invert ? 1 : 0; - - image = cairo_image_surface_create (CAIRO_FORMAT_A8, scaledWidth, scaledHeight); - if (cairo_surface_status (image)) { - imgStr->close(); - delete imgStr; - return; - } - - buffer = cairo_image_surface_get_data (image); - row_stride = cairo_image_surface_get_stride (image); - - int yp = height / scaledHeight; - int yq = height % scaledHeight; - int xp = width / scaledWidth; - int xq = width % scaledWidth; - int yt = 0; - int origHeight_c = origHeight; - /* use MIN() because yp might be > origHeight because of padding */ - unsigned char *pixBuf = (unsigned char *)malloc(MIN(yp+1, origHeight)*width); - int lastYStep = 1; - int total = 0; - for (int y = 0; y < scaledHeight; y++) { - // y scale Bresenham - int yStep = yp; - yt += yq; - - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row (s) from image ignoring the padding as appropriate - { - int n = (yp > 0) ? yStep : lastYStep; - total += n; - if (n > 0) { - unsigned char *p = pixBuf; - int head_pad_count = head_pad; - int origHeight_count = origHeight; - int tail_pad_count = tail_pad; - for (int i=0; igetLine(); - for (int j=0; j 0 ? yStep : 1; - int origN = n; - - /* compute the size of padding and pixels that will be used for this row */ - int head_pad_size = MIN(n, head_pad); - n -= head_pad_size; - head_pad -= MIN(head_pad_size, yStep); - - int pix_size = MIN(n, origHeight); - n -= pix_size; - origHeight -= MIN(pix_size, yStep); - - int tail_pad_size = MIN(n, tail_pad); - n -= tail_pad_size; - tail_pad -= MIN(tail_pad_size, yStep); - if (n != 0) { - printf("n = %d (%d %d %d)\n", n, head_pad_size, pix_size, tail_pad_size); - assert(n == 0); - } - - for (int x = 0; x < scaledWidth; ++x) { - int xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - int m = xStep > 0 ? xStep : 1; - float pixAcc0 = 0; - /* could m * head_pad_size * tail_pad_size overflow? */ - if (invert_bit) { - pixAcc0 += m * head_pad_size * tail_pad_size * 255; - } else { - pixAcc0 += m * head_pad_size * tail_pad_size * 0; - } - /* Accumulate all of the source pixels for the destination pixel */ - for (int i = 0; i < pix_size; ++i) { - for (int j = 0; j< m; ++j) { - if (xSrc + i*width + j > MIN(yp + 1, origHeight_c)*width) { - printf("%d > %d (%d %d %d %d) (%d %d %d)\n", xSrc + i*width + j, MIN(yp + 1, origHeight_c)*width, xSrc, i , width, j, yp, origHeight_c, width); - printf("%d %d %d\n", head_pad_size, pix_size, tail_pad_size); - assert(0 && "bad access\n"); - } - pixAcc0 += pixBuf[xSrc + i*width + j]; - } - } - buffer[y * row_stride + x] = splashFloor(pixAcc0 / (origN*m)); - xSrc += xStep; - x1 += 1; - } - - } - free(pixBuf); - - cairo_surface_mark_dirty (image); - pattern = cairo_pattern_create_for_surface (image); - cairo_surface_destroy (image); - if (cairo_pattern_status (pattern)) { - imgStr->close(); - delete imgStr; - return; - } - - /* we should actually be using CAIRO_FILTER_NEAREST here. However, - * cairo doesn't yet do minifaction filtering causing scaled down - * images with CAIRO_FILTER_NEAREST to look really bad */ - cairo_pattern_set_filter (pattern, - interpolate ? CAIRO_FILTER_BEST : CAIRO_FILTER_FAST); - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - - if (state->getFillColorSpace()->getMode() == csPattern) { - cairo_matrix_init_translate (&matrix, 0, scaledHeight); - cairo_matrix_scale (&matrix, scaledWidth, -scaledHeight); - cairo_pattern_set_matrix (pattern, &matrix); - if (cairo_pattern_status (pattern)) { - cairo_pattern_destroy (pattern); - imgStr->close(); - delete imgStr; - return; - } - - mask = cairo_pattern_reference (pattern); - cairo_get_matrix (cairo, &mask_matrix); - } else { - cairo_save (cairo); - - /* modify our current transformation so that the prescaled image - * goes where it is supposed to */ - cairo_get_matrix(cairo, &matrix); - cairo_scale(cairo, 1.0/matrix.xx, 1.0/matrix.yy); - // get integer co-ords - cairo_translate (cairo, tx - matrix.x0, ty2 - matrix.y0); - if (yScale > 0) - cairo_scale(cairo, 1, -1); - - cairo_rectangle (cairo, 0., 0., scaledWidth, scaledHeight); - cairo_clip (cairo); - cairo_mask (cairo, pattern); - - //cairo_get_matrix(cairo, &matrix); - //printf("mask at: [%f %f], [%f %f], %f %f\n\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0); - cairo_restore(cairo); - } - - if (cairo_shape) { - cairo_save (cairo_shape); - - /* modify our current transformation so that the prescaled image - * goes where it is supposed to */ - cairo_get_matrix(cairo_shape, &matrix); - cairo_scale(cairo_shape, 1.0/matrix.xx, 1.0/matrix.yy); - // get integer co-ords - cairo_translate (cairo_shape, tx - matrix.x0, ty2 - matrix.y0); - if (yScale > 0) - cairo_scale(cairo_shape, 1, -1); - - cairo_rectangle (cairo_shape, 0., 0., scaledWidth, scaledHeight); - cairo_fill (cairo_shape); - - cairo_restore(cairo_shape); - } - - cairo_pattern_destroy (pattern); - - imgStr->close(); - delete imgStr; -} - -void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref, - Stream *str, int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, int maskWidth, - int maskHeight, GBool maskInvert, - GBool maskInterpolate) -{ - ImageStream *maskImgStr, *imgStr; - int row_stride; - unsigned char *maskBuffer, *buffer; - unsigned char *maskDest; - unsigned int *dest; - cairo_surface_t *maskImage, *image; - cairo_pattern_t *maskPattern, *pattern; - cairo_matrix_t matrix; - cairo_matrix_t maskMatrix; - Guchar *pix; - int x, y; - int invert_bit; - cairo_filter_t filter; - cairo_filter_t maskFilter; - - maskImgStr = new ImageStream(maskStr, maskWidth, 1, 1); - maskImgStr->reset(); - - maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight); - if (cairo_surface_status (maskImage)) { - maskImgStr->close(); - delete maskImgStr; - return; - } - - maskBuffer = cairo_image_surface_get_data (maskImage); - row_stride = cairo_image_surface_get_stride (maskImage); - - invert_bit = maskInvert ? 1 : 0; - - for (y = 0; y < maskHeight; y++) { - pix = maskImgStr->getLine(); - maskDest = maskBuffer + y * row_stride; - for (x = 0; x < maskWidth; x++) { - if (pix[x] ^ invert_bit) - *maskDest++ = 0; - else - *maskDest++ = 255; - } - } - - maskImgStr->close(); - delete maskImgStr; - - maskFilter = getFilterForSurface (maskImage, maskInterpolate); - - cairo_surface_mark_dirty (maskImage); - maskPattern = cairo_pattern_create_for_surface (maskImage); - cairo_surface_destroy (maskImage); - if (cairo_pattern_status (maskPattern)) - return; - -#if 0 - /* ICCBased color space doesn't do any color correction - * so check its underlying color space as well */ - int is_identity_transform; - is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || - (colorMap->getColorSpace()->getMode() == csICCBased && - ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB); -#endif - - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); - - image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); - if (cairo_surface_status (image)) - goto cleanup; - - buffer = cairo_image_surface_get_data (image); - row_stride = cairo_image_surface_get_stride (image); - for (y = 0; y < height; y++) { - dest = (unsigned int *) (buffer + y * row_stride); - pix = imgStr->getLine(); - colorMap->getRGBLine (pix, dest, width); - } - - filter = getFilterForSurface (image, interpolate); - - cairo_surface_mark_dirty (image); - pattern = cairo_pattern_create_for_surface (image); - cairo_surface_destroy (image); - if (cairo_pattern_status (pattern)) - goto cleanup; - - LOG (printf ("drawMaskedImage %dx%d\n", width, height)); - - cairo_pattern_set_filter (pattern, filter); - cairo_pattern_set_filter (maskPattern, maskFilter); - - if (!printing) { - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD); - } - - cairo_matrix_init_translate (&matrix, 0, height); - cairo_matrix_scale (&matrix, width, -height); - cairo_pattern_set_matrix (pattern, &matrix); - if (cairo_pattern_status (pattern)) { - cairo_pattern_destroy (pattern); - cairo_pattern_destroy (maskPattern); - goto cleanup; - } - - cairo_matrix_init_translate (&maskMatrix, 0, maskHeight); - cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight); - cairo_pattern_set_matrix (maskPattern, &maskMatrix); - if (cairo_pattern_status (maskPattern)) { - cairo_pattern_destroy (maskPattern); - cairo_pattern_destroy (pattern); - goto cleanup; - } - - if (!printing) { - cairo_save (cairo); - cairo_set_source (cairo, pattern); - cairo_rectangle (cairo, 0., 0., 1., 1.); - cairo_clip (cairo); - cairo_mask (cairo, maskPattern); - cairo_restore (cairo); - } else { - cairo_set_source (cairo, pattern); - cairo_mask (cairo, maskPattern); - } - - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_set_source (cairo_shape, pattern); - if (!printing) { - cairo_rectangle (cairo_shape, 0., 0., 1., 1.); - cairo_fill (cairo_shape); - } else { - cairo_mask (cairo_shape, pattern); - } - cairo_restore (cairo_shape); - } - - cairo_pattern_destroy (maskPattern); - cairo_pattern_destroy (pattern); - -cleanup: - imgStr->close(); - delete imgStr; -} - - -//XXX: is this affect by AIS(alpha is shape)? -void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap, - GBool maskInterpolate) -{ - ImageStream *maskImgStr, *imgStr; - int row_stride; - unsigned char *maskBuffer, *buffer; - unsigned char *maskDest; - unsigned int *dest; - cairo_surface_t *maskImage, *image; - cairo_pattern_t *maskPattern, *pattern; - cairo_matrix_t maskMatrix, matrix; - Guchar *pix; - int y; - cairo_filter_t filter; - cairo_filter_t maskFilter; - - maskImgStr = new ImageStream(maskStr, maskWidth, - maskColorMap->getNumPixelComps(), - maskColorMap->getBits()); - maskImgStr->reset(); - - maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight); - if (cairo_surface_status (maskImage)) { - maskImgStr->close(); - delete maskImgStr; - return; - } - - maskBuffer = cairo_image_surface_get_data (maskImage); - row_stride = cairo_image_surface_get_stride (maskImage); - for (y = 0; y < maskHeight; y++) { - maskDest = (unsigned char *) (maskBuffer + y * row_stride); - pix = maskImgStr->getLine(); - maskColorMap->getGrayLine (pix, maskDest, maskWidth); - } - - maskImgStr->close(); - delete maskImgStr; - - maskFilter = getFilterForSurface (maskImage, maskInterpolate); - - cairo_surface_mark_dirty (maskImage); - maskPattern = cairo_pattern_create_for_surface (maskImage); - cairo_surface_destroy (maskImage); - if (cairo_pattern_status (maskPattern)) - return; - -#if 0 - /* ICCBased color space doesn't do any color correction - * so check its underlying color space as well */ - int is_identity_transform; - is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || - (colorMap->getColorSpace()->getMode() == csICCBased && - ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB); -#endif - - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); - - image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); - if (cairo_surface_status (image)) - goto cleanup; - - buffer = cairo_image_surface_get_data (image); - row_stride = cairo_image_surface_get_stride (image); - for (y = 0; y < height; y++) { - dest = (unsigned int *) (buffer + y * row_stride); - pix = imgStr->getLine(); - colorMap->getRGBLine (pix, dest, width); - } - - filter = getFilterForSurface (image, interpolate); - - cairo_surface_mark_dirty (image); - - setMimeData(str, ref, image); - - pattern = cairo_pattern_create_for_surface (image); - cairo_surface_destroy (image); - if (cairo_pattern_status (pattern)) - goto cleanup; - - LOG (printf ("drawSoftMaskedImage %dx%d\n", width, height)); - - cairo_pattern_set_filter (pattern, filter); - cairo_pattern_set_filter (maskPattern, maskFilter); - - if (!printing) { - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD); - } - - cairo_matrix_init_translate (&matrix, 0, height); - cairo_matrix_scale (&matrix, width, -height); - cairo_pattern_set_matrix (pattern, &matrix); - if (cairo_pattern_status (pattern)) { - cairo_pattern_destroy (pattern); - cairo_pattern_destroy (maskPattern); - goto cleanup; - } - - cairo_matrix_init_translate (&maskMatrix, 0, maskHeight); - cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight); - cairo_pattern_set_matrix (maskPattern, &maskMatrix); - if (cairo_pattern_status (maskPattern)) { - cairo_pattern_destroy (maskPattern); - cairo_pattern_destroy (pattern); - goto cleanup; - } - - if (fill_opacity != 1.0) - cairo_push_group (cairo); - else - cairo_save (cairo); - - cairo_set_source (cairo, pattern); - if (!printing) { - cairo_rectangle (cairo, 0., 0., 1., 1.); - cairo_clip (cairo); - } - cairo_mask (cairo, maskPattern); - - if (fill_opacity != 1.0) { - cairo_pop_group_to_source (cairo); - cairo_save (cairo); - if (!printing) { - cairo_rectangle (cairo, 0., 0., 1., 1.); - cairo_clip (cairo); - } - cairo_paint_with_alpha (cairo, fill_opacity); - } - cairo_restore (cairo); - - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_set_source (cairo_shape, pattern); - if (!printing) { - cairo_rectangle (cairo_shape, 0., 0., 1., 1.); - cairo_fill (cairo_shape); - } else { - cairo_mask (cairo_shape, pattern); - } - cairo_restore (cairo_shape); - } - - cairo_pattern_destroy (maskPattern); - cairo_pattern_destroy (pattern); - -cleanup: - imgStr->close(); - delete imgStr; -} - -GBool CairoOutputDev::getStreamData (Stream *str, char **buffer, int *length) -{ - int len, i; - char *strBuffer; - - len = 0; - str->close(); - str->reset(); - while (str->getChar() != EOF) len++; - if (len == 0) - return gFalse; - - strBuffer = (char *)gmalloc (len); - - str->close(); - str->reset(); - for (i = 0; i < len; ++i) - strBuffer[i] = str->getChar(); - - *buffer = strBuffer; - *length = len; - - return gTrue; -} - -void CairoOutputDev::setMimeData(Stream *str, Object *ref, cairo_surface_t *image) -{ - char *strBuffer; - int len; - Object obj; - - if (!printing || !(str->getKind() == strDCT || str->getKind() == strJPX)) - return; - - // colorspace in stream dict may be different from colorspace in jpx - // data - if (str->getKind() == strJPX) { - GBool hasColorSpace = !str->getDict()->lookup("ColorSpace", &obj)->isNull(); - obj.free(); - if (hasColorSpace) - return; - } - - if (getStreamData (str->getNextStream(), &strBuffer, &len)) { - cairo_status_t st; - -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2) - if (ref && ref->isRef()) { - Ref imgRef = ref->getRef(); - GooString *surfaceId = new GooString("poppler-surface-"); - surfaceId->appendf("{0:d}-{1:d}", imgRef.gen, imgRef.num); - char *idBuffer = copyString(surfaceId->getCString()); - st = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_UNIQUE_ID, - (const unsigned char *)idBuffer, - surfaceId->getLength(), - gfree, idBuffer); - if (st) - gfree(idBuffer); - delete surfaceId; - } -#endif - - st = cairo_surface_set_mime_data (image, - str->getKind() == strDCT ? - CAIRO_MIME_TYPE_JPEG : CAIRO_MIME_TYPE_JP2, - (const unsigned char *)strBuffer, len, - gfree, strBuffer); - if (st) - gfree (strBuffer); - } -} - -class RescaleDrawImage : public CairoRescaleBox { -private: - ImageStream *imgStr; - GfxRGB *lookup; - int width; - GfxImageColorMap *colorMap; - int *maskColors; - int current_row; - -public: - cairo_surface_t *getSourceImage(Stream *str, - int widthA, int height, - int scaledWidth, int scaledHeight, - GBool printing, - GfxImageColorMap *colorMapA, - int *maskColorsA) { - cairo_surface_t *image = NULL; - int i; - - lookup = NULL; - colorMap = colorMapA; - maskColors = maskColorsA; - width = widthA; - current_row = -1; - - /* TODO: Do we want to cache these? */ - imgStr = new ImageStream(str, width, - colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); - -#if 0 - /* ICCBased color space doesn't do any color correction - * so check its underlying color space as well */ - int is_identity_transform; - is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB || - (colorMap->getColorSpace()->getMode() == csICCBased && - ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB); -#endif - - // special case for one-channel (monochrome/gray/separation) images: - // build a lookup table here - if (colorMap->getNumPixelComps() == 1) { - int n; - Guchar pix; - - n = 1 << colorMap->getBits(); - lookup = (GfxRGB *)gmallocn(n, sizeof(GfxRGB)); - for (i = 0; i < n; ++i) { - pix = (Guchar)i; - - colorMap->getRGB(&pix, &lookup[i]); - } - } - - if (printing || scaledWidth >= width || scaledHeight >= height) { - // No downscaling. Create cairo image containing the source image data. - unsigned char *buffer; - int stride; - - image = cairo_image_surface_create (maskColors ? - CAIRO_FORMAT_ARGB32 : - CAIRO_FORMAT_RGB24, - width, height); - if (cairo_surface_status (image)) - goto cleanup; - - buffer = cairo_image_surface_get_data (image); - stride = cairo_image_surface_get_stride (image); - for (int y = 0; y < height; y++) { - uint32_t *dest = (uint32_t *) (buffer + y * stride); - getRow(y, dest); - } - } else { - // // Downscaling required. Create cairo image the size of the - // rescaled image and // downscale the source image data into - // the cairo image. downScaleImage() will call getRow() to read - // source image data from the image stream. This avoids having - // to create an image the size of the source image which may - // exceed cairo's 32676x32767 image size limit (and also saves a - // lot of memory). - image = cairo_image_surface_create (maskColors ? - CAIRO_FORMAT_ARGB32 : - CAIRO_FORMAT_RGB24, - scaledWidth, scaledHeight); - if (cairo_surface_status (image)) - goto cleanup; - - downScaleImage(width, height, - scaledWidth, scaledHeight, - 0, 0, scaledWidth, scaledHeight, - image); - } - cairo_surface_mark_dirty (image); - - cleanup: - gfree(lookup); - imgStr->close(); - delete imgStr; - return image; - } - - void getRow(int row_num, uint32_t *row_data) { - int i; - Guchar *pix; - - if (row_num <= current_row) - return; - - while (current_row < row_num) { - pix = imgStr->getLine(); - current_row++; - } - - if (lookup) { - Guchar *p = pix; - GfxRGB rgb; - - for (i = 0; i < width; i++) { - rgb = lookup[*p]; - row_data[i] = - ((int) colToByte(rgb.r) << 16) | - ((int) colToByte(rgb.g) << 8) | - ((int) colToByte(rgb.b) << 0); - p++; - } - } else { - colorMap->getRGBLine (pix, row_data, width); - } - - if (maskColors) { - for (int x = 0; x < width; x++) { - bool is_opaque = false; - for (int i = 0; i < colorMap->getNumPixelComps(); ++i) { - if (pix[i] < maskColors[2*i] || - pix[i] > maskColors[2*i+1]) { - is_opaque = true; - break; - } - } - if (is_opaque) - *row_data |= 0xff000000; - else - *row_data = 0; - row_data++; - pix += colorMap->getNumPixelComps(); - } - } - } - -}; - -void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, - int widthA, int heightA, - GfxImageColorMap *colorMap, - GBool interpolate, - int *maskColors, GBool inlineImg) -{ - cairo_surface_t *image; - cairo_pattern_t *pattern, *maskPattern; - cairo_matrix_t matrix; - int width, height; - int scaledWidth, scaledHeight; - cairo_filter_t filter = CAIRO_FILTER_BILINEAR; - RescaleDrawImage rescale; - - LOG (printf ("drawImage %dx%d\n", widthA, heightA)); - - cairo_get_matrix(cairo, &matrix); - getScaledSize (&matrix, widthA, heightA, &scaledWidth, &scaledHeight); - image = rescale.getSourceImage(str, widthA, heightA, scaledWidth, scaledHeight, printing, colorMap, maskColors); - if (!image) - return; - - width = cairo_image_surface_get_width (image); - height = cairo_image_surface_get_height (image); - if (width == widthA && height == heightA) - filter = getFilterForSurface (image, interpolate); - - if (!inlineImg) /* don't read stream twice if it is an inline image */ - setMimeData(str, ref, image); - - pattern = cairo_pattern_create_for_surface (image); - cairo_surface_destroy (image); - if (cairo_pattern_status (pattern)) - return; - - cairo_pattern_set_filter (pattern, filter); - - if (!printing) - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); - - cairo_matrix_init_translate (&matrix, 0, height); - cairo_matrix_scale (&matrix, width, -height); - cairo_pattern_set_matrix (pattern, &matrix); - if (cairo_pattern_status (pattern)) { - cairo_pattern_destroy (pattern); - return; - } - - if (!mask && fill_opacity != 1.0) { - maskPattern = cairo_pattern_create_rgba (1., 1., 1., fill_opacity); - } else if (mask) { - maskPattern = cairo_pattern_reference (mask); - } else { - maskPattern = NULL; - } - - cairo_save (cairo); - cairo_set_source (cairo, pattern); - if (!printing) - cairo_rectangle (cairo, 0., 0., 1., 1.); - if (maskPattern) { - if (!printing) - cairo_clip (cairo); - cairo_set_matrix (cairo, &mask_matrix); - cairo_mask (cairo, maskPattern); - } else { - if (printing) - cairo_paint (cairo); - else - cairo_fill (cairo); - } - cairo_restore (cairo); - - cairo_pattern_destroy (maskPattern); - - if (cairo_shape) { - cairo_save (cairo_shape); - cairo_set_source (cairo_shape, pattern); - if (printing) { - cairo_paint (cairo_shape); - } else { - cairo_rectangle (cairo_shape, 0., 0., 1., 1.); - cairo_fill (cairo_shape); - } - cairo_restore (cairo_shape); - } - - cairo_pattern_destroy (pattern); -} - - -//------------------------------------------------------------------------ -// ImageOutputDev -//------------------------------------------------------------------------ - -CairoImageOutputDev::CairoImageOutputDev() -{ - images = NULL; - numImages = 0; - size = 0; - imgDrawCbk = NULL; - imgDrawCbkData = NULL; -} - -CairoImageOutputDev::~CairoImageOutputDev() -{ - int i; - - for (i = 0; i < numImages; i++) - delete images[i]; - gfree (images); -} - -void CairoImageOutputDev::saveImage(CairoImage *image) -{ - if (numImages >= size) { - size += 16; - images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *)); - } - images[numImages++] = image; -} - -void CairoImageOutputDev::getBBox(GfxState *state, int width, int height, - double *x1, double *y1, double *x2, double *y2) -{ - double *ctm = state->getCTM(); - cairo_matrix_t matrix; - cairo_matrix_init(&matrix, - ctm[0], ctm[1], - -ctm[2], -ctm[3], - ctm[2] + ctm[4], ctm[3] + ctm[5]); - - int scaledWidth, scaledHeight; - getScaledSize (&matrix, width, height, &scaledWidth, &scaledHeight); - - if (matrix.xx >= 0) { - *x1 = matrix.x0; - } else { - *x1 = matrix.x0 - scaledWidth; - } - *x2 = *x1 + scaledWidth; - - if (matrix.yy >= 0) { - *y1 = matrix.y0; - } else { - *y1 = matrix.y0 - scaledHeight; - } - *y2 = *y1 + scaledHeight; -} - -void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg) -{ - cairo_t *cr; - cairo_surface_t *surface; - double x1, y1, x2, y2; - CairoImage *image; - - getBBox(state, width, height, &x1, &y1, &x2, &y2); - - image = new CairoImage (x1, y1, x2, y2); - saveImage (image); - - if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - setCairo (cr); - cairo_translate (cr, 0, height); - cairo_scale (cr, width, -height); - - CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg); - image->setImage (surface); - - setCairo (NULL); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } -} - -void CairoImageOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg, double *baseMatrix) -{ - cairo_t *cr; - cairo_surface_t *surface; - double x1, y1, x2, y2; - CairoImage *image; - - getBBox(state, width, height, &x1, &y1, &x2, &y2); - - image = new CairoImage (x1, y1, x2, y2); - saveImage (image); - - if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - setCairo (cr); - cairo_translate (cr, 0, height); - cairo_scale (cr, width, -height); - - CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, inlineImg, gFalse); - if (state->getFillColorSpace()->getMode() == csPattern) { - cairo_mask (cairo, mask); - } - image->setImage (surface); - - setCairo (NULL); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } -} - -void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg) -{ - cairo_t *cr; - cairo_surface_t *surface; - double x1, y1, x2, y2; - CairoImage *image; - - getBBox(state, width, height, &x1, &y1, &x2, &y2); - - image = new CairoImage (x1, y1, x2, y2); - saveImage (image); - - if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - setCairo (cr); - cairo_translate (cr, 0, height); - cairo_scale (cr, width, -height); - - CairoOutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate, maskColors, inlineImg); - image->setImage (surface); - - setCairo (NULL); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } -} - -void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap, - GBool maskInterpolate) -{ - cairo_t *cr; - cairo_surface_t *surface; - double x1, y1, x2, y2; - CairoImage *image; - - getBBox(state, width, height, &x1, &y1, &x2, &y2); - - image = new CairoImage (x1, y1, x2, y2); - saveImage (image); - - if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - setCairo (cr); - cairo_translate (cr, 0, height); - cairo_scale (cr, width, -height); - - CairoOutputDev::drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate, - maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate); - image->setImage (surface); - - setCairo (NULL); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } -} - -void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GBool maskInvert, GBool maskInterpolate) -{ - cairo_t *cr; - cairo_surface_t *surface; - double x1, y1, x2, y2; - CairoImage *image; - - getBBox(state, width, height, &x1, &y1, &x2, &y2); - - image = new CairoImage (x1, y1, x2, y2); - saveImage (image); - - if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) { - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - setCairo (cr); - cairo_translate (cr, 0, height); - cairo_scale (cr, width, -height); - - CairoOutputDev::drawMaskedImage(state, ref, str, width, height, colorMap, interpolate, - maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate); - image->setImage (surface); - - setCairo (NULL); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } -} diff --git a/src/CairoOutputDev/CairoOutputDev.h b/src/CairoOutputDev/CairoOutputDev.h deleted file mode 100644 index c9ae33d..0000000 --- a/src/CairoOutputDev/CairoOutputDev.h +++ /dev/null @@ -1,507 +0,0 @@ -//======================================================================== -// -// CairoOutputDev.h -// -// Copyright 2003 Glyph & Cog, LLC -// Copyright 2004 Red Hat, INC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005-2008 Jeff Muizelaar -// Copyright (C) 2005, 2006 Kristian Høgsberg -// Copyright (C) 2005 Nickolay V. Shmyrev -// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos -// Copyright (C) 2008, 2009, 2011-2013 Adrian Johnson -// Copyright (C) 2008 Michael Vrable -// Copyright (C) 2010-2013 Thomas Freitag -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef CAIROOUTPUTDEV_H -#define CAIROOUTPUTDEV_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "goo/gtypes.h" -#include -#include "OutputDev.h" -#include "TextOutputDev.h" -#include "GfxState.h" - -class PDFDoc; -class GfxState; -class GfxPath; -class Gfx8BitFont; -struct GfxRGB; -class CairoFontEngine; -class CairoFont; - -//------------------------------------------------------------------------ - -//------------------------------------------------------------------------ -// CairoImage -//------------------------------------------------------------------------ -class CairoImage { -public: - // Constructor. - CairoImage (double x1, double y1, double x2, double y2); - - // Destructor. - ~CairoImage (); - - // Set the image cairo surface - void setImage (cairo_surface_t *image); - - // Get the image cairo surface - cairo_surface_t *getImage () const { return image; } - - // Get the image rectangle - void getRect (double *xa1, double *ya1, double *xa2, double *ya2) - { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } - -private: - cairo_surface_t *image; // image cairo surface - double x1, y1; // upper left corner - double x2, y2; // lower right corner -}; - - -//------------------------------------------------------------------------ -// CairoOutputDev -//------------------------------------------------------------------------ - -class CairoOutputDev: public OutputDev { -public: - - // Constructor. - CairoOutputDev(); - - // Destructor. - virtual ~CairoOutputDev(); - - //----- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gTrue; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gTrue; } - - // Does this device use tilingPatternFill()? If this returns false, - // tiling pattern fills will be reduced to a series of other drawing - // operations. - virtual GBool useTilingPatternFill() { return gTrue; } - - // Does this device use functionShadedFill(), axialShadedFill(), and - // radialShadedFill()? If this returns false, these shaded fills - // will be reduced to a series of other drawing operations. -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) - virtual GBool useShadedFills(int type) { return type <= 7; } -#else - virtual GBool useShadedFills(int type) { return type < 4; } -#endif - - // Does this device use FillColorStop()? - virtual GBool useFillColorStop() { return gTrue; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gFalse; } - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state, XRef *xref); - - // End a page. - virtual void endPage(); - - //----- save/restore graphics state - virtual void saveState(GfxState *state); - virtual void restoreState(GfxState *state); - - //----- update graphics state - virtual void updateAll(GfxState *state); - virtual void setDefaultCTM(double *ctm); - virtual void updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32); - virtual void updateLineDash(GfxState *state); - virtual void updateFlatness(GfxState *state); - virtual void updateLineJoin(GfxState *state); - virtual void updateLineCap(GfxState *state); - virtual void updateMiterLimit(GfxState *state); - virtual void updateLineWidth(GfxState *state); - virtual void updateFillColor(GfxState *state); - virtual void updateStrokeColor(GfxState *state); - virtual void updateFillOpacity(GfxState *state); - virtual void updateStrokeOpacity(GfxState *state); - virtual void updateFillColorStop(GfxState *state, double offset); - virtual void updateBlendMode(GfxState *state); - - //----- update text state - virtual void updateFont(GfxState *state); - - //----- path painting - virtual void stroke(GfxState *state); - virtual void fill(GfxState *state); - virtual void eoFill(GfxState *state); - virtual void clipToStrokePath(GfxState *state); - virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str, - double *pmat, int paintType, int tilingType, Dict *resDict, - double *mat, double *bbox, - int x0, int y0, int x1, int y1, - double xStep, double yStep); - virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax); - virtual GBool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading); - virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax); - virtual GBool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading); -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) - virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading); - virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading); -#endif - - //----- path clipping - virtual void clip(GfxState *state); - virtual void eoClip(GfxState *state); - - //----- text drawing - void beginString(GfxState *state, GooString *s); - void endString(GfxState *state); - void drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, int nBytes, Unicode *u, int uLen); - void beginActualText(GfxState *state, GooString *text); - void endActualText(GfxState *state); - - virtual GBool beginType3Char(GfxState *state, double x, double y, - double dx, double dy, - CharCode code, Unicode *u, int uLen); - virtual void endType3Char(GfxState *state); - virtual void beginTextObject(GfxState *state); - virtual void endTextObject(GfxState *state); - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, GBool interpolate, - GBool inlineImg); - virtual void setSoftMaskFromImageMask(GfxState *state, - Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg, double *baseMatrix); - virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix); - void drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, GBool interpolate, - GBool inlineImg); - void drawImageMaskRegular(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, GBool interpolate, - GBool inlineImg); - - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg); - virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap, - GBool maskInterpolate); - - virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GBool maskInvert, GBool maskInterpolate); - - //----- transparency groups and soft masks - virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/, - GfxColorSpace * /*blendingColorSpace*/, - GBool /*isolated*/, GBool /*knockout*/, - GBool /*forSoftMask*/); - virtual void endTransparencyGroup(GfxState * /*state*/); - void popTransparencyGroup(); - virtual void paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/); - virtual void setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/, - Function * /*transferFunc*/, GfxColor * /*backdropColor*/); - virtual void clearSoftMask(GfxState * /*state*/); - - //----- Type 3 font operators - virtual void type3D0(GfxState *state, double wx, double wy); - virtual void type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury); - - //----- special access - - // Called to indicate that a new PDF document has been loaded. - void startDoc(PDFDoc *docA, CairoFontEngine *fontEngine = NULL); - - GBool isReverseVideo() { return gFalse; } - - void setCairo (cairo_t *cr); - void setTextPage (TextPage *text); - void setPrinting (GBool printing) { this->printing = printing; needFontUpdate = gTrue; } - - void setInType3Char(GBool inType3Char) { this->inType3Char = inType3Char; } - void getType3GlyphWidth (double *wx, double *wy) { *wx = t3_glyph_wx; *wy = t3_glyph_wy; } - GBool hasType3GlyphBBox () { return t3_glyph_has_bbox; } - double *getType3GlyphBBox () { return t3_glyph_bbox; } - -protected: - void doPath(cairo_t *cairo, GfxState *state, GfxPath *path); - cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface); - void getScaledSize(const cairo_matrix_t *matrix, - int orig_width, int orig_height, - int *scaledWidth, int *scaledHeight); - cairo_filter_t getFilterForSurface(cairo_surface_t *image, - GBool interpolate); - GBool getStreamData (Stream *str, char **buffer, int *length); - void setMimeData(Stream *str, Object *ref, cairo_surface_t *image); - void fillToStrokePathClip(GfxState *state); - void alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y); - - GfxRGB fill_color, stroke_color; - cairo_pattern_t *fill_pattern, *stroke_pattern; - double fill_opacity; - double stroke_opacity; - GBool stroke_adjust; - GBool adjusted_stroke_width; - GBool align_stroke_coords; - CairoFont *currentFont; - XRef *xref; - - struct StrokePathClip { - GfxPath *path; - cairo_matrix_t ctm; - double line_width; - double *dashes; - int dash_count; - double dash_offset; - cairo_line_cap_t cap; - cairo_line_join_t join; - double miter; - } *strokePathClip; - - PDFDoc *doc; // the current document - - static FT_Library ft_lib; - static GBool ft_lib_initialized; - - CairoFontEngine *fontEngine; - GBool fontEngine_owner; - - cairo_t *cairo; - cairo_matrix_t orig_matrix; - GBool needFontUpdate; // set when the font needs to be updated - GBool printing; - GBool use_show_text_glyphs; - cairo_surface_t *surface; - cairo_glyph_t *glyphs; - int glyphCount; - cairo_text_cluster_t *clusters; - int clusterCount; - char *utf8; - int utf8Count; - int utf8Max; - cairo_path_t *textClipPath; - GBool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2) - GBool inType3Char; // inside a Type 3 CharProc - double t3_glyph_wx, t3_glyph_wy; - GBool t3_glyph_has_bbox; - double t3_glyph_bbox[4]; - - GBool prescaleImages; - - TextPage *text; // text for the current page - ActualText *actualText; - - cairo_pattern_t *group; - cairo_pattern_t *shape; - cairo_pattern_t *mask; - cairo_matrix_t mask_matrix; - cairo_surface_t *cairo_shape_surface; - cairo_t *cairo_shape; - int knockoutCount; - struct ColorSpaceStack { - GBool knockout; - GfxColorSpace *cs; - cairo_matrix_t group_matrix; - struct ColorSpaceStack *next; - } * groupColorSpaceStack; - - struct MaskStack { - cairo_pattern_t *mask; - cairo_matrix_t mask_matrix; - struct MaskStack *next; - } *maskStack; - -}; - -//------------------------------------------------------------------------ -// CairoImageOutputDev -//------------------------------------------------------------------------ - -//XXX: this should ideally not inherit from CairoOutputDev but use it instead perhaps -class CairoImageOutputDev: public CairoOutputDev { -public: - - // Constructor. - CairoImageOutputDev(); - - // Destructor. - virtual ~CairoImageOutputDev(); - - //----- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gTrue; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gFalse; } - - // Does this device use tilingPatternFill()? If this returns false, - // tiling pattern fills will be reduced to a series of other drawing - // operations. - virtual GBool useTilingPatternFill() { return gTrue; } - - // Does this device use functionShadedFill(), axialShadedFill(), and - // radialShadedFill()? If this returns false, these shaded fills - // will be reduced to a series of other drawing operations. -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2) - virtual GBool useShadedFills(int type) { return type <= 7; } -#else - virtual GBool useShadedFills(int type) { return type < 4; } -#endif - - // Does this device use FillColorStop()? - virtual GBool useFillColorStop() { return gFalse; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gFalse; } - - // Does this device need non-text content? - virtual GBool needNonText() { return gTrue; } - - //----- save/restore graphics state - virtual void saveState(GfxState *state) { } - virtual void restoreState(GfxState *state) { } - - //----- update graphics state - virtual void updateAll(GfxState *state) { } - virtual void setDefaultCTM(double *ctm) { } - virtual void updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32) { } - virtual void updateLineDash(GfxState *state) { } - virtual void updateFlatness(GfxState *state) { } - virtual void updateLineJoin(GfxState *state) { } - virtual void updateLineCap(GfxState *state) { } - virtual void updateMiterLimit(GfxState *state) { } - virtual void updateLineWidth(GfxState *state) { } - virtual void updateFillColor(GfxState *state) { } - virtual void updateStrokeColor(GfxState *state) { } - virtual void updateFillOpacity(GfxState *state) { } - virtual void updateStrokeOpacity(GfxState *state) { } - virtual void updateBlendMode(GfxState *state) { } - - //----- update text state - virtual void updateFont(GfxState *state) { } - - //----- path painting - virtual void stroke(GfxState *state) { } - virtual void fill(GfxState *state) { } - virtual void eoFill(GfxState *state) { } - virtual void clipToStrokePath(GfxState *state) { } - virtual GBool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, Object *str, - double *pmat, int paintType, int tilingType, Dict *resDict, - double *mat, double *bbox, - int x0, int y0, int x1, int y1, - double xStep, double yStep) { return gTrue; } - virtual GBool axialShadedFill(GfxState *state, - GfxAxialShading *shading, - double tMin, double tMax) { return gTrue; } - virtual GBool radialShadedFill(GfxState *state, - GfxRadialShading *shading, - double sMin, double sMax) { return gTrue; } - - //----- path clipping - virtual void clip(GfxState *state) { } - virtual void eoClip(GfxState *state) { } - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg); - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg); - virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GfxImageColorMap *maskColorMap, - GBool maskInterpolate); - virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, - int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, - Stream *maskStr, - int maskWidth, int maskHeight, - GBool maskInvert, GBool maskInterpolate); - virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg, double *baseMatrix); - virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {} - - - //----- transparency groups and soft masks - virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/, - GfxColorSpace * /*blendingColorSpace*/, - GBool /*isolated*/, GBool /*knockout*/, - GBool /*forSoftMask*/) {} - virtual void endTransparencyGroup(GfxState * /*state*/) {} - virtual void paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {} - virtual void setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/, - Function * /*transferFunc*/, GfxColor * /*backdropColor*/) {} - virtual void clearSoftMask(GfxState * /*state*/) {} - - //----- Image list - // By default images are not rendred - void setImageDrawDecideCbk(GBool (*cbk)(int img_id, void *data), - void *data) { imgDrawCbk = cbk; imgDrawCbkData = data; } - // Iterate through list of images. - int getNumImages() const { return numImages; } - CairoImage *getImage(int i) const { return images[i]; } - -private: - void saveImage(CairoImage *image); - void getBBox(GfxState *state, int width, int height, - double *x1, double *y1, double *x2, double *y2); - - CairoImage **images; - int numImages; - int size; - GBool (*imgDrawCbk)(int img_id, void *data); - void *imgDrawCbkData; -}; - -#endif diff --git a/src/CairoOutputDev/CairoRescaleBox.cc b/src/CairoOutputDev/CairoRescaleBox.cc deleted file mode 100644 index 3d19689..0000000 --- a/src/CairoOutputDev/CairoRescaleBox.cc +++ /dev/null @@ -1,377 +0,0 @@ -/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ -/* - * Copyright © 2009 Mozilla Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Mozilla Corporation not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Mozilla Corporation makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT - * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - * - * Author: Jeff Muizelaar, Mozilla Corp. - */ - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2012 Hib Eris -// Copyright (C) 2012 Adrian Johnson -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - - -/* This implements a box filter that supports non-integer box sizes */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include "goo/gmem.h" -#include "CairoRescaleBox.h" - - -/* we work in fixed point where 1. == 1 << 24 */ -#define FIXED_SHIFT 24 - - -static void downsample_row_box_filter ( - int start, int width, - uint32_t *src, uint32_t *dest, - int coverage[], int pixel_coverage) -{ - /* we need an array of the pixel contribution of each destination pixel on the boundaries. - * we invert the value to get the value on the other size of the box */ - /* - - value = a * contribution * 1/box_size - value += a * 1/box_size - value += a * 1/box_size - value += a * 1/box_size - value += a * (1 - contribution) * 1/box_size - a * (1/box_size - contribution * 1/box_size) - - box size is constant - - - value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size - contribution_b = (1 - contribution_a) - = (1 - contribution_a_next) - */ - - /* box size = ceil(src_width/dest_width) */ - int x = 0; - - /* skip to start */ - /* XXX: it might be possible to do this directly instead of iteratively, however - * the iterative solution is simple */ - while (x < start) - { - int box = 1 << FIXED_SHIFT; - int start_coverage = coverage[x]; - box -= start_coverage; - src++; - while (box >= pixel_coverage) - { - src++; - box -= pixel_coverage; - } - x++; - } - - while (x < start + width) - { - uint32_t a = 0; - uint32_t r = 0; - uint32_t g = 0; - uint32_t b = 0; - int box = 1 << FIXED_SHIFT; - int start_coverage = coverage[x]; - - a = ((*src >> 24) & 0xff) * start_coverage; - r = ((*src >> 16) & 0xff) * start_coverage; - g = ((*src >> 8) & 0xff) * start_coverage; - b = ((*src >> 0) & 0xff) * start_coverage; - src++; - x++; - box -= start_coverage; - - while (box >= pixel_coverage) - { - a += ((*src >> 24) & 0xff) * pixel_coverage; - r += ((*src >> 16) & 0xff) * pixel_coverage; - g += ((*src >> 8) & 0xff) * pixel_coverage; - b += ((*src >> 0) & 0xff) * pixel_coverage; - src++; - - box -= pixel_coverage; - } - - /* multiply by whatever is leftover - * this ensures that we don't bias down. - * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */ - if (box > 0) - { - a += ((*src >> 24) & 0xff) * box; - r += ((*src >> 16) & 0xff) * box; - g += ((*src >> 8) & 0xff) * box; - b += ((*src >> 0) & 0xff) * box; - } - - a >>= FIXED_SHIFT; - r >>= FIXED_SHIFT; - g >>= FIXED_SHIFT; - b >>= FIXED_SHIFT; - - *dest = (a << 24) | (r << 16) | (g << 8) | b; - dest++; - } -} - -static void downsample_columns_box_filter ( - int n, - int start_coverage, - int pixel_coverage, - uint32_t *src, uint32_t *dest) -{ - int stride = n; - while (n--) { - uint32_t a = 0; - uint32_t r = 0; - uint32_t g = 0; - uint32_t b = 0; - uint32_t *column_src = src; - int box = 1 << FIXED_SHIFT; - - a = ((*column_src >> 24) & 0xff) * start_coverage; - r = ((*column_src >> 16) & 0xff) * start_coverage; - g = ((*column_src >> 8) & 0xff) * start_coverage; - b = ((*column_src >> 0) & 0xff) * start_coverage; - column_src += stride; - box -= start_coverage; - - while (box >= pixel_coverage) - { - a += ((*column_src >> 24) & 0xff) * pixel_coverage; - r += ((*column_src >> 16) & 0xff) * pixel_coverage; - g += ((*column_src >> 8) & 0xff) * pixel_coverage; - b += ((*column_src >> 0) & 0xff) * pixel_coverage; - column_src += stride; - box -= pixel_coverage; - } - - if (box > 0) { - a += ((*column_src >> 24) & 0xff) * box; - r += ((*column_src >> 16) & 0xff) * box; - g += ((*column_src >> 8) & 0xff) * box; - b += ((*column_src >> 0) & 0xff) * box; - } - - a >>= FIXED_SHIFT; - r >>= FIXED_SHIFT; - g >>= FIXED_SHIFT; - b >>= FIXED_SHIFT; - - *dest = (a << 24) | (r << 16) | (g << 8) | b; - dest++; - src++; - } -} - -static int compute_coverage (int coverage[], int src_length, int dest_length) -{ - int i; - /* num = src_length/dest_length - total = sum(pixel) / num - - pixel * 1/num == pixel * dest_length / src_length - */ - /* the average contribution of each source pixel */ - int ratio = ((1 << 24)*(long long int)dest_length)/src_length; - /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length - * we'll need someplace to put the other bits. - * - * We want to ensure a + n*ratio < 1<<24 - * - * 1<<24 - * */ - - double scale = (double)src_length/dest_length; - - /* for each destination pixel compute the coverage of the left most pixel included in the box */ - /* I have a proof of this, which this margin is too narrow to contain */ - for (i=0; i= i*scale - - floor((i+1)*scale) - ceil(i*scale) <= scale - - further since: floor((i+1)*scale) - ceil(i*scale) is an integer - - therefore: - floor((i+1)*scale) - ceil(i*scale) <= floor(scale) - */ - - if (left_fract == 0.) - count--; - - /* compute how much the right-most pixel contributes */ - overage = ratio*(right_fract); - - /* the remainder is the the amount that the left-most pixel - * contributes */ - coverage[i] = (1<<24) - (count * ratio + overage); - } - - return ratio; -} - - -GBool CairoRescaleBox::downScaleImage(unsigned orig_width, unsigned orig_height, - signed scaled_width, signed scaled_height, - unsigned short int start_column, unsigned short int start_row, - unsigned short int width, unsigned short int height, - cairo_surface_t *dest_surface) { - int pixel_coverage_x, pixel_coverage_y; - int dest_y; - int src_y = 0; - uint32_t *scanline; - int *x_coverage = NULL; - int *y_coverage = NULL; - uint32_t *temp_buf = NULL; - GBool retval = gFalse; - unsigned int *dest; - int dst_stride; - - dest = (unsigned int *)cairo_image_surface_get_data (dest_surface); - dst_stride = cairo_image_surface_get_stride (dest_surface); - - scanline = (uint32_t*)gmallocn3 (orig_width, 1, sizeof(int)); - - x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int)); - y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int)); - - /* we need to allocate enough room for ceil(src_height/dest_height)+1 - Example: - src_height = 140 - dest_height = 50 - src_height/dest_height = 2.8 - - |-------------| 2.8 pixels - |----|----|----|----| 4 pixels - need to sample 3 pixels - - |-------------| 2.8 pixels - |----|----|----|----| 4 pixels - need to sample 4 pixels - */ - - temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t)); - - if (!x_coverage || !y_coverage || !scanline || !temp_buf) - goto cleanup; - - pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width); - pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height); - - assert (width + start_column <= scaled_width); - - - - /* skip the rows at the beginning */ - for (dest_y = 0; dest_y < start_row; dest_y++) - { - int box = 1 << FIXED_SHIFT; - int start_coverage_y = y_coverage[dest_y]; - box -= start_coverage_y; - src_y++; - while (box >= pixel_coverage_y) - { - box -= pixel_coverage_y; - src_y++; - } - } - - for (; dest_y < start_row + height; dest_y++) - { - int columns = 0; - int box = 1 << FIXED_SHIFT; - int start_coverage_y = y_coverage[dest_y]; - - getRow(src_y, scanline); - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - src_y++; - box -= start_coverage_y; - - while (box >= pixel_coverage_y) - { - getRow(src_y, scanline); - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - src_y++; - box -= pixel_coverage_y; - } - - /* downsample any leftovers */ - if (box > 0) - { - getRow(src_y, scanline); - downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x); - columns++; - } - - /* now scale the rows we just downsampled in the y direction */ - downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest); - dest += dst_stride / 4; - -// assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width); - } -// assert (src_y<=orig_height); - - retval = gTrue; - -cleanup: - free (x_coverage); - free (y_coverage); - free (temp_buf); - free (scanline); - - return retval; -} diff --git a/src/CairoOutputDev/CairoRescaleBox.h b/src/CairoOutputDev/CairoRescaleBox.h deleted file mode 100644 index 072e8a9..0000000 --- a/src/CairoOutputDev/CairoRescaleBox.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright © 2009 Mozilla Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Mozilla Corporation not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Mozilla Corporation makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT - * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - * - * Author: Jeff Muizelaar, Mozilla Corp. - */ - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2012 Adrian Johnson -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef CAIRO_RESCALE_BOX_H -#define CAIRO_RESCALE_BOX_H - -#include "goo/gtypes.h" -#include - -class CairoRescaleBox { -public: - - CairoRescaleBox() {}; - virtual ~CairoRescaleBox() {}; - - virtual GBool downScaleImage(unsigned orig_width, unsigned orig_height, - signed scaled_width, signed scaled_height, - unsigned short int start_column, unsigned short int start_row, - unsigned short int width, unsigned short int height, - cairo_surface_t *dest_surface); - - virtual void getRow(int row_num, uint32_t *row_data) = 0; - -}; - -#endif /* CAIRO_RESCALE_BOX_H */ diff --git a/src/pdf2htmlEX-config.h.in b/src/pdf2htmlEX-config.h.in index 09dc253..3071036 100644 --- a/src/pdf2htmlEX-config.h.in +++ b/src/pdf2htmlEX-config.h.in @@ -12,7 +12,7 @@ #include #define POPPLER_OLDER_THAN_0_23_0 @POPPLER_OLDER_THAN_0_23_0@ -#define HAVE_CAIRO @HAVE_CAIRO@ +#define ENABLE_SVG @ENABLE_SVG@ namespace pdf2htmlEX {