OLD | NEW |
1 | |
2 /* | 1 /* |
3 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
4 * | 3 * |
5 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 5 * found in the LICENSE file. |
7 */ | 6 */ |
8 | 7 |
9 | 8 |
10 #include "SkData.h" | 9 #include "SkData.h" |
11 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 return result; | 42 return result; |
44 } | 43 } |
45 | 44 |
46 // static | 45 // static |
47 void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) { | 46 void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) { |
48 SkScalar values[6]; | 47 SkScalar values[6]; |
49 if (!matrix.asAffine(values)) { | 48 if (!matrix.asAffine(values)) { |
50 SkMatrix::SetAffineIdentity(values); | 49 SkMatrix::SetAffineIdentity(values); |
51 } | 50 } |
52 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) { | 51 for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) { |
53 SkPDFScalar::Append(values[i], content); | 52 SkPDFUtils::AppendScalar(values[i], content); |
54 content->writeText(" "); | 53 content->writeText(" "); |
55 } | 54 } |
56 content->writeText("cm\n"); | 55 content->writeText("cm\n"); |
57 } | 56 } |
58 | 57 |
59 // static | 58 // static |
60 void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) { | 59 void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) { |
61 SkPDFScalar::Append(x, content); | 60 SkPDFUtils::AppendScalar(x, content); |
62 content->writeText(" "); | 61 content->writeText(" "); |
63 SkPDFScalar::Append(y, content); | 62 SkPDFUtils::AppendScalar(y, content); |
64 content->writeText(" m\n"); | 63 content->writeText(" m\n"); |
65 } | 64 } |
66 | 65 |
67 // static | 66 // static |
68 void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) { | 67 void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) { |
69 SkPDFScalar::Append(x, content); | 68 SkPDFUtils::AppendScalar(x, content); |
70 content->writeText(" "); | 69 content->writeText(" "); |
71 SkPDFScalar::Append(y, content); | 70 SkPDFUtils::AppendScalar(y, content); |
72 content->writeText(" l\n"); | 71 content->writeText(" l\n"); |
73 } | 72 } |
74 | 73 |
75 // static | 74 // static |
76 void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, | 75 void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, |
77 SkScalar ctl2X, SkScalar ctl2Y, | 76 SkScalar ctl2X, SkScalar ctl2Y, |
78 SkScalar dstX, SkScalar dstY, SkWStream* content) { | 77 SkScalar dstX, SkScalar dstY, SkWStream* content) { |
79 SkString cmd("y\n"); | 78 SkString cmd("y\n"); |
80 SkPDFScalar::Append(ctl1X, content); | 79 SkPDFUtils::AppendScalar(ctl1X, content); |
81 content->writeText(" "); | 80 content->writeText(" "); |
82 SkPDFScalar::Append(ctl1Y, content); | 81 SkPDFUtils::AppendScalar(ctl1Y, content); |
83 content->writeText(" "); | 82 content->writeText(" "); |
84 if (ctl2X != dstX || ctl2Y != dstY) { | 83 if (ctl2X != dstX || ctl2Y != dstY) { |
85 cmd.set("c\n"); | 84 cmd.set("c\n"); |
86 SkPDFScalar::Append(ctl2X, content); | 85 SkPDFUtils::AppendScalar(ctl2X, content); |
87 content->writeText(" "); | 86 content->writeText(" "); |
88 SkPDFScalar::Append(ctl2Y, content); | 87 SkPDFUtils::AppendScalar(ctl2Y, content); |
89 content->writeText(" "); | 88 content->writeText(" "); |
90 } | 89 } |
91 SkPDFScalar::Append(dstX, content); | 90 SkPDFUtils::AppendScalar(dstX, content); |
92 content->writeText(" "); | 91 content->writeText(" "); |
93 SkPDFScalar::Append(dstY, content); | 92 SkPDFUtils::AppendScalar(dstY, content); |
94 content->writeText(" "); | 93 content->writeText(" "); |
95 content->writeText(cmd.c_str()); | 94 content->writeText(cmd.c_str()); |
96 } | 95 } |
97 | 96 |
98 static void append_quad(const SkPoint quad[], SkWStream* content) { | 97 static void append_quad(const SkPoint quad[], SkWStream* content) { |
99 SkPoint cubic[4]; | 98 SkPoint cubic[4]; |
100 SkConvertQuadToCubic(quad, cubic); | 99 SkConvertQuadToCubic(quad, cubic); |
101 SkPDFUtils::AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, | 100 SkPDFUtils::AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, |
102 cubic[3].fX, cubic[3].fY, content); | 101 cubic[3].fX, cubic[3].fY, content); |
103 } | 102 } |
104 | 103 |
105 // static | 104 // static |
106 void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) { | 105 void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) { |
107 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. | 106 // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. |
108 SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop); | 107 SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop); |
109 | 108 |
110 SkPDFScalar::Append(rect.fLeft, content); | 109 SkPDFUtils::AppendScalar(rect.fLeft, content); |
111 content->writeText(" "); | 110 content->writeText(" "); |
112 SkPDFScalar::Append(bottom, content); | 111 SkPDFUtils::AppendScalar(bottom, content); |
113 content->writeText(" "); | 112 content->writeText(" "); |
114 SkPDFScalar::Append(rect.width(), content); | 113 SkPDFUtils::AppendScalar(rect.width(), content); |
115 content->writeText(" "); | 114 content->writeText(" "); |
116 SkPDFScalar::Append(rect.height(), content); | 115 SkPDFUtils::AppendScalar(rect.height(), content); |
117 content->writeText(" re\n"); | 116 content->writeText(" re\n"); |
118 } | 117 } |
119 | 118 |
120 // static | 119 // static |
121 void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, | 120 void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, |
122 SkWStream* content) { | 121 SkWStream* content) { |
123 // Filling a path with no area results in a drawing in PDF renderers but | 122 // Filling a path with no area results in a drawing in PDF renderers but |
124 // Chrome expects to be able to draw some such entities with no visible | 123 // Chrome expects to be able to draw some such entities with no visible |
125 // result, so we detect those cases and discard the drawing for them. | 124 // result, so we detect those cases and discard the drawing for them. |
126 // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). | 125 // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 // color (SCN, scn) | 244 // color (SCN, scn) |
246 SkString resourceName = SkPDFResourceDict::getResourceName( | 245 SkString resourceName = SkPDFResourceDict::getResourceName( |
247 SkPDFResourceDict::kPattern_ResourceType, | 246 SkPDFResourceDict::kPattern_ResourceType, |
248 objectIndex); | 247 objectIndex); |
249 content->writeText("/Pattern CS/Pattern cs/"); | 248 content->writeText("/Pattern CS/Pattern cs/"); |
250 content->writeText(resourceName.c_str()); | 249 content->writeText(resourceName.c_str()); |
251 content->writeText(" SCN/"); | 250 content->writeText(" SCN/"); |
252 content->writeText(resourceName.c_str()); | 251 content->writeText(resourceName.c_str()); |
253 content->writeText(" scn\n"); | 252 content->writeText(" scn\n"); |
254 } | 253 } |
| 254 |
| 255 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { |
| 256 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and |
| 257 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). |
| 258 // When using floats that are outside the whole value range, we can use |
| 259 // integers instead. |
| 260 |
| 261 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) |
| 262 if (value > 32767 || value < -32767) { |
| 263 stream->writeDecAsText(SkScalarRoundToInt(value)); |
| 264 return; |
| 265 } |
| 266 |
| 267 char buffer[SkStrAppendScalar_MaxSize]; |
| 268 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); |
| 269 stream->write(buffer, end - buffer); |
| 270 return; |
| 271 #endif // !SK_ALLOW_LARGE_PDF_SCALARS |
| 272 |
| 273 #if defined(SK_ALLOW_LARGE_PDF_SCALARS) |
| 274 // Floats have 24bits of significance, so anything outside that range is |
| 275 // no more precise than an int. (Plus PDF doesn't support scientific |
| 276 // notation, so this clamps to SK_Max/MinS32). |
| 277 if (value > (1 << 24) || value < -(1 << 24)) { |
| 278 stream->writeDecAsText(value); |
| 279 return; |
| 280 } |
| 281 // Continue to enforce the PDF limits for small floats. |
| 282 if (value < 1.0f/65536 && value > -1.0f/65536) { |
| 283 stream->writeDecAsText(0); |
| 284 return; |
| 285 } |
| 286 // SkStrAppendFloat might still use scientific notation, so use snprintf |
| 287 // directly.. |
| 288 static const int kFloat_MaxSize = 19; |
| 289 char buffer[kFloat_MaxSize]; |
| 290 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); |
| 291 // %f always prints trailing 0s, so strip them. |
| 292 for (; buffer[len - 1] == '0' && len > 0; len--) { |
| 293 buffer[len - 1] = '\0'; |
| 294 } |
| 295 if (buffer[len - 1] == '.') { |
| 296 buffer[len - 1] = '\0'; |
| 297 } |
| 298 stream->writeText(buffer); |
| 299 return; |
| 300 #endif // SK_ALLOW_LARGE_PDF_SCALARS |
| 301 } |
| 302 |
| 303 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { |
| 304 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
| 305 SkASSERT(len <= kMaxLen); |
| 306 |
| 307 // 7-bit clean is a heuristic to decide what string format to use; |
| 308 // a 7-bit clean string should require little escaping. |
| 309 bool sevenBitClean = true; |
| 310 size_t characterCount = 2 + len; |
| 311 for (size_t i = 0; i < len; i++) { |
| 312 if (cin[i] > '~' || cin[i] < ' ') { |
| 313 sevenBitClean = false; |
| 314 break; |
| 315 } |
| 316 if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') { |
| 317 ++characterCount; |
| 318 } |
| 319 } |
| 320 SkString result; |
| 321 if (sevenBitClean) { |
| 322 result.resize(characterCount); |
| 323 char* str = result.writable_str(); |
| 324 *str++ = '('; |
| 325 for (size_t i = 0; i < len; i++) { |
| 326 if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') { |
| 327 *str++ = '\\'; |
| 328 } |
| 329 *str++ = cin[i]; |
| 330 } |
| 331 *str++ = ')'; |
| 332 } else { |
| 333 result.resize(2 * len + 2); |
| 334 char* str = result.writable_str(); |
| 335 *str++ = '<'; |
| 336 for (size_t i = 0; i < len; i++) { |
| 337 uint8_t c = static_cast<uint8_t>(cin[i]); |
| 338 static const char gHex[] = "0123456789ABCDEF"; |
| 339 *str++ = gHex[(c >> 4) & 0xF]; |
| 340 *str++ = gHex[(c ) & 0xF]; |
| 341 } |
| 342 *str++ = '>'; |
| 343 } |
| 344 return result; |
| 345 } |
OLD | NEW |