• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SkPaint.h"
18 #include "SkPath.h"
19 #include "SkPDFUtils.h"
20 #include "SkStream.h"
21 #include "SkString.h"
22 #include "SkPDFTypes.h"
23 
24 // static
MatrixToArray(const SkMatrix & matrix)25 SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
26     SkScalar values[6];
27     SkAssertResult(matrix.pdfTransform(values));
28 
29     SkPDFArray* result = new SkPDFArray;
30     result->reserve(6);
31     for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
32         result->append(new SkPDFScalar(values[i]))->unref();
33     }
34     return result;
35 }
36 
37 // static
AppendTransform(const SkMatrix & matrix,SkWStream * content)38 void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
39     SkScalar values[6];
40     SkAssertResult(matrix.pdfTransform(values));
41     for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
42         SkPDFScalar::Append(values[i], content);
43         content->writeText(" ");
44     }
45     content->writeText("cm\n");
46 }
47 
48 // static
MoveTo(SkScalar x,SkScalar y,SkWStream * content)49 void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
50     SkPDFScalar::Append(x, content);
51     content->writeText(" ");
52     SkPDFScalar::Append(y, content);
53     content->writeText(" m\n");
54 }
55 
56 // static
AppendLine(SkScalar x,SkScalar y,SkWStream * content)57 void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) {
58     SkPDFScalar::Append(x, content);
59     content->writeText(" ");
60     SkPDFScalar::Append(y, content);
61     content->writeText(" l\n");
62 }
63 
64 // static
AppendCubic(SkScalar ctl1X,SkScalar ctl1Y,SkScalar ctl2X,SkScalar ctl2Y,SkScalar dstX,SkScalar dstY,SkWStream * content)65 void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
66                              SkScalar ctl2X, SkScalar ctl2Y,
67                              SkScalar dstX, SkScalar dstY, SkWStream* content) {
68     SkString cmd("y\n");
69     SkPDFScalar::Append(ctl1X, content);
70     content->writeText(" ");
71     SkPDFScalar::Append(ctl1Y, content);
72     content->writeText(" ");
73     if (ctl2X != dstX || ctl2Y != dstY) {
74         cmd.set("c\n");
75         SkPDFScalar::Append(ctl2X, content);
76         content->writeText(" ");
77         SkPDFScalar::Append(ctl2Y, content);
78         content->writeText(" ");
79     }
80     SkPDFScalar::Append(dstX, content);
81     content->writeText(" ");
82     SkPDFScalar::Append(dstY, content);
83     content->writeText(" ");
84     content->writeText(cmd.c_str());
85 }
86 
87 // static
AppendRectangle(const SkRect & rect,SkWStream * content)88 void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
89     // Skia has 0,0 at top left, pdf at bottom left.  Do the right thing.
90     SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop);
91 
92     SkPDFScalar::Append(rect.fLeft, content);
93     content->writeText(" ");
94     SkPDFScalar::Append(bottom, content);
95     content->writeText(" ");
96     SkPDFScalar::Append(rect.width(), content);
97     content->writeText(" ");
98     SkPDFScalar::Append(rect.height(), content);
99     content->writeText(" re\n");
100 }
101 
102 // static
EmitPath(const SkPath & path,SkWStream * content)103 void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
104     SkPoint args[4];
105     SkPath::Iter iter(path, false);
106     for (SkPath::Verb verb = iter.next(args);
107          verb != SkPath::kDone_Verb;
108          verb = iter.next(args)) {
109         // args gets all the points, even the implicit first point.
110         switch (verb) {
111             case SkPath::kMove_Verb:
112                 MoveTo(args[0].fX, args[0].fY, content);
113                 break;
114             case SkPath::kLine_Verb:
115                 AppendLine(args[1].fX, args[1].fY, content);
116                 break;
117             case SkPath::kQuad_Verb: {
118                 // Convert quad to cubic (degree elevation). http://goo.gl/vS4i
119                 const SkScalar three = SkIntToScalar(3);
120                 args[1].scale(SkIntToScalar(2));
121                 SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three);
122                 SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three);
123                 SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three);
124                 SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three);
125                 AppendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY,
126                             content);
127                 break;
128             }
129             case SkPath::kCubic_Verb:
130                 AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
131                             args[3].fX, args[3].fY, content);
132                 break;
133             case SkPath::kClose_Verb:
134                 ClosePath(content);
135                 break;
136             case SkPath::kDone_Verb:
137                 break;
138             default:
139                 SkASSERT(false);
140                 break;
141         }
142     }
143 }
144 
145 // static
ClosePath(SkWStream * content)146 void SkPDFUtils::ClosePath(SkWStream* content) {
147     content->writeText("h\n");
148 }
149 
150 // static
PaintPath(SkPaint::Style style,SkPath::FillType fill,SkWStream * content)151 void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
152                            SkWStream* content) {
153     if (style == SkPaint::kFill_Style)
154         content->writeText("f");
155     else if (style == SkPaint::kStrokeAndFill_Style)
156         content->writeText("B");
157     else if (style == SkPaint::kStroke_Style)
158         content->writeText("S");
159 
160     if (style != SkPaint::kStroke_Style) {
161         NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
162         NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
163         if (fill == SkPath::kEvenOdd_FillType)
164             content->writeText("*");
165     }
166     content->writeText("\n");
167 }
168 
169 // static
StrokePath(SkWStream * content)170 void SkPDFUtils::StrokePath(SkWStream* content) {
171     SkPDFUtils::PaintPath(
172         SkPaint::kStroke_Style, SkPath::kWinding_FillType, content);
173 }
174 
175 // static
DrawFormXObject(int objectIndex,SkWStream * content)176 void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) {
177     content->writeText("/X");
178     content->writeDecAsText(objectIndex);
179     content->writeText(" Do\n");
180 }
181 
182 // static
ApplyGraphicState(int objectIndex,SkWStream * content)183 void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) {
184     content->writeText("/G");
185     content->writeDecAsText(objectIndex);
186     content->writeText(" gs\n");
187 }
188