summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authormiklosh <miklosh@users.sourceforge.net>2007-08-09 13:04:00 +0000
committermiklosh <miklosh@users.sourceforge.net>2007-08-09 13:04:00 +0000
commite0c2afb13438f6c7494e395235e08dcde6c554a1 (patch)
tree083affebdf4e8c3fa0b732cfa7ef48badde10740 /src
parentFix unbalanced <b> tags in ru.po (diff)
downloadinkscape-e0c2afb13438f6c7494e395235e08dcde6c554a1.tar.gz
inkscape-e0c2afb13438f6c7494e395235e08dcde6c554a1.zip
Added support for the shading operator
(bzr r3439)
Diffstat (limited to 'src')
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.cpp74
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.h2
-rw-r--r--src/extension/internal/pdfinput/svg-builder.cpp59
-rw-r--r--src/extension/internal/pdfinput/svg-builder.h6
4 files changed, 122 insertions, 19 deletions
diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp
index 1d312c116..465350b78 100644
--- a/src/extension/internal/pdfinput/pdf-parser.cpp
+++ b/src/extension/internal/pdfinput/pdf-parser.cpp
@@ -298,6 +298,7 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
state = new GfxState(72.0, 72.0, cropBox, rotate, gTrue);
fontChanged = gFalse;
clip = clipNone;
+ lastClipPath = NULL;
ignoreUndef = 0;
operatorHistory = NULL;
builder = builderA;
@@ -353,6 +354,7 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
state = new GfxState(72, 72, box, 0, gFalse);
fontChanged = gFalse;
clip = clipNone;
+ lastClipPath = NULL;
ignoreUndef = 0;
for (i = 0; i < 6; ++i) {
baseMatrix[i] = state->getCTM()[i];
@@ -373,6 +375,9 @@ PdfParser::~PdfParser() {
if (state) {
delete state;
}
+ if (lastClipPath) {
+ delete lastClipPath;
+ }
}
void PdfParser::parse(Object *obj, GBool topLevel) {
@@ -1554,14 +1559,52 @@ void PdfParser::opShFill(Object args[], int numArgs) {
GfxShading *shading;
GfxPath *savedPath;
double xMin, yMin, xMax, yMax;
+ double gradientTransform[6];
+ double *matrix = NULL;
+ GBool savedState = gFalse;
if (!(shading = res->lookupShading(args[0].getName()))) {
return;
}
// save current graphics state
- savedPath = state->getPath()->copy();
- saveState();
+ if (shading->getType() != 2 && shading->getType() != 3) {
+ savedPath = state->getPath()->copy();
+ saveState();
+ savedState = gTrue;
+ } else { // get gradient transform if possible
+ // check proper operator sequence
+ // first there should be one W(*) and then one 'cm' somewhere before 'sh'
+ GBool seenClip, seenConcat;
+ seenClip = gFalse;
+ seenConcat = gFalse;
+ int i = 1;
+ while (i <= maxOperatorHistoryDepth) {
+ const char *opName = getPreviousOperator(i);
+ if (!strcmp(opName, "cm")) {
+ if (seenConcat) { // more than one 'cm'
+ break;
+ } else {
+ seenConcat = gTrue;
+ }
+ } else if (!strcmp(opName, "W") || !strcmp(opName, "W*")) {
+ if (seenConcat) { // good sequence
+ seenClip = gTrue;
+ break;
+ } else { // no 'cm' so bail out
+ break;
+ }
+ }
+ i++;
+ }
+
+ if (seenConcat && seenClip) {
+ if (builder->getTransform((double*)&gradientTransform)) {
+ matrix = (double*)&gradientTransform;
+ builder->setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); // remove transform
+ }
+ }
+ }
// clip to bbox
if (shading->getHasBBox()) {
@@ -1572,12 +1615,16 @@ void PdfParser::opShFill(Object args[], int numArgs) {
state->lineTo(xMin, yMax);
state->closePath();
state->clip();
- builder->clip(state);
+ if (savedState)
+ builder->setClipPath(state);
+ else
+ builder->clip(state);
state->clearPath();
}
// set the color space
- state->setFillColorSpace(shading->getColorSpace()->copy());
+ if (savedState)
+ state->setFillColorSpace(shading->getColorSpace()->copy());
// do shading type-specific operations
switch (shading->getType()) {
@@ -1586,7 +1633,10 @@ void PdfParser::opShFill(Object args[], int numArgs) {
break;
case 2:
case 3:
- // no need to implement these
+ if (lastClipPath) {
+ builder->addShadedFill(shading, matrix, lastClipPath,
+ lastClipType == clipEO ? true : false);
+ }
break;
case 4:
case 5:
@@ -1599,8 +1649,10 @@ void PdfParser::opShFill(Object args[], int numArgs) {
}
// restore graphics state
- restoreState();
- state->setPath(savedPath);
+ if (savedState) {
+ restoreState();
+ state->setPath(savedPath);
+ }
delete shading;
}
@@ -1949,10 +2001,18 @@ void PdfParser::doEndPath() {
void PdfParser::opClip(Object args[], int numArgs) {
clip = clipNormal;
+ lastClipType = clipNormal;
+ if (lastClipPath)
+ delete lastClipPath;
+ lastClipPath = state->getPath()->copy();
}
void PdfParser::opEOClip(Object args[], int numArgs) {
clip = clipEO;
+ lastClipType = clipEO;
+ if (lastClipPath)
+ delete lastClipPath;
+ lastClipPath = state->getPath()->copy();
}
//------------------------------------------------------------------------
diff --git a/src/extension/internal/pdfinput/pdf-parser.h b/src/extension/internal/pdfinput/pdf-parser.h
index 5747dcc9a..404574537 100644
--- a/src/extension/internal/pdfinput/pdf-parser.h
+++ b/src/extension/internal/pdfinput/pdf-parser.h
@@ -154,6 +154,8 @@ private:
void pushOperator(const char *name);
OpHistoryEntry *popOperator();
const char *getPreviousOperator(unsigned int look_back=1); // returns the nth previous operator's name
+ GfxPath *lastClipPath; // Used as the path to be filled for an 'sh' operator
+ GfxClipType lastClipType;
void go(GBool topLevel);
void execOp(Object *cmd, Object args[], int numArgs);
diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp
index 78426b85d..08719afd0 100644
--- a/src/extension/internal/pdfinput/svg-builder.cpp
+++ b/src/extension/internal/pdfinput/svg-builder.cpp
@@ -383,6 +383,42 @@ void SvgBuilder::addPath(GfxState *state, bool fill, bool stroke, bool even_odd)
}
/**
+ * \brief Emits the current path in poppler's GfxState data structure
+ * The path is set to be filled with the given shading.
+ */
+void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *path,
+ bool even_odd) {
+
+ Inkscape::XML::Node *path_node = _xml_doc->createElement("svg:path");
+ gchar *pathtext = svgInterpretPath(path);
+ path_node->setAttribute("d", pathtext);
+ g_free(pathtext);
+
+ // Set style
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ gchar *id = _createGradient(shading, matrix);
+ if (id) {
+ gchar *urltext = g_strdup_printf ("url(#%s)", id);
+ sp_repr_css_set_property(css, "fill", urltext);
+ g_free(urltext);
+ g_free(id);
+ } else {
+ sp_repr_css_attr_unref(css);
+ Inkscape::GC::release(path_node);
+ return;
+ }
+ if (even_odd) {
+ sp_repr_css_set_property(css, "fill-rule", "evenodd");
+ }
+ sp_repr_css_set_property(css, "stroke", "none");
+ sp_repr_css_change(path_node, css, "style");
+ sp_repr_css_attr_unref(css);
+
+ _container->appendChild(path_node);
+ Inkscape::GC::release(path_node);
+}
+
+/**
* \brief Clips to the current path set in GfxState
* \param state poppler's data structure
* \param even_odd whether the even-odd rule should be applied
@@ -480,7 +516,9 @@ gchar *SvgBuilder::_createPattern(GfxPattern *pattern, GfxState *state, bool is_
gchar *id = NULL;
if ( pattern != NULL ) {
if ( pattern->getType() == 2 ) { // Shading pattern
- id = _createGradient((GfxShadingPattern*)pattern);
+ GfxShadingPattern *shading_pattern = (GfxShadingPattern*)pattern;
+ id = _createGradient(shading_pattern->getShading(),
+ shading_pattern->getMatrix());
} else if ( pattern->getType() == 1 ) { // Tiling pattern
id = _createTilingPattern((GfxTilingPattern*)pattern, state, is_stroke);
}
@@ -558,8 +596,7 @@ gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern,
* \brief Creates a linear or radial gradient from poppler's data structure
* \return id of the created object
*/
-gchar *SvgBuilder::_createGradient(GfxShadingPattern *shading_pattern) {
- GfxShading *shading = shading_pattern->getShading();
+gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix) {
Inkscape::XML::Node *gradient;
Function *func;
int num_funcs;
@@ -598,13 +635,15 @@ gchar *SvgBuilder::_createGradient(GfxShadingPattern *shading_pattern) {
}
gradient->setAttribute("gradientUnits", "userSpaceOnUse");
// Flip the gradient transform around the y axis
- double *p2u = shading_pattern->getMatrix();
- NR::Matrix pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]);
- NR::Matrix flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX);
- pat_matrix *= flip;
- gchar *transform_text = sp_svg_transform_write(pat_matrix);
- gradient->setAttribute("gradientTransform", transform_text);
- g_free(transform_text);
+ if (matrix) {
+ NR::Matrix pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3],
+ matrix[4], matrix[5]);
+ NR::Matrix flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX);
+ pat_matrix *= flip;
+ gchar *transform_text = sp_svg_transform_write(pat_matrix);
+ gradient->setAttribute("gradientTransform", transform_text);
+ g_free(transform_text);
+ }
if ( extend0 && extend1 ) {
gradient->setAttribute("spreadMethod", "pad");
diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h
index 5004e90f9..f2fc77971 100644
--- a/src/extension/internal/pdfinput/svg-builder.h
+++ b/src/extension/internal/pdfinput/svg-builder.h
@@ -33,9 +33,10 @@ namespace Inkscape {
class GooString;
class Function;
struct GfxState;
+class GfxPath;
class GfxPattern;
-class GfxShadingPattern;
class GfxTilingPattern;
+class GfxShading;
class GfxFont;
class GfxImageColorMap;
class Stream;
@@ -93,6 +94,7 @@ public:
// Path adding
void addPath(GfxState *state, bool fill, bool stroke, bool even_odd=false);
+ void addShadedFill(GfxShading *shading, double *matrix, GfxPath *path, bool even_odd=false);
// Image handling
void addImage(GfxState *state, Stream *str, int width, int height,
@@ -144,7 +146,7 @@ private:
// Pattern creation
gchar *_createPattern(GfxPattern *pattern, GfxState *state, bool is_stroke=false);
- gchar *_createGradient(GfxShadingPattern *shading_pattern);
+ gchar *_createGradient(GfxShading *shading, double *matrix);
bool _addStopsToGradient(Inkscape::XML::Node *gradient, Function *func, double opacity);
bool _addSamplesToGradient(Inkscape::XML::Node *gradient, Function *func,
double offset0, double offset1, double opacity);