1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkGeometry.h" 11 #include "SkPaint.h" 12 #include "SkPath.h" 13 #include "SkPDFUtils.h" 14 #include "SkStream.h" 15 #include "SkString.h" 16 #include "SkPDFTypes.h" 17 18 // static 19 SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) { 20 SkScalar values[6]; 21 if (!matrix.asAffine(values)) { 22 SkMatrix::SetAffineIdentity(values); 23 } 24 25 SkPDFArray* result = new SkPDFArray; 26 result->reserve(6); 27 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) { 28 result->appendScalar(values[i]); 29 } 30 return result; 31 } 32 33 // static 34 void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) { 35 SkScalar values[6]; 36 if (!matrix.asAffine(values)) { 37 SkMatrix::SetAffineIdentity(values); 38 } 39 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) { 40 SkPDFScalar::Append(values[i], content); 41 content->writeText(" "); 42 } 43 content->writeText("cm\n"); 44 } 45 46 // static 47 void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) { 48 SkPDFScalar::Append(x, content); 49 content->writeText(" "); 50 SkPDFScalar::Append(y, content); 51 content->writeText(" m\n"); 52 } 53 54 // static 55 void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) { 56 SkPDFScalar::Append(x, content); 57 content->writeText(" "); 58 SkPDFScalar::Append(y, content); 59 content->writeText(" l\n"); 60 } 61 62 // static 63 void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, 64 SkScalar ctl2X, SkScalar ctl2Y, 65 SkScalar dstX, SkScalar dstY, SkWStream* content) { 66 SkString cmd("y\n"); 67 SkPDFScalar::Append(ctl1X, content); 68 content->writeText(" "); 69 SkPDFScalar::Append(ctl1Y, content); 70 content->writeText(" "); 71 if (ctl2X != dstX || ctl2Y != dstY) { 72 cmd.set("c\n"); 73 SkPDFScalar::Append(ctl2X, content); 74 content->writeText(" "); 75 SkPDFScalar::Append(ctl2Y, content); 76 content->writeText(" "); 77 } 78 SkPDFScalar::Append(dstX, content); 79 content->writeText(" "); 80 SkPDFScalar::Append(dstY, content); 81 content->writeText(" "); 82 content->writeText(cmd.c_str()); 83 } 84 85 // static 86 void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) { 87 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. 88 SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop); 89 90 SkPDFScalar::Append(rect.fLeft, content); 91 content->writeText(" "); 92 SkPDFScalar::Append(bottom, content); 93 content->writeText(" "); 94 SkPDFScalar::Append(rect.width(), content); 95 content->writeText(" "); 96 SkPDFScalar::Append(rect.height(), content); 97 content->writeText(" re\n"); 98 } 99 100 // static 101 void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) { 102 SkPoint args[4]; 103 SkPath::Iter iter(path, false); 104 for (SkPath::Verb verb = iter.next(args); 105 verb != SkPath::kDone_Verb; 106 verb = iter.next(args)) { 107 // args gets all the points, even the implicit first point. 108 switch (verb) { 109 case SkPath::kMove_Verb: 110 MoveTo(args[0].fX, args[0].fY, content); 111 break; 112 case SkPath::kLine_Verb: 113 AppendLine(args[1].fX, args[1].fY, content); 114 break; 115 case SkPath::kQuad_Verb: { 116 SkPoint cubic[4]; 117 SkConvertQuadToCubic(args, cubic); 118 AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, 119 cubic[3].fX, cubic[3].fY, content); 120 break; 121 } 122 case SkPath::kCubic_Verb: 123 AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY, 124 args[3].fX, args[3].fY, content); 125 break; 126 case SkPath::kClose_Verb: 127 ClosePath(content); 128 break; 129 default: 130 SkASSERT(false); 131 break; 132 } 133 } 134 } 135 136 // static 137 void SkPDFUtils::ClosePath(SkWStream* content) { 138 content->writeText("h\n"); 139 } 140 141 // static 142 void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill, 143 SkWStream* content) { 144 if (style == SkPaint::kFill_Style) { 145 content->writeText("f"); 146 } else if (style == SkPaint::kStrokeAndFill_Style) { 147 content->writeText("B"); 148 } else if (style == SkPaint::kStroke_Style) { 149 content->writeText("S"); 150 } 151 152 if (style != SkPaint::kStroke_Style) { 153 NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false); 154 NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false); 155 if (fill == SkPath::kEvenOdd_FillType) { 156 content->writeText("*"); 157 } 158 } 159 content->writeText("\n"); 160 } 161 162 // static 163 void SkPDFUtils::StrokePath(SkWStream* content) { 164 SkPDFUtils::PaintPath( 165 SkPaint::kStroke_Style, SkPath::kWinding_FillType, content); 166 } 167 168 // static 169 void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) { 170 content->writeText("/X"); 171 content->writeDecAsText(objectIndex); 172 content->writeText(" Do\n"); 173 } 174 175 // static 176 void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) { 177 content->writeText("/G"); 178 content->writeDecAsText(objectIndex); 179 content->writeText(" gs\n"); 180 } 181