Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * 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 |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 | 8 |
| 9 #include "SkData.h" | 9 #include "SkData.h" |
| 10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
| 11 #include "SkPaint.h" | 11 #include "SkPaint.h" |
| 12 #include "SkPath.h" | 12 #include "SkPath.h" |
| 13 #include "SkPDFResourceDict.h" | 13 #include "SkPDFResourceDict.h" |
| 14 #include "SkPDFUtils.h" | 14 #include "SkPDFUtils.h" |
| 15 #include "SkStream.h" | 15 #include "SkStream.h" |
| 16 #include "SkString.h" | 16 #include "SkString.h" |
| 17 #include "SkPDFTypes.h" | 17 #include "SkPDFTypes.h" |
| 18 | 18 |
| 19 #include <cmath> | |
| 20 | |
| 19 //static | 21 //static |
| 20 SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) { | 22 SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) { |
| 21 SkPDFArray* result = new SkPDFArray(); | 23 SkPDFArray* result = new SkPDFArray(); |
| 22 result->reserve(4); | 24 result->reserve(4); |
| 23 result->appendScalar(rect.fLeft); | 25 result->appendScalar(rect.fLeft); |
| 24 result->appendScalar(rect.fTop); | 26 result->appendScalar(rect.fTop); |
| 25 result->appendScalar(rect.fRight); | 27 result->appendScalar(rect.fRight); |
| 26 result->appendScalar(rect.fBottom); | 28 result->appendScalar(rect.fBottom); |
| 27 return result; | 29 return result; |
| 28 } | 30 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 SkString resourceName = SkPDFResourceDict::getResourceName( | 248 SkString resourceName = SkPDFResourceDict::getResourceName( |
| 247 SkPDFResourceDict::kPattern_ResourceType, | 249 SkPDFResourceDict::kPattern_ResourceType, |
| 248 objectIndex); | 250 objectIndex); |
| 249 content->writeText("/Pattern CS/Pattern cs/"); | 251 content->writeText("/Pattern CS/Pattern cs/"); |
| 250 content->writeText(resourceName.c_str()); | 252 content->writeText(resourceName.c_str()); |
| 251 content->writeText(" SCN/"); | 253 content->writeText(" SCN/"); |
| 252 content->writeText(resourceName.c_str()); | 254 content->writeText(resourceName.c_str()); |
| 253 content->writeText(" scn\n"); | 255 content->writeText(" scn\n"); |
| 254 } | 256 } |
| 255 | 257 |
| 256 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { | 258 void SkPDFUtils::AppendScalar(SkScalar v, SkWStream* stream) { |
| 257 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and | 259 if (v == SK_FloatInfinity) { |
| 258 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). | 260 v = FLT_MAX; // nearest finite float. |
| 259 // When using floats that are outside the whole value range, we can use | 261 } |
| 260 // integers instead. | 262 if (v == SK_FloatNegativeInfinity) { |
| 261 | 263 v = -FLT_MAX; // nearest finite float. |
| 262 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) | 264 } |
| 263 if (value > 32767 || value < -32767) { | 265 if (!isfinite(v)) { |
| 264 stream->writeDecAsText(SkScalarRoundToInt(value)); | 266 stream->writeText("0"); // Unsupported number in PDF |
| 265 return; | 267 return; |
| 266 } | 268 } |
| 267 | 269 // "PDF does not support [numbers] in exponential format (such as 6.02e23)" |
| 268 char buffer[SkStrAppendScalar_MaxSize]; | 270 // Inspired by: |
| 269 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); | 271 // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal- conversion/ |
| 270 stream->write(buffer, end - buffer); | 272 // Must use double math to keep precision right. |
| 271 return; | 273 double value = static_cast<double>(v); |
| 272 #endif // !SK_ALLOW_LARGE_PDF_SCALARS | 274 char result[1076]; |
| 273 | 275 size_t resultIndex = 0; |
| 274 #if defined(SK_ALLOW_LARGE_PDF_SCALARS) | 276 if (value < 0.0) { |
| 275 // Floats have 24bits of significance, so anything outside that range is | 277 result[resultIndex++] = '-'; |
| 276 // no more precise than an int. (Plus PDF doesn't support scientific | 278 value = -value; |
| 277 // notation, so this clamps to SK_Max/MinS32). | 279 } |
| 278 if (value > (1 << 24) || value < -(1 << 24)) { | 280 double intPart; |
| 279 stream->writeDecAsText(value); | 281 double fracPart = std::modf(value, &intPart); |
| 282 size_t significantDigits = 0; | |
| 283 const size_t maxSignificantDigits = 9; // any less loses precision | |
|
tomhudson
2016/02/22 20:13:46
With a 32b signed fixed, can't we have 10 signific
hal.canary
2016/02/22 22:45:38
Ah, but we don't have a fixed-point input. SkScal
| |
| 284 SkASSERT(intPart >= 0.0 && fracPart >= 0.0); | |
|
tomhudson
2016/02/22 20:13:46
What happened to negative numbers? std::modf() "[D
hal.canary
2016/02/22 22:45:38
I already dealt with negative number.
tomhudson
2016/02/24 20:10:56
Acknowledged.
| |
| 285 if (intPart == 0.0 && fracPart == 0.0) { | |
| 286 stream->writeText("0"); // Unsupported number in PDF | |
|
tomhudson
2016/02/22 20:13:46
Why is 0 unsupported?
hal.canary
2016/02/22 22:45:38
cut-and-paste error.
| |
| 280 return; | 287 return; |
| 281 } | 288 } |
| 282 // Continue to enforce the PDF limits for small floats. | 289 if (intPart > 0.0) { |
|
tomhudson
2016/02/22 20:13:46
This code looks like it was hard to write; it shou
| |
| 283 if (value < 1.0f/65536 && value > -1.0f/65536) { | 290 char reversed[311]; |
|
tomhudson
2016/02/22 20:13:46
What's with the magic number 311? No idea how you
hal.canary
2016/02/22 22:45:38
that's a holdover from the double code. I did som
| |
| 284 stream->writeDecAsText(0); | 291 size_t reveredIndex = 0; |
|
tomhudson
2016/02/22 20:13:46
Why is this index holy or particularly esteemed? (
hal.canary
2016/02/22 22:45:38
done
| |
| 285 return; | 292 while (intPart > 0.0) { |
| 293 SkASSERT(reveredIndex < sizeof(reversed)); | |
| 294 int digit = static_cast<int>(std::fmod(intPart, 10.0)); | |
| 295 SkASSERT(digit >= 0 && digit <= 9); | |
| 296 reversed[reveredIndex++] = '0' + digit; | |
| 297 intPart = std::floor(intPart / 10.0); | |
| 298 } | |
| 299 significantDigits = reveredIndex; | |
| 300 while (reveredIndex-- > 0) { | |
| 301 result[resultIndex++] = reversed[reveredIndex]; | |
| 302 SkASSERT(resultIndex <= sizeof(result)); | |
| 303 } | |
| 286 } | 304 } |
| 287 // SkStrAppendFloat might still use scientific notation, so use snprintf | 305 if (fracPart > 0 && significantDigits < maxSignificantDigits) { |
| 288 // directly.. | 306 result[resultIndex++] = '.'; |
| 289 static const int kFloat_MaxSize = 19; | 307 SkASSERT(resultIndex <= sizeof(result)); |
| 290 char buffer[kFloat_MaxSize]; | 308 do { |
| 291 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); | 309 fracPart *= 10.0; |
| 292 // %f always prints trailing 0s, so strip them. | 310 fracPart = std::modf(fracPart, &intPart); |
| 293 for (; buffer[len - 1] == '0' && len > 0; len--) { | 311 int digit = static_cast<int>(intPart); |
| 294 buffer[len - 1] = '\0'; | 312 result[resultIndex++] = '0' + digit; |
| 313 SkASSERT(digit >= 0 && digit <= 9); | |
| 314 SkASSERT(resultIndex <= sizeof(result)); | |
| 315 if (digit > 0 || significantDigits > 0) { | |
| 316 ++significantDigits; | |
| 317 } | |
| 318 } while (fracPart > 0 && significantDigits < maxSignificantDigits); | |
| 319 | |
| 295 } | 320 } |
| 296 if (buffer[len - 1] == '.') { | 321 stream->write(result, resultIndex); |
| 297 buffer[len - 1] = '\0'; | |
| 298 } | |
| 299 stream->writeText(buffer); | |
| 300 return; | |
| 301 #endif // SK_ALLOW_LARGE_PDF_SCALARS | |
| 302 } | 322 } |
| 303 | 323 |
| 304 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { | 324 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { |
| 305 SkDEBUGCODE(static const size_t kMaxLen = 65535;) | 325 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
| 306 SkASSERT(len <= kMaxLen); | 326 SkASSERT(len <= kMaxLen); |
| 307 | 327 |
| 308 // 7-bit clean is a heuristic to decide what string format to use; | 328 // 7-bit clean is a heuristic to decide what string format to use; |
| 309 // a 7-bit clean string should require little escaping. | 329 // a 7-bit clean string should require little escaping. |
| 310 bool sevenBitClean = true; | 330 bool sevenBitClean = true; |
| 311 size_t characterCount = 2 + len; | 331 size_t characterCount = 2 + len; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 337 for (size_t i = 0; i < len; i++) { | 357 for (size_t i = 0; i < len; i++) { |
| 338 uint8_t c = static_cast<uint8_t>(cin[i]); | 358 uint8_t c = static_cast<uint8_t>(cin[i]); |
| 339 static const char gHex[] = "0123456789ABCDEF"; | 359 static const char gHex[] = "0123456789ABCDEF"; |
| 340 *str++ = gHex[(c >> 4) & 0xF]; | 360 *str++ = gHex[(c >> 4) & 0xF]; |
| 341 *str++ = gHex[(c ) & 0xF]; | 361 *str++ = gHex[(c ) & 0xF]; |
| 342 } | 362 } |
| 343 *str++ = '>'; | 363 *str++ = '>'; |
| 344 } | 364 } |
| 345 return result; | 365 return result; |
| 346 } | 366 } |
| OLD | NEW |