gfx/skia/trunk/src/pdf/SkPDFUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/pdf/SkPDFUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,249 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkData.h"
    1.14 +#include "SkGeometry.h"
    1.15 +#include "SkPaint.h"
    1.16 +#include "SkPath.h"
    1.17 +#include "SkPDFResourceDict.h"
    1.18 +#include "SkPDFUtils.h"
    1.19 +#include "SkStream.h"
    1.20 +#include "SkString.h"
    1.21 +#include "SkPDFTypes.h"
    1.22 +
    1.23 +//static
    1.24 +SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) {
    1.25 +    SkPDFArray* result = new SkPDFArray();
    1.26 +    result->reserve(4);
    1.27 +    result->appendScalar(rect.fLeft);
    1.28 +    result->appendScalar(rect.fTop);
    1.29 +    result->appendScalar(rect.fRight);
    1.30 +    result->appendScalar(rect.fBottom);
    1.31 +    return result;
    1.32 +}
    1.33 +
    1.34 +// static
    1.35 +SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
    1.36 +    SkScalar values[6];
    1.37 +    if (!matrix.asAffine(values)) {
    1.38 +        SkMatrix::SetAffineIdentity(values);
    1.39 +    }
    1.40 +
    1.41 +    SkPDFArray* result = new SkPDFArray;
    1.42 +    result->reserve(6);
    1.43 +    for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
    1.44 +        result->appendScalar(values[i]);
    1.45 +    }
    1.46 +    return result;
    1.47 +}
    1.48 +
    1.49 +// static
    1.50 +void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
    1.51 +    SkScalar values[6];
    1.52 +    if (!matrix.asAffine(values)) {
    1.53 +        SkMatrix::SetAffineIdentity(values);
    1.54 +    }
    1.55 +    for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
    1.56 +        SkPDFScalar::Append(values[i], content);
    1.57 +        content->writeText(" ");
    1.58 +    }
    1.59 +    content->writeText("cm\n");
    1.60 +}
    1.61 +
    1.62 +// static
    1.63 +void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
    1.64 +    SkPDFScalar::Append(x, content);
    1.65 +    content->writeText(" ");
    1.66 +    SkPDFScalar::Append(y, content);
    1.67 +    content->writeText(" m\n");
    1.68 +}
    1.69 +
    1.70 +// static
    1.71 +void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) {
    1.72 +    SkPDFScalar::Append(x, content);
    1.73 +    content->writeText(" ");
    1.74 +    SkPDFScalar::Append(y, content);
    1.75 +    content->writeText(" l\n");
    1.76 +}
    1.77 +
    1.78 +// static
    1.79 +void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
    1.80 +                             SkScalar ctl2X, SkScalar ctl2Y,
    1.81 +                             SkScalar dstX, SkScalar dstY, SkWStream* content) {
    1.82 +    SkString cmd("y\n");
    1.83 +    SkPDFScalar::Append(ctl1X, content);
    1.84 +    content->writeText(" ");
    1.85 +    SkPDFScalar::Append(ctl1Y, content);
    1.86 +    content->writeText(" ");
    1.87 +    if (ctl2X != dstX || ctl2Y != dstY) {
    1.88 +        cmd.set("c\n");
    1.89 +        SkPDFScalar::Append(ctl2X, content);
    1.90 +        content->writeText(" ");
    1.91 +        SkPDFScalar::Append(ctl2Y, content);
    1.92 +        content->writeText(" ");
    1.93 +    }
    1.94 +    SkPDFScalar::Append(dstX, content);
    1.95 +    content->writeText(" ");
    1.96 +    SkPDFScalar::Append(dstY, content);
    1.97 +    content->writeText(" ");
    1.98 +    content->writeText(cmd.c_str());
    1.99 +}
   1.100 +
   1.101 +// static
   1.102 +void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
   1.103 +    // Skia has 0,0 at top left, pdf at bottom left.  Do the right thing.
   1.104 +    SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop);
   1.105 +
   1.106 +    SkPDFScalar::Append(rect.fLeft, content);
   1.107 +    content->writeText(" ");
   1.108 +    SkPDFScalar::Append(bottom, content);
   1.109 +    content->writeText(" ");
   1.110 +    SkPDFScalar::Append(rect.width(), content);
   1.111 +    content->writeText(" ");
   1.112 +    SkPDFScalar::Append(rect.height(), content);
   1.113 +    content->writeText(" re\n");
   1.114 +}
   1.115 +
   1.116 +// static
   1.117 +void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle,
   1.118 +                          SkWStream* content) {
   1.119 +    // Filling a path with no area results in a drawing in PDF renderers but
   1.120 +    // Chrome expects to be able to draw some such entities with no visible
   1.121 +    // result, so we detect those cases and discard the drawing for them.
   1.122 +    // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y).
   1.123 +    enum SkipFillState {
   1.124 +        kEmpty_SkipFillState         = 0,
   1.125 +        kSingleLine_SkipFillState    = 1,
   1.126 +        kNonSingleLine_SkipFillState = 2,
   1.127 +    };
   1.128 +    SkipFillState fillState = kEmpty_SkipFillState;
   1.129 +    if (paintStyle != SkPaint::kFill_Style) {
   1.130 +        fillState = kNonSingleLine_SkipFillState;
   1.131 +    }
   1.132 +    SkPoint lastMovePt = SkPoint::Make(0,0);
   1.133 +    SkDynamicMemoryWStream currentSegment;
   1.134 +    SkPoint args[4];
   1.135 +    SkPath::Iter iter(path, false);
   1.136 +    for (SkPath::Verb verb = iter.next(args);
   1.137 +         verb != SkPath::kDone_Verb;
   1.138 +         verb = iter.next(args)) {
   1.139 +        // args gets all the points, even the implicit first point.
   1.140 +        switch (verb) {
   1.141 +            case SkPath::kMove_Verb:
   1.142 +                MoveTo(args[0].fX, args[0].fY, &currentSegment);
   1.143 +                lastMovePt = args[0];
   1.144 +                fillState = kEmpty_SkipFillState;
   1.145 +                break;
   1.146 +            case SkPath::kLine_Verb:
   1.147 +                AppendLine(args[1].fX, args[1].fY, &currentSegment);
   1.148 +                if (fillState == kEmpty_SkipFillState) {
   1.149 +                   if (args[0] != lastMovePt) {
   1.150 +                       fillState = kSingleLine_SkipFillState;
   1.151 +                   }
   1.152 +                } else if (fillState == kSingleLine_SkipFillState) {
   1.153 +                    fillState = kNonSingleLine_SkipFillState;
   1.154 +                }
   1.155 +                break;
   1.156 +            case SkPath::kQuad_Verb: {
   1.157 +                SkPoint cubic[4];
   1.158 +                SkConvertQuadToCubic(args, cubic);
   1.159 +                AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
   1.160 +                            cubic[3].fX, cubic[3].fY, &currentSegment);
   1.161 +                fillState = kNonSingleLine_SkipFillState;
   1.162 +                break;
   1.163 +            }
   1.164 +            case SkPath::kCubic_Verb:
   1.165 +                AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
   1.166 +                            args[3].fX, args[3].fY, &currentSegment);
   1.167 +                fillState = kNonSingleLine_SkipFillState;
   1.168 +                break;
   1.169 +            case SkPath::kClose_Verb:
   1.170 +                if (fillState != kSingleLine_SkipFillState) {
   1.171 +                    ClosePath(&currentSegment);
   1.172 +                    SkData* data = currentSegment.copyToData();
   1.173 +                    content->write(data->data(), data->size());
   1.174 +                    data->unref();
   1.175 +                }
   1.176 +                currentSegment.reset();
   1.177 +                break;
   1.178 +            default:
   1.179 +                SkASSERT(false);
   1.180 +                break;
   1.181 +        }
   1.182 +    }
   1.183 +    if (currentSegment.bytesWritten() > 0) {
   1.184 +        SkData* data = currentSegment.copyToData();
   1.185 +        content->write(data->data(), data->size());
   1.186 +        data->unref();
   1.187 +    }
   1.188 +}
   1.189 +
   1.190 +// static
   1.191 +void SkPDFUtils::ClosePath(SkWStream* content) {
   1.192 +    content->writeText("h\n");
   1.193 +}
   1.194 +
   1.195 +// static
   1.196 +void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
   1.197 +                           SkWStream* content) {
   1.198 +    if (style == SkPaint::kFill_Style) {
   1.199 +        content->writeText("f");
   1.200 +    } else if (style == SkPaint::kStrokeAndFill_Style) {
   1.201 +        content->writeText("B");
   1.202 +    } else if (style == SkPaint::kStroke_Style) {
   1.203 +        content->writeText("S");
   1.204 +    }
   1.205 +
   1.206 +    if (style != SkPaint::kStroke_Style) {
   1.207 +        NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
   1.208 +        NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
   1.209 +        if (fill == SkPath::kEvenOdd_FillType) {
   1.210 +            content->writeText("*");
   1.211 +        }
   1.212 +    }
   1.213 +    content->writeText("\n");
   1.214 +}
   1.215 +
   1.216 +// static
   1.217 +void SkPDFUtils::StrokePath(SkWStream* content) {
   1.218 +    SkPDFUtils::PaintPath(
   1.219 +        SkPaint::kStroke_Style, SkPath::kWinding_FillType, content);
   1.220 +}
   1.221 +
   1.222 +// static
   1.223 +void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) {
   1.224 +    content->writeText("/");
   1.225 +    content->writeText(SkPDFResourceDict::getResourceName(
   1.226 +            SkPDFResourceDict::kXObject_ResourceType,
   1.227 +            objectIndex).c_str());
   1.228 +    content->writeText(" Do\n");
   1.229 +}
   1.230 +
   1.231 +// static
   1.232 +void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) {
   1.233 +    content->writeText("/");
   1.234 +    content->writeText(SkPDFResourceDict::getResourceName(
   1.235 +            SkPDFResourceDict::kExtGState_ResourceType,
   1.236 +            objectIndex).c_str());
   1.237 +    content->writeText(" gs\n");
   1.238 +}
   1.239 +
   1.240 +// static
   1.241 +void SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) {
   1.242 +    // Select Pattern color space (CS, cs) and set pattern object as current
   1.243 +    // color (SCN, scn)
   1.244 +    SkString resourceName = SkPDFResourceDict::getResourceName(
   1.245 +            SkPDFResourceDict::kPattern_ResourceType,
   1.246 +            objectIndex);
   1.247 +    content->writeText("/Pattern CS/Pattern cs/");
   1.248 +    content->writeText(resourceName.c_str());
   1.249 +    content->writeText(" SCN/");
   1.250 +    content->writeText(resourceName.c_str());
   1.251 +    content->writeText(" scn\n");
   1.252 +}

mercurial