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 |