Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(328)

Side by Side Diff: src/pdf/SkPDFUtils.cpp

Issue 1720863003: SkPDF: fix scalar serialization (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/skbug_4868.cpp ('k') | tests/PDFPrimitivesTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « gm/skbug_4868.cpp ('k') | tests/PDFPrimitivesTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698