| 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 |