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 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 value, SkWStream* stream) { |
257 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and | 259 char result[kMaximumFloatDecimalLength]; |
258 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). | 260 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); |
259 // When using floats that are outside the whole value range, we can use | 261 SkASSERT(len < kMaximumFloatDecimalLength); |
260 // integers instead. | 262 stream->write(result, len); |
263 } | |
261 | 264 |
262 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) | 265 /** Write a string into result, includeing a terminating '\0' (for |
tomhudson
2016/02/24 20:10:56
nit: including
| |
263 if (value > 32767 || value < -32767) { | 266 unit testing). Return strlen(result) (for SkWStream::write) The |
264 stream->writeDecAsText(SkScalarRoundToInt(value)); | 267 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and |
265 return; | 268 sscanf(result, "%f", &x) will return the original value iff the |
269 value is finite. This function accepts all possible input values. | |
270 | |
271 Motivation: "PDF does not support [numbers] in exponential format | |
272 (such as 6.02e23)." Otherwise, this function would rely on a | |
273 sprintf-type function from the standard library. */ | |
274 size_t SkPDFUtils::FloatToDecimal(float value, | |
275 char result[kMaximumFloatDecimalLength]) { | |
276 /* The longest result is -FLT_MIN. | |
277 We serialize it as "-.0000000000000000000000000000000000000117549435" | |
278 which has 48 characters plus a terminating '\0'. */ | |
279 | |
280 /* section C.1 of the PDF1.4 spec (http://goo.gl/0SCswJ) says that | |
281 most PDF rasterizers will use fixed-point scalars that lack the | |
282 dynamic range of floats. Even if this is the case, I want to | |
283 serialize these (uncommon) very small and very large scalar | |
284 values with enough precision to allow a floating-point | |
285 rasterizer to read them in with perfect accuracy. | |
286 Experimentally, rasterizers such as pdfium do seem to benefit | |
287 from this. Rasterizers that rely on fixed-point scalars should | |
288 gracefully ignore these values that they can not parse. */ | |
289 char* output = &result[0]; | |
290 const char* const end = &result[kMaximumFloatDecimalLength - 1]; | |
291 // subtract one to leave space for '\0'. | |
292 | |
293 /* This function is written to accept any possible input value, | |
294 including non-finite values such as INF and NAN. In that case, | |
295 we ignore value-correctness and and output a syntacticly-valid | |
296 number. */ | |
297 if (value == SK_FloatInfinity) { | |
298 value = FLT_MAX; // nearest finite float. | |
266 } | 299 } |
300 if (value == SK_FloatNegativeInfinity) { | |
301 value = -FLT_MAX; // nearest finite float. | |
302 } | |
303 if (!std::isfinite(value) || value == 0.0f) { | |
304 // NAN is unsupported in PDF. Always output a valid number. | |
305 // Also catch zero here, as a special case. | |
306 *output++ = '0'; | |
307 *output = '\0'; | |
308 return output - result; | |
309 } | |
310 // Inspired by: | |
311 // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal- conversion/ | |
267 | 312 |
268 char buffer[SkStrAppendScalar_MaxSize]; | 313 if (value < 0.0) { |
269 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); | 314 *output++ = '-'; |
270 stream->write(buffer, end - buffer); | 315 value = -value; |
271 return; | 316 } |
272 #endif // !SK_ALLOW_LARGE_PDF_SCALARS | 317 SkASSERT(value >= 0.0f); |
273 | 318 |
274 #if defined(SK_ALLOW_LARGE_PDF_SCALARS) | 319 // Must use double math to keep precision right. |
275 // Floats have 24bits of significance, so anything outside that range is | 320 double intPart; |
276 // no more precise than an int. (Plus PDF doesn't support scientific | 321 double fracPart = std::modf(static_cast<double>(value), &intPart); |
277 // notation, so this clamps to SK_Max/MinS32). | 322 SkASSERT(intPart + fracPart == static_cast<double>(value)); |
278 if (value > (1 << 24) || value < -(1 << 24)) { | 323 size_t significantDigits = 0; |
279 stream->writeDecAsText(value); | 324 const size_t maxSignificantDigits = 9; |
280 return; | 325 // Any fewer significant digits loses precision. The unit test |
326 // checks round-trip correctness. | |
327 SkASSERT(intPart >= 0.0 && fracPart >= 0.0); // negative handled already. | |
328 SkASSERT(intPart > 0.0 || fracPart > 0.0); // zero already caught. | |
329 if (intPart > 0.0) { | |
330 // put the intPart digits onto a stack for later reversal. | |
331 char reversed[1 + FLT_MAX_10_EXP]; // 39 == 1 + FLT_MAX_10_EXP | |
332 // the largest integer part is FLT_MAX; it has 39 decimal digits. | |
333 size_t reversedIndex = 0; | |
334 do { | |
335 SkASSERT(reversedIndex < sizeof(reversed)); | |
336 int digit = static_cast<int>(std::fmod(intPart, 10.0)); | |
337 SkASSERT(digit >= 0 && digit <= 9); | |
338 reversed[reversedIndex++] = '0' + digit; | |
339 intPart = std::floor(intPart / 10.0); | |
340 } while (intPart > 0.0); | |
341 significantDigits = reversedIndex; | |
342 SkASSERT(reversedIndex <= sizeof(reversed)); | |
343 SkASSERT(output + reversedIndex <= end); | |
344 while (reversedIndex-- > 0) { // pop from stack, append to result | |
345 *output++ = reversed[reversedIndex]; | |
346 } | |
281 } | 347 } |
282 // Continue to enforce the PDF limits for small floats. | 348 if (fracPart > 0 && significantDigits < maxSignificantDigits) { |
283 if (value < 1.0f/65536 && value > -1.0f/65536) { | 349 *output++ = '.'; |
284 stream->writeDecAsText(0); | 350 SkASSERT(output <= end); |
285 return; | 351 do { |
352 fracPart = std::modf(fracPart * 10.0, &intPart); | |
353 int digit = static_cast<int>(intPart); | |
354 SkASSERT(digit >= 0 && digit <= 9); | |
355 *output++ = '0' + digit; | |
356 SkASSERT(output <= end); | |
357 if (digit > 0 || significantDigits > 0) { | |
358 // start counting significantDigits after first non-zero digit. | |
359 ++significantDigits; | |
360 } | |
361 } while (fracPart > 0.0 | |
362 && significantDigits < maxSignificantDigits | |
363 && output < end); | |
364 // When fracPart == 0, additional digits will be zero. | |
365 // When significantDigits == maxSignificantDigits, we can stop. | |
366 // when output == end, we have filed the string. | |
367 // Note: denormalized numbers will not have the same number of | |
368 // significantDigits, but do not need them to round-trip. | |
286 } | 369 } |
287 // SkStrAppendFloat might still use scientific notation, so use snprintf | 370 SkASSERT(output <= end); |
288 // directly.. | 371 *output = '\0'; |
289 static const int kFloat_MaxSize = 19; | 372 return output - result; |
290 char buffer[kFloat_MaxSize]; | |
291 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); | |
292 // %f always prints trailing 0s, so strip them. | |
293 for (; buffer[len - 1] == '0' && len > 0; len--) { | |
294 buffer[len - 1] = '\0'; | |
295 } | |
296 if (buffer[len - 1] == '.') { | |
297 buffer[len - 1] = '\0'; | |
298 } | |
299 stream->writeText(buffer); | |
300 return; | |
301 #endif // SK_ALLOW_LARGE_PDF_SCALARS | |
302 } | 373 } |
303 | 374 |
304 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { | 375 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { |
305 SkDEBUGCODE(static const size_t kMaxLen = 65535;) | 376 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
306 SkASSERT(len <= kMaxLen); | 377 SkASSERT(len <= kMaxLen); |
307 | 378 |
308 // 7-bit clean is a heuristic to decide what string format to use; | 379 // 7-bit clean is a heuristic to decide what string format to use; |
309 // a 7-bit clean string should require little escaping. | 380 // a 7-bit clean string should require little escaping. |
310 bool sevenBitClean = true; | 381 bool sevenBitClean = true; |
311 size_t characterCount = 2 + len; | 382 size_t characterCount = 2 + len; |
(...skipping 25 matching lines...) Expand all Loading... | |
337 for (size_t i = 0; i < len; i++) { | 408 for (size_t i = 0; i < len; i++) { |
338 uint8_t c = static_cast<uint8_t>(cin[i]); | 409 uint8_t c = static_cast<uint8_t>(cin[i]); |
339 static const char gHex[] = "0123456789ABCDEF"; | 410 static const char gHex[] = "0123456789ABCDEF"; |
340 *str++ = gHex[(c >> 4) & 0xF]; | 411 *str++ = gHex[(c >> 4) & 0xF]; |
341 *str++ = gHex[(c ) & 0xF]; | 412 *str++ = gHex[(c ) & 0xF]; |
342 } | 413 } |
343 *str++ = '>'; | 414 *str++ = '>'; |
344 } | 415 } |
345 return result; | 416 return result; |
346 } | 417 } |
OLD | NEW |