blob: 56271bc9d5db38af28790858f736c9cd60b1b4ce [file] [log] [blame]
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +00001/*
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"
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000020#include "SkStream.h"
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000021#include "SkString.h"
22#include "SkPDFTypes.h"
23
24// static
25SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
26 SkScalar values[6];
bungeman@google.com1ddd7c32011-07-13 19:41:55 +000027 if (!matrix.asAffine(values)) {
28 SkMatrix::SetAffineIdentity(values);
29 }
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000030
31 SkPDFArray* result = new SkPDFArray;
32 result->reserve(6);
33 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
reed@google.comc789cf12011-07-20 12:14:33 +000034 result->appendScalar(values[i]);
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000035 }
36 return result;
37}
38
39// static
vandebo@chromium.org75f97e42011-04-11 23:24:18 +000040void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
41 SkScalar values[6];
bungeman@google.com1ddd7c32011-07-13 19:41:55 +000042 if (!matrix.asAffine(values)) {
43 SkMatrix::SetAffineIdentity(values);
44 }
vandebo@chromium.org75f97e42011-04-11 23:24:18 +000045 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
46 SkPDFScalar::Append(values[i], content);
47 content->writeText(" ");
48 }
49 content->writeText("cm\n");
50}
51
52// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000053void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000054 SkPDFScalar::Append(x, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000055 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000056 SkPDFScalar::Append(y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000057 content->writeText(" m\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000058}
59
60// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000061void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000062 SkPDFScalar::Append(x, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000063 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000064 SkPDFScalar::Append(y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000065 content->writeText(" l\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000066}
67
68// static
69void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
70 SkScalar ctl2X, SkScalar ctl2Y,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000071 SkScalar dstX, SkScalar dstY, SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000072 SkString cmd("y\n");
73 SkPDFScalar::Append(ctl1X, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000074 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000075 SkPDFScalar::Append(ctl1Y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000076 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000077 if (ctl2X != dstX || ctl2Y != dstY) {
78 cmd.set("c\n");
79 SkPDFScalar::Append(ctl2X, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000080 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000081 SkPDFScalar::Append(ctl2Y, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000082 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000083 }
84 SkPDFScalar::Append(dstX, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000085 content->writeText(" ");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000086 SkPDFScalar::Append(dstY, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000087 content->writeText(" ");
88 content->writeText(cmd.c_str());
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +000089}
90
91// static
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000092void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
93 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
94 SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop);
95
96 SkPDFScalar::Append(rect.fLeft, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000097 content->writeText(" ");
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +000098 SkPDFScalar::Append(bottom, content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +000099 content->writeText(" ");
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000100 SkPDFScalar::Append(rect.width(), content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000101 content->writeText(" ");
vandebo@chromium.org9fbdf872011-05-09 07:55:58 +0000102 SkPDFScalar::Append(rect.height(), content);
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000103 content->writeText(" re\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000104}
105
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000106// static
107void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000108 SkPoint args[4];
109 SkPath::Iter iter(path, false);
110 for (SkPath::Verb verb = iter.next(args);
111 verb != SkPath::kDone_Verb;
112 verb = iter.next(args)) {
113 // args gets all the points, even the implicit first point.
114 switch (verb) {
115 case SkPath::kMove_Verb:
116 MoveTo(args[0].fX, args[0].fY, content);
117 break;
118 case SkPath::kLine_Verb:
119 AppendLine(args[1].fX, args[1].fY, content);
120 break;
121 case SkPath::kQuad_Verb: {
122 // Convert quad to cubic (degree elevation). http://goo.gl/vS4i
123 const SkScalar three = SkIntToScalar(3);
124 args[1].scale(SkIntToScalar(2));
125 SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three);
126 SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three);
127 SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three);
128 SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three);
129 AppendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY,
130 content);
131 break;
132 }
133 case SkPath::kCubic_Verb:
134 AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY,
135 args[3].fX, args[3].fY, content);
136 break;
137 case SkPath::kClose_Verb:
138 ClosePath(content);
139 break;
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000140 default:
141 SkASSERT(false);
142 break;
143 }
144 }
145}
146
147// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000148void SkPDFUtils::ClosePath(SkWStream* content) {
149 content->writeText("h\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000150}
151
152// static
153void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000154 SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000155 if (style == SkPaint::kFill_Style)
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000156 content->writeText("f");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000157 else if (style == SkPaint::kStrokeAndFill_Style)
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000158 content->writeText("B");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000159 else if (style == SkPaint::kStroke_Style)
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000160 content->writeText("S");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000161
162 if (style != SkPaint::kStroke_Style) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000163 NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
164 NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
165 if (fill == SkPath::kEvenOdd_FillType)
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000166 content->writeText("*");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000167 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000168 content->writeText("\n");
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000169}
170
171// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000172void SkPDFUtils::StrokePath(SkWStream* content) {
ctguil@chromium.orgf966fd32011-03-04 21:47:04 +0000173 SkPDFUtils::PaintPath(
174 SkPaint::kStroke_Style, SkPath::kWinding_FillType, content);
175}
vandebo@chromium.org6112c212011-05-13 03:50:38 +0000176
177// static
178void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) {
179 content->writeText("/X");
180 content->writeDecAsText(objectIndex);
181 content->writeText(" Do\n");
182}
183
184// static
185void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) {
186 content->writeText("/G");
187 content->writeDecAsText(objectIndex);
188 content->writeText(" gs\n");
189}