1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkPDFDevice.h" 9 10 #include "SkAnnotation.h" 11 #include "SkColor.h" 12 #include "SkClipStack.h" 13 #include "SkData.h" 14 #include "SkDraw.h" 15 #include "SkGlyphCache.h" 16 #include "SkPaint.h" 17 #include "SkPath.h" 18 #include "SkPathOps.h" 19 #include "SkPDFBitmap.h" 20 #include "SkPDFFont.h" 21 #include "SkPDFFormXObject.h" 22 #include "SkPDFGraphicState.h" 23 #include "SkPDFResourceDict.h" 24 #include "SkPDFShader.h" 25 #include "SkPDFStream.h" 26 #include "SkPDFTypes.h" 27 #include "SkPDFUtils.h" 28 #include "SkRect.h" 29 #include "SkRRect.h" 30 #include "SkString.h" 31 #include "SkSurface.h" 32 #include "SkTextFormatParams.h" 33 #include "SkTemplates.h" 34 #include "SkTypefacePriv.h" 35 #include "SkXfermodeInterpretation.h" 36 37 #define DPI_FOR_RASTER_SCALE_ONE 72 38 39 // Utility functions 40 41 // If the paint will definitely draw opaquely, replace kSrc_Mode with 42 // kSrcOver_Mode. http://crbug.com/473572 43 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { 44 if (kSrcOver_SkXfermodeInterpretation 45 == SkInterpretXfermode(*paint, false)) { 46 paint->setXfermode(NULL); 47 } 48 } 49 50 static void emit_pdf_color(SkColor color, SkWStream* result) { 51 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. 52 SkScalar colorScale = SkScalarInvert(0xFF); 53 SkPDFUtils::AppendScalar(SkColorGetR(color) * colorScale, result); 54 result->writeText(" "); 55 SkPDFUtils::AppendScalar(SkColorGetG(color) * colorScale, result); 56 result->writeText(" "); 57 SkPDFUtils::AppendScalar(SkColorGetB(color) * colorScale, result); 58 result->writeText(" "); 59 } 60 61 static SkPaint calculate_text_paint(const SkPaint& paint) { 62 SkPaint result = paint; 63 if (result.isFakeBoldText()) { 64 SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(), 65 kStdFakeBoldInterpKeys, 66 kStdFakeBoldInterpValues, 67 kStdFakeBoldInterpLength); 68 SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); 69 if (result.getStyle() == SkPaint::kFill_Style) { 70 result.setStyle(SkPaint::kStrokeAndFill_Style); 71 } else { 72 width += result.getStrokeWidth(); 73 } 74 result.setStrokeWidth(width); 75 } 76 return result; 77 } 78 79 // Stolen from measure_text in SkDraw.cpp and then tweaked. 80 static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, 81 const uint16_t* glyphs, size_t len, 82 SkScalar* x, SkScalar* y) { 83 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 84 return; 85 } 86 87 SkMatrix ident; 88 ident.reset(); 89 SkAutoGlyphCache autoCache(paint, NULL, &ident); 90 SkGlyphCache* cache = autoCache.getCache(); 91 92 const char* start = reinterpret_cast<const char*>(glyphs); 93 const char* stop = reinterpret_cast<const char*>(glyphs + len); 94 SkFixed xAdv = 0, yAdv = 0; 95 96 // TODO(vandebo): This probably needs to take kerning into account. 97 while (start < stop) { 98 const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0); 99 xAdv += glyph.fAdvanceX; 100 yAdv += glyph.fAdvanceY; 101 }; 102 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 103 return; 104 } 105 106 SkScalar xAdj = SkFixedToScalar(xAdv); 107 SkScalar yAdj = SkFixedToScalar(yAdv); 108 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 109 xAdj = SkScalarHalf(xAdj); 110 yAdj = SkScalarHalf(yAdj); 111 } 112 *x = *x - xAdj; 113 *y = *y - yAdj; 114 } 115 116 static int max_glyphid_for_typeface(SkTypeface* typeface) { 117 SkAutoResolveDefaultTypeface autoResolve(typeface); 118 typeface = autoResolve.get(); 119 return typeface->countGlyphs() - 1; 120 } 121 122 typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage; 123 124 static int force_glyph_encoding(const SkPaint& paint, const void* text, 125 size_t len, SkGlyphStorage* storage, 126 const uint16_t** glyphIDs) { 127 // Make sure we have a glyph id encoding. 128 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 129 int numGlyphs = paint.textToGlyphs(text, len, NULL); 130 storage->reset(numGlyphs); 131 paint.textToGlyphs(text, len, storage->get()); 132 *glyphIDs = storage->get(); 133 return numGlyphs; 134 } 135 136 // For user supplied glyph ids we need to validate them. 137 SkASSERT((len & 1) == 0); 138 int numGlyphs = SkToInt(len / 2); 139 const uint16_t* input = static_cast<const uint16_t*>(text); 140 141 int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface()); 142 int validated; 143 for (validated = 0; validated < numGlyphs; ++validated) { 144 if (input[validated] > maxGlyphID) { 145 break; 146 } 147 } 148 if (validated >= numGlyphs) { 149 *glyphIDs = static_cast<const uint16_t*>(text); 150 return numGlyphs; 151 } 152 153 // Silently drop anything out of range. 154 storage->reset(numGlyphs); 155 if (validated > 0) { 156 memcpy(storage->get(), input, validated * sizeof(uint16_t)); 157 } 158 159 for (int i = validated; i < numGlyphs; ++i) { 160 storage->get()[i] = input[i]; 161 if (input[i] > maxGlyphID) { 162 storage->get()[i] = 0; 163 } 164 } 165 *glyphIDs = storage->get(); 166 return numGlyphs; 167 } 168 169 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 170 SkWStream* content) { 171 // Flip the text about the x-axis to account for origin swap and include 172 // the passed parameters. 173 content->writeText("1 0 "); 174 SkPDFUtils::AppendScalar(0 - textSkewX, content); 175 content->writeText(" -1 "); 176 SkPDFUtils::AppendScalar(x, content); 177 content->writeText(" "); 178 SkPDFUtils::AppendScalar(y, content); 179 content->writeText(" Tm\n"); 180 } 181 182 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 183 // later being our representation of an object in the PDF file. 184 struct GraphicStateEntry { 185 GraphicStateEntry(); 186 187 // Compare the fields we care about when setting up a new content entry. 188 bool compareInitialState(const GraphicStateEntry& b); 189 190 SkMatrix fMatrix; 191 // We can't do set operations on Paths, though PDF natively supports 192 // intersect. If the clip stack does anything other than intersect, 193 // we have to fall back to the region. Treat fClipStack as authoritative. 194 // See http://code.google.com/p/skia/issues/detail?id=221 195 SkClipStack fClipStack; 196 SkRegion fClipRegion; 197 198 // When emitting the content entry, we will ensure the graphic state 199 // is set to these values first. 200 SkColor fColor; 201 SkScalar fTextScaleX; // Zero means we don't care what the value is. 202 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 203 int fShaderIndex; 204 int fGraphicStateIndex; 205 206 // We may change the font (i.e. for Type1 support) within a 207 // ContentEntry. This is the one currently in effect, or NULL if none. 208 SkPDFFont* fFont; 209 // In PDF, text size has no default value. It is only valid if fFont is 210 // not NULL. 211 SkScalar fTextSize; 212 }; 213 214 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK), 215 fTextScaleX(SK_Scalar1), 216 fTextFill(SkPaint::kFill_Style), 217 fShaderIndex(-1), 218 fGraphicStateIndex(-1), 219 fFont(NULL), 220 fTextSize(SK_ScalarNaN) { 221 fMatrix.reset(); 222 } 223 224 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) { 225 return fColor == cur.fColor && 226 fShaderIndex == cur.fShaderIndex && 227 fGraphicStateIndex == cur.fGraphicStateIndex && 228 fMatrix == cur.fMatrix && 229 fClipStack == cur.fClipStack && 230 (fTextScaleX == 0 || 231 (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill)); 232 } 233 234 class GraphicStackState { 235 public: 236 GraphicStackState(const SkClipStack& existingClipStack, 237 const SkRegion& existingClipRegion, 238 SkWStream* contentStream) 239 : fStackDepth(0), 240 fContentStream(contentStream) { 241 fEntries[0].fClipStack = existingClipStack; 242 fEntries[0].fClipRegion = existingClipRegion; 243 } 244 245 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 246 const SkPoint& translation); 247 void updateMatrix(const SkMatrix& matrix); 248 void updateDrawingState(const GraphicStateEntry& state); 249 250 void drainStack(); 251 252 private: 253 void push(); 254 void pop(); 255 GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 256 257 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 258 static const int kMaxStackDepth = 12; 259 GraphicStateEntry fEntries[kMaxStackDepth + 1]; 260 int fStackDepth; 261 SkWStream* fContentStream; 262 }; 263 264 void GraphicStackState::drainStack() { 265 while (fStackDepth) { 266 pop(); 267 } 268 } 269 270 void GraphicStackState::push() { 271 SkASSERT(fStackDepth < kMaxStackDepth); 272 fContentStream->writeText("q\n"); 273 fStackDepth++; 274 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; 275 } 276 277 void GraphicStackState::pop() { 278 SkASSERT(fStackDepth > 0); 279 fContentStream->writeText("Q\n"); 280 fStackDepth--; 281 } 282 283 // This function initializes iter to be an iterator on the "stack" argument 284 // and then skips over the leading entries as specified in prefix. It requires 285 // and asserts that "prefix" will be a prefix to "stack." 286 static void skip_clip_stack_prefix(const SkClipStack& prefix, 287 const SkClipStack& stack, 288 SkClipStack::Iter* iter) { 289 SkClipStack::B2TIter prefixIter(prefix); 290 iter->reset(stack, SkClipStack::Iter::kBottom_IterStart); 291 292 const SkClipStack::Element* prefixEntry; 293 const SkClipStack::Element* iterEntry; 294 295 for (prefixEntry = prefixIter.next(); prefixEntry; 296 prefixEntry = prefixIter.next()) { 297 iterEntry = iter->next(); 298 SkASSERT(iterEntry); 299 // Because of SkClipStack does internal intersection, the last clip 300 // entry may differ. 301 if (*prefixEntry != *iterEntry) { 302 SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op); 303 SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op); 304 SkASSERT(iterEntry->getType() == prefixEntry->getType()); 305 // back up the iterator by one 306 iter->prev(); 307 prefixEntry = prefixIter.next(); 308 break; 309 } 310 } 311 312 SkASSERT(prefixEntry == NULL); 313 } 314 315 static void emit_clip(SkPath* clipPath, SkRect* clipRect, 316 SkWStream* contentStream) { 317 SkASSERT(clipPath || clipRect); 318 319 SkPath::FillType clipFill; 320 if (clipPath) { 321 SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream); 322 clipFill = clipPath->getFillType(); 323 } else { 324 SkPDFUtils::AppendRectangle(*clipRect, contentStream); 325 clipFill = SkPath::kWinding_FillType; 326 } 327 328 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); 329 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); 330 if (clipFill == SkPath::kEvenOdd_FillType) { 331 contentStream->writeText("W* n\n"); 332 } else { 333 contentStream->writeText("W n\n"); 334 } 335 } 336 337 /* Calculate an inverted path's equivalent non-inverted path, given the 338 * canvas bounds. 339 * outPath may alias with invPath (since this is supported by PathOps). 340 */ 341 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, 342 SkPath* outPath) { 343 SkASSERT(invPath.isInverseFillType()); 344 345 SkPath clipPath; 346 clipPath.addRect(bounds); 347 348 return Op(clipPath, invPath, kIntersect_PathOp, outPath); 349 } 350 351 #ifdef SK_PDF_USE_PATHOPS_CLIPPING 352 // Sanity check the numerical values of the SkRegion ops and PathOps ops 353 // enums so region_op_to_pathops_op can do a straight passthrough cast. 354 // If these are failing, it may be necessary to make region_op_to_pathops_op 355 // do more. 356 SK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp, 357 region_pathop_mismatch); 358 SK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp, 359 region_pathop_mismatch); 360 SK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp, 361 region_pathop_mismatch); 362 SK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp, 363 region_pathop_mismatch); 364 SK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op == 365 (int)kReverseDifference_PathOp, 366 region_pathop_mismatch); 367 368 static SkPathOp region_op_to_pathops_op(SkRegion::Op op) { 369 SkASSERT(op >= 0); 370 SkASSERT(op <= SkRegion::kReverseDifference_Op); 371 return (SkPathOp)op; 372 } 373 374 /* Uses Path Ops to calculate a vector SkPath clip from a clip stack. 375 * Returns true if successful, or false if not successful. 376 * If successful, the resulting clip is stored in outClipPath. 377 * If not successful, outClipPath is undefined, and a fallback method 378 * should be used. 379 */ 380 static bool get_clip_stack_path(const SkMatrix& transform, 381 const SkClipStack& clipStack, 382 const SkRegion& clipRegion, 383 SkPath* outClipPath) { 384 outClipPath->reset(); 385 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 386 387 const SkClipStack::Element* clipEntry; 388 SkClipStack::Iter iter; 389 iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart); 390 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 391 SkPath entryPath; 392 if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) { 393 outClipPath->reset(); 394 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 395 continue; 396 } else { 397 clipEntry->asPath(&entryPath); 398 } 399 entryPath.transform(transform); 400 401 if (SkRegion::kReplace_Op == clipEntry->getOp()) { 402 *outClipPath = entryPath; 403 } else { 404 SkPathOp op = region_op_to_pathops_op(clipEntry->getOp()); 405 if (!Op(*outClipPath, entryPath, op, outClipPath)) { 406 return false; 407 } 408 } 409 } 410 411 if (outClipPath->isInverseFillType()) { 412 // The bounds are slightly outset to ensure this is correct in the 413 // face of floating-point accuracy and possible SkRegion bitmap 414 // approximations. 415 SkRect clipBounds = SkRect::Make(clipRegion.getBounds()); 416 clipBounds.outset(SK_Scalar1, SK_Scalar1); 417 if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) { 418 return false; 419 } 420 } 421 return true; 422 } 423 #endif 424 425 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF 426 // graphic state stack, and the fact that we can know all the clips used 427 // on the page to optimize this. 428 void GraphicStackState::updateClip(const SkClipStack& clipStack, 429 const SkRegion& clipRegion, 430 const SkPoint& translation) { 431 if (clipStack == currentEntry()->fClipStack) { 432 return; 433 } 434 435 while (fStackDepth > 0) { 436 pop(); 437 if (clipStack == currentEntry()->fClipStack) { 438 return; 439 } 440 } 441 push(); 442 443 currentEntry()->fClipStack = clipStack; 444 currentEntry()->fClipRegion = clipRegion; 445 446 SkMatrix transform; 447 transform.setTranslate(translation.fX, translation.fY); 448 449 #ifdef SK_PDF_USE_PATHOPS_CLIPPING 450 SkPath clipPath; 451 if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { 452 emit_clip(&clipPath, NULL, fContentStream); 453 return; 454 } 455 #endif 456 // gsState->initialEntry()->fClipStack/Region specifies the clip that has 457 // already been applied. (If this is a top level device, then it specifies 458 // a clip to the content area. If this is a layer, then it specifies 459 // the clip in effect when the layer was created.) There's no need to 460 // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the 461 // initial clip on the parent layer. (This means there's a bug if the user 462 // expands the clip and then uses any xfer mode that uses dst: 463 // http://code.google.com/p/skia/issues/detail?id=228 ) 464 SkClipStack::Iter iter; 465 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 466 467 // If the clip stack does anything other than intersect or if it uses 468 // an inverse fill type, we have to fall back to the clip region. 469 bool needRegion = false; 470 const SkClipStack::Element* clipEntry; 471 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 472 if (clipEntry->getOp() != SkRegion::kIntersect_Op || 473 clipEntry->isInverseFilled()) { 474 needRegion = true; 475 break; 476 } 477 } 478 479 if (needRegion) { 480 SkPath clipPath; 481 SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); 482 emit_clip(&clipPath, NULL, fContentStream); 483 } else { 484 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 485 const SkClipStack::Element* clipEntry; 486 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 487 SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op); 488 switch (clipEntry->getType()) { 489 case SkClipStack::Element::kRect_Type: { 490 SkRect translatedClip; 491 transform.mapRect(&translatedClip, clipEntry->getRect()); 492 emit_clip(NULL, &translatedClip, fContentStream); 493 break; 494 } 495 default: { 496 SkPath translatedPath; 497 clipEntry->asPath(&translatedPath); 498 translatedPath.transform(transform, &translatedPath); 499 emit_clip(&translatedPath, NULL, fContentStream); 500 break; 501 } 502 } 503 } 504 } 505 } 506 507 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { 508 if (matrix == currentEntry()->fMatrix) { 509 return; 510 } 511 512 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { 513 SkASSERT(fStackDepth > 0); 514 SkASSERT(fEntries[fStackDepth].fClipStack == 515 fEntries[fStackDepth -1].fClipStack); 516 pop(); 517 518 SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask); 519 } 520 if (matrix.getType() == SkMatrix::kIdentity_Mask) { 521 return; 522 } 523 524 push(); 525 SkPDFUtils::AppendTransform(matrix, fContentStream); 526 currentEntry()->fMatrix = matrix; 527 } 528 529 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 530 // PDF treats a shader as a color, so we only set one or the other. 531 if (state.fShaderIndex >= 0) { 532 if (state.fShaderIndex != currentEntry()->fShaderIndex) { 533 SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream); 534 currentEntry()->fShaderIndex = state.fShaderIndex; 535 } 536 } else { 537 if (state.fColor != currentEntry()->fColor || 538 currentEntry()->fShaderIndex >= 0) { 539 emit_pdf_color(state.fColor, fContentStream); 540 fContentStream->writeText("RG "); 541 emit_pdf_color(state.fColor, fContentStream); 542 fContentStream->writeText("rg\n"); 543 currentEntry()->fColor = state.fColor; 544 currentEntry()->fShaderIndex = -1; 545 } 546 } 547 548 if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) { 549 SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream); 550 currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex; 551 } 552 553 if (state.fTextScaleX) { 554 if (state.fTextScaleX != currentEntry()->fTextScaleX) { 555 SkScalar pdfScale = SkScalarMul(state.fTextScaleX, 556 SkIntToScalar(100)); 557 SkPDFUtils::AppendScalar(pdfScale, fContentStream); 558 fContentStream->writeText(" Tz\n"); 559 currentEntry()->fTextScaleX = state.fTextScaleX; 560 } 561 if (state.fTextFill != currentEntry()->fTextFill) { 562 SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); 563 SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, 564 enum_must_match_value); 565 SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, 566 enum_must_match_value); 567 fContentStream->writeDecAsText(state.fTextFill); 568 fContentStream->writeText(" Tr\n"); 569 currentEntry()->fTextFill = state.fTextFill; 570 } 571 } 572 } 573 574 static bool not_supported_for_layers(const SkPaint& layerPaint) { 575 // PDF does not support image filters, so render them on CPU. 576 // Note that this rendering is done at "screen" resolution (100dpi), not 577 // printer resolution. 578 // FIXME: It may be possible to express some filters natively using PDF 579 // to improve quality and file size (http://skbug.com/3043) 580 581 // TODO: should we return true if there is a colorfilter? 582 return layerPaint.getImageFilter() != NULL; 583 } 584 585 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) { 586 if (cinfo.fForImageFilter || 587 (layerPaint && not_supported_for_layers(*layerPaint))) { 588 return NULL; 589 } 590 SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height()); 591 return SkPDFDevice::Create(size, fRasterDpi, fCanon); 592 } 593 594 595 struct ContentEntry { 596 GraphicStateEntry fState; 597 SkDynamicMemoryWStream fContent; 598 SkAutoTDelete<ContentEntry> fNext; 599 600 // If the stack is too deep we could get Stack Overflow. 601 // So we manually destruct the object. 602 ~ContentEntry() { 603 ContentEntry* val = fNext.detach(); 604 while (val != NULL) { 605 ContentEntry* valNext = val->fNext.detach(); 606 // When the destructor is called, fNext is NULL and exits. 607 delete val; 608 val = valNext; 609 } 610 } 611 }; 612 613 // A helper class to automatically finish a ContentEntry at the end of a 614 // drawing method and maintain the state needed between set up and finish. 615 class ScopedContentEntry { 616 public: 617 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 618 const SkPaint& paint, bool hasText = false) 619 : fDevice(device), 620 fContentEntry(NULL), 621 fXfermode(SkXfermode::kSrcOver_Mode), 622 fDstFormXObject(NULL) { 623 init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText); 624 } 625 ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, 626 const SkRegion& clipRegion, const SkMatrix& matrix, 627 const SkPaint& paint, bool hasText = false) 628 : fDevice(device), 629 fContentEntry(NULL), 630 fXfermode(SkXfermode::kSrcOver_Mode), 631 fDstFormXObject(NULL) { 632 init(clipStack, clipRegion, matrix, paint, hasText); 633 } 634 635 ~ScopedContentEntry() { 636 if (fContentEntry) { 637 SkPath* shape = &fShape; 638 if (shape->isEmpty()) { 639 shape = NULL; 640 } 641 fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape); 642 } 643 SkSafeUnref(fDstFormXObject); 644 } 645 646 ContentEntry* entry() { return fContentEntry; } 647 648 /* Returns true when we explicitly need the shape of the drawing. */ 649 bool needShape() { 650 switch (fXfermode) { 651 case SkXfermode::kClear_Mode: 652 case SkXfermode::kSrc_Mode: 653 case SkXfermode::kSrcIn_Mode: 654 case SkXfermode::kSrcOut_Mode: 655 case SkXfermode::kDstIn_Mode: 656 case SkXfermode::kDstOut_Mode: 657 case SkXfermode::kSrcATop_Mode: 658 case SkXfermode::kDstATop_Mode: 659 case SkXfermode::kModulate_Mode: 660 return true; 661 default: 662 return false; 663 } 664 } 665 666 /* Returns true unless we only need the shape of the drawing. */ 667 bool needSource() { 668 if (fXfermode == SkXfermode::kClear_Mode) { 669 return false; 670 } 671 return true; 672 } 673 674 /* If the shape is different than the alpha component of the content, then 675 * setShape should be called with the shape. In particular, images and 676 * devices have rectangular shape. 677 */ 678 void setShape(const SkPath& shape) { 679 fShape = shape; 680 } 681 682 private: 683 SkPDFDevice* fDevice; 684 ContentEntry* fContentEntry; 685 SkXfermode::Mode fXfermode; 686 SkPDFFormXObject* fDstFormXObject; 687 SkPath fShape; 688 689 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 690 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 691 // Shape has to be flatten before we get here. 692 if (matrix.hasPerspective()) { 693 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); 694 return; 695 } 696 if (paint.getXfermode()) { 697 paint.getXfermode()->asMode(&fXfermode); 698 } 699 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 700 matrix, paint, hasText, 701 &fDstFormXObject); 702 } 703 }; 704 705 //////////////////////////////////////////////////////////////////////////////// 706 707 SkPDFDevice::SkPDFDevice(SkISize pageSize, 708 SkScalar rasterDpi, 709 SkPDFCanon* canon, 710 bool flip) 711 : fPageSize(pageSize) 712 , fContentSize(pageSize) 713 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) 714 , fAnnotations(NULL) 715 , fLastContentEntry(NULL) 716 , fLastMarginContentEntry(NULL) 717 , fDrawingArea(kContent_DrawingArea) 718 , fClipStack(NULL) 719 , fFontGlyphUsage(SkNEW(SkPDFGlyphSetMap)) 720 , fRasterDpi(rasterDpi) 721 , fCanon(canon) { 722 SkASSERT(pageSize.width() > 0); 723 SkASSERT(pageSize.height() > 0); 724 fLegacyBitmap.setInfo( 725 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); 726 if (flip) { 727 // Skia generally uses the top left as the origin but PDF 728 // natively has the origin at the bottom left. This matrix 729 // corrects for that. But that only needs to be done once, we 730 // don't do it when layering. 731 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); 732 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); 733 } else { 734 fInitialTransform.setIdentity(); 735 } 736 } 737 738 SkPDFDevice::~SkPDFDevice() { 739 this->cleanUp(true); 740 } 741 742 void SkPDFDevice::init() { 743 fAnnotations = NULL; 744 fContentEntries.free(); 745 fLastContentEntry = NULL; 746 fMarginContentEntries.free(); 747 fLastMarginContentEntry = NULL; 748 fDrawingArea = kContent_DrawingArea; 749 if (fFontGlyphUsage.get() == NULL) { 750 fFontGlyphUsage.reset(SkNEW(SkPDFGlyphSetMap)); 751 } 752 } 753 754 void SkPDFDevice::cleanUp(bool clearFontUsage) { 755 fGraphicStateResources.unrefAll(); 756 fXObjectResources.unrefAll(); 757 fFontResources.unrefAll(); 758 fShaderResources.unrefAll(); 759 SkSafeUnref(fAnnotations); 760 fNamedDestinations.deleteAll(); 761 762 if (clearFontUsage) { 763 fFontGlyphUsage->reset(); 764 } 765 } 766 767 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 768 SkPaint newPaint = paint; 769 replace_srcmode_on_opaque_paint(&newPaint); 770 771 newPaint.setStyle(SkPaint::kFill_Style); 772 ScopedContentEntry content(this, d, newPaint); 773 internalDrawPaint(newPaint, content.entry()); 774 } 775 776 void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 777 ContentEntry* contentEntry) { 778 if (!contentEntry) { 779 return; 780 } 781 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 782 SkIntToScalar(this->height())); 783 SkMatrix inverse; 784 if (!contentEntry->fState.fMatrix.invert(&inverse)) { 785 return; 786 } 787 inverse.mapRect(&bbox); 788 789 SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent); 790 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 791 &contentEntry->fContent); 792 } 793 794 void SkPDFDevice::drawPoints(const SkDraw& d, 795 SkCanvas::PointMode mode, 796 size_t count, 797 const SkPoint* points, 798 const SkPaint& srcPaint) { 799 SkPaint passedPaint = srcPaint; 800 replace_srcmode_on_opaque_paint(&passedPaint); 801 802 if (count == 0) { 803 return; 804 } 805 806 if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { 807 return; 808 } 809 810 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. 811 // We only use this when there's a path effect because of the overhead 812 // of multiple calls to setUpContentEntry it causes. 813 if (passedPaint.getPathEffect()) { 814 if (d.fClip->isEmpty()) { 815 return; 816 } 817 SkDraw pointDraw(d); 818 pointDraw.fDevice = this; 819 pointDraw.drawPoints(mode, count, points, passedPaint, true); 820 return; 821 } 822 823 const SkPaint* paint = &passedPaint; 824 SkPaint modifiedPaint; 825 826 if (mode == SkCanvas::kPoints_PointMode && 827 paint->getStrokeCap() != SkPaint::kRound_Cap) { 828 modifiedPaint = *paint; 829 paint = &modifiedPaint; 830 if (paint->getStrokeWidth()) { 831 // PDF won't draw a single point with square/butt caps because the 832 // orientation is ambiguous. Draw a rectangle instead. 833 modifiedPaint.setStyle(SkPaint::kFill_Style); 834 SkScalar strokeWidth = paint->getStrokeWidth(); 835 SkScalar halfStroke = SkScalarHalf(strokeWidth); 836 for (size_t i = 0; i < count; i++) { 837 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); 838 r.inset(-halfStroke, -halfStroke); 839 drawRect(d, r, modifiedPaint); 840 } 841 return; 842 } else { 843 modifiedPaint.setStrokeCap(SkPaint::kRound_Cap); 844 } 845 } 846 847 ScopedContentEntry content(this, d, *paint); 848 if (!content.entry()) { 849 return; 850 } 851 852 switch (mode) { 853 case SkCanvas::kPolygon_PointMode: 854 SkPDFUtils::MoveTo(points[0].fX, points[0].fY, 855 &content.entry()->fContent); 856 for (size_t i = 1; i < count; i++) { 857 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, 858 &content.entry()->fContent); 859 } 860 SkPDFUtils::StrokePath(&content.entry()->fContent); 861 break; 862 case SkCanvas::kLines_PointMode: 863 for (size_t i = 0; i < count/2; i++) { 864 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, 865 &content.entry()->fContent); 866 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, 867 points[i * 2 + 1].fY, 868 &content.entry()->fContent); 869 SkPDFUtils::StrokePath(&content.entry()->fContent); 870 } 871 break; 872 case SkCanvas::kPoints_PointMode: 873 SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); 874 for (size_t i = 0; i < count; i++) { 875 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, 876 &content.entry()->fContent); 877 SkPDFUtils::ClosePath(&content.entry()->fContent); 878 SkPDFUtils::StrokePath(&content.entry()->fContent); 879 } 880 break; 881 default: 882 SkASSERT(false); 883 } 884 } 885 886 void SkPDFDevice::drawRect(const SkDraw& d, 887 const SkRect& rect, 888 const SkPaint& srcPaint) { 889 SkPaint paint = srcPaint; 890 replace_srcmode_on_opaque_paint(&paint); 891 SkRect r = rect; 892 r.sort(); 893 894 if (paint.getPathEffect()) { 895 if (d.fClip->isEmpty()) { 896 return; 897 } 898 SkPath path; 899 path.addRect(r); 900 drawPath(d, path, paint, NULL, true); 901 return; 902 } 903 904 if (handleRectAnnotation(r, *d.fMatrix, paint)) { 905 return; 906 } 907 908 ScopedContentEntry content(this, d, paint); 909 if (!content.entry()) { 910 return; 911 } 912 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); 913 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 914 &content.entry()->fContent); 915 } 916 917 void SkPDFDevice::drawRRect(const SkDraw& draw, 918 const SkRRect& rrect, 919 const SkPaint& srcPaint) { 920 SkPaint paint = srcPaint; 921 replace_srcmode_on_opaque_paint(&paint); 922 SkPath path; 923 path.addRRect(rrect); 924 this->drawPath(draw, path, paint, NULL, true); 925 } 926 927 void SkPDFDevice::drawOval(const SkDraw& draw, 928 const SkRect& oval, 929 const SkPaint& srcPaint) { 930 SkPaint paint = srcPaint; 931 replace_srcmode_on_opaque_paint(&paint); 932 SkPath path; 933 path.addOval(oval); 934 this->drawPath(draw, path, paint, NULL, true); 935 } 936 937 void SkPDFDevice::drawPath(const SkDraw& d, 938 const SkPath& origPath, 939 const SkPaint& srcPaint, 940 const SkMatrix* prePathMatrix, 941 bool pathIsMutable) { 942 SkPaint paint = srcPaint; 943 replace_srcmode_on_opaque_paint(&paint); 944 SkPath modifiedPath; 945 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 946 947 SkMatrix matrix = *d.fMatrix; 948 if (prePathMatrix) { 949 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 950 if (!pathIsMutable) { 951 pathPtr = &modifiedPath; 952 pathIsMutable = true; 953 } 954 origPath.transform(*prePathMatrix, pathPtr); 955 } else { 956 matrix.preConcat(*prePathMatrix); 957 } 958 } 959 960 if (paint.getPathEffect()) { 961 if (d.fClip->isEmpty()) { 962 return; 963 } 964 if (!pathIsMutable) { 965 pathPtr = &modifiedPath; 966 pathIsMutable = true; 967 } 968 bool fill = paint.getFillPath(origPath, pathPtr); 969 970 SkPaint noEffectPaint(paint); 971 noEffectPaint.setPathEffect(NULL); 972 if (fill) { 973 noEffectPaint.setStyle(SkPaint::kFill_Style); 974 } else { 975 noEffectPaint.setStyle(SkPaint::kStroke_Style); 976 noEffectPaint.setStrokeWidth(0); 977 } 978 drawPath(d, *pathPtr, noEffectPaint, NULL, true); 979 return; 980 } 981 982 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { 983 return; 984 } 985 986 if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) { 987 return; 988 } 989 990 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 991 if (!content.entry()) { 992 return; 993 } 994 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), 995 &content.entry()->fContent); 996 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 997 &content.entry()->fContent); 998 } 999 1000 void SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1001 const SkRect* src, const SkRect& dst, 1002 const SkPaint& srcPaint, 1003 SkCanvas::DrawBitmapRectFlags flags) { 1004 SkPaint paint = srcPaint; 1005 if (bitmap.isOpaque()) { 1006 replace_srcmode_on_opaque_paint(&paint); 1007 } 1008 1009 // TODO: this code path must be updated to respect the flags parameter 1010 SkMatrix matrix; 1011 SkRect bitmapBounds, tmpSrc, tmpDst; 1012 SkBitmap tmpBitmap; 1013 1014 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 1015 1016 // Compute matrix from the two rectangles 1017 if (src) { 1018 tmpSrc = *src; 1019 } else { 1020 tmpSrc = bitmapBounds; 1021 } 1022 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1023 1024 const SkBitmap* bitmapPtr = &bitmap; 1025 1026 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 1027 // needed (if the src was clipped). No check needed if src==null. 1028 if (src) { 1029 if (!bitmapBounds.contains(*src)) { 1030 if (!tmpSrc.intersect(bitmapBounds)) { 1031 return; // nothing to draw 1032 } 1033 // recompute dst, based on the smaller tmpSrc 1034 matrix.mapRect(&tmpDst, tmpSrc); 1035 } 1036 1037 // since we may need to clamp to the borders of the src rect within 1038 // the bitmap, we extract a subset. 1039 // TODO: make sure this is handled in drawBitmap and remove from here. 1040 SkIRect srcIR; 1041 tmpSrc.roundOut(&srcIR); 1042 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 1043 return; 1044 } 1045 bitmapPtr = &tmpBitmap; 1046 1047 // Since we did an extract, we need to adjust the matrix accordingly 1048 SkScalar dx = 0, dy = 0; 1049 if (srcIR.fLeft > 0) { 1050 dx = SkIntToScalar(srcIR.fLeft); 1051 } 1052 if (srcIR.fTop > 0) { 1053 dy = SkIntToScalar(srcIR.fTop); 1054 } 1055 if (dx || dy) { 1056 matrix.preTranslate(dx, dy); 1057 } 1058 } 1059 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 1060 } 1061 1062 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 1063 const SkMatrix& matrix, const SkPaint& srcPaint) { 1064 SkPaint paint = srcPaint; 1065 if (bitmap.isOpaque()) { 1066 replace_srcmode_on_opaque_paint(&paint); 1067 } 1068 1069 if (d.fClip->isEmpty()) { 1070 return; 1071 } 1072 1073 SkMatrix transform = matrix; 1074 transform.postConcat(*d.fMatrix); 1075 this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL, 1076 paint); 1077 } 1078 1079 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap, 1080 int x, int y, const SkPaint& srcPaint) { 1081 SkPaint paint = srcPaint; 1082 if (bitmap.isOpaque()) { 1083 replace_srcmode_on_opaque_paint(&paint); 1084 } 1085 1086 if (d.fClip->isEmpty()) { 1087 return; 1088 } 1089 1090 SkMatrix matrix; 1091 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1092 this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, 1093 paint); 1094 } 1095 1096 // Create a PDF string. Maximum length (in bytes) is 65,535. 1097 // @param input A string value. 1098 // @param len The length of the input array. 1099 // @param wideChars True iff the upper byte in each uint16_t is 1100 // significant and should be encoded and not 1101 // discarded. If true, the upper byte is encoded 1102 // first. Otherwise, we assert the upper byte is 1103 // zero. 1104 static SkString format_wide_string(const uint16_t* input, 1105 size_t len, 1106 bool wideChars) { 1107 if (wideChars) { 1108 SkASSERT(2 * len < 65535); 1109 static const char gHex[] = "0123456789ABCDEF"; 1110 SkString result(4 * len + 2); 1111 result[0] = '<'; 1112 for (size_t i = 0; i < len; i++) { 1113 result[4 * i + 1] = gHex[(input[i] >> 12) & 0xF]; 1114 result[4 * i + 2] = gHex[(input[i] >> 8) & 0xF]; 1115 result[4 * i + 3] = gHex[(input[i] >> 4) & 0xF]; 1116 result[4 * i + 4] = gHex[(input[i] ) & 0xF]; 1117 } 1118 result[4 * len + 1] = '>'; 1119 return result; 1120 } else { 1121 SkASSERT(len <= 65535); 1122 SkString tmp(len); 1123 for (size_t i = 0; i < len; i++) { 1124 SkASSERT(0 == input[i] >> 8); 1125 tmp[i] = static_cast<uint8_t>(input[i]); 1126 } 1127 return SkPDFUtils::FormatString(tmp.c_str(), tmp.size()); 1128 } 1129 } 1130 1131 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1132 SkScalar x, SkScalar y, const SkPaint& srcPaint) { 1133 SkPaint paint = srcPaint; 1134 replace_srcmode_on_opaque_paint(&paint); 1135 1136 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1137 if (paint.getMaskFilter() != NULL) { 1138 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1139 // making text unreadable (e.g. same text twice when using CSS shadows). 1140 return; 1141 } 1142 SkPaint textPaint = calculate_text_paint(paint); 1143 ScopedContentEntry content(this, d, textPaint, true); 1144 if (!content.entry()) { 1145 return; 1146 } 1147 1148 SkGlyphStorage storage(0); 1149 const uint16_t* glyphIDs = NULL; 1150 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1151 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1152 1153 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1154 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); 1155 content.entry()->fContent.writeText("BT\n"); 1156 set_text_transform(x, y, textPaint.getTextSkewX(), 1157 &content.entry()->fContent); 1158 int consumedGlyphCount = 0; 1159 1160 SkTDArray<uint16_t> glyphIDsCopy(glyphIDs, numGlyphs); 1161 1162 while (numGlyphs > consumedGlyphCount) { 1163 updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry()); 1164 SkPDFFont* font = content.entry()->fState.fFont; 1165 1166 int availableGlyphs = font->glyphsToPDFFontEncoding( 1167 glyphIDsCopy.begin() + consumedGlyphCount, 1168 numGlyphs - consumedGlyphCount); 1169 fFontGlyphUsage->noteGlyphUsage( 1170 font, glyphIDsCopy.begin() + consumedGlyphCount, 1171 availableGlyphs); 1172 SkString encodedString = 1173 format_wide_string(glyphIDsCopy.begin() + consumedGlyphCount, 1174 availableGlyphs, font->multiByteGlyphs()); 1175 content.entry()->fContent.writeText(encodedString.c_str()); 1176 consumedGlyphCount += availableGlyphs; 1177 content.entry()->fContent.writeText(" Tj\n"); 1178 } 1179 content.entry()->fContent.writeText("ET\n"); 1180 } 1181 1182 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1183 const SkScalar pos[], int scalarsPerPos, 1184 const SkPoint& offset, const SkPaint& srcPaint) { 1185 SkPaint paint = srcPaint; 1186 replace_srcmode_on_opaque_paint(&paint); 1187 1188 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1189 if (paint.getMaskFilter() != NULL) { 1190 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1191 // making text unreadable (e.g. same text twice when using CSS shadows). 1192 return; 1193 } 1194 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos); 1195 SkPaint textPaint = calculate_text_paint(paint); 1196 ScopedContentEntry content(this, d, textPaint, true); 1197 if (!content.entry()) { 1198 return; 1199 } 1200 1201 SkGlyphStorage storage(0); 1202 const uint16_t* glyphIDs = NULL; 1203 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1204 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1205 1206 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1207 content.entry()->fContent.writeText("BT\n"); 1208 updateFont(textPaint, glyphIDs[0], content.entry()); 1209 for (size_t i = 0; i < numGlyphs; i++) { 1210 SkPDFFont* font = content.entry()->fState.fFont; 1211 uint16_t encodedValue = glyphIDs[i]; 1212 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 1213 // The current pdf font cannot encode the current glyph. 1214 // Try to get a pdf font which can encode the current glyph. 1215 updateFont(textPaint, glyphIDs[i], content.entry()); 1216 font = content.entry()->fState.fFont; 1217 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 1218 SkDEBUGFAIL("PDF could not encode glyph."); 1219 continue; 1220 } 1221 } 1222 1223 fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); 1224 SkScalar x = offset.x() + pos[i * scalarsPerPos]; 1225 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos + 1] : 0); 1226 1227 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); 1228 set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent); 1229 SkString encodedString = 1230 format_wide_string(&encodedValue, 1, font->multiByteGlyphs()); 1231 content.entry()->fContent.writeText(encodedString.c_str()); 1232 content.entry()->fContent.writeText(" Tj\n"); 1233 } 1234 content.entry()->fContent.writeText("ET\n"); 1235 } 1236 1237 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 1238 int vertexCount, const SkPoint verts[], 1239 const SkPoint texs[], const SkColor colors[], 1240 SkXfermode* xmode, const uint16_t indices[], 1241 int indexCount, const SkPaint& paint) { 1242 if (d.fClip->isEmpty()) { 1243 return; 1244 } 1245 // TODO: implement drawVertices 1246 } 1247 1248 void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, 1249 int x, int y, const SkPaint& paint) { 1250 // our onCreateCompatibleDevice() always creates SkPDFDevice subclasses. 1251 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); 1252 if (pdfDevice->isContentEmpty()) { 1253 return; 1254 } 1255 1256 SkMatrix matrix; 1257 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1258 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1259 if (!content.entry()) { 1260 return; 1261 } 1262 if (content.needShape()) { 1263 SkPath shape; 1264 shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), 1265 SkIntToScalar(device->width()), 1266 SkIntToScalar(device->height()))); 1267 content.setShape(shape); 1268 } 1269 if (!content.needSource()) { 1270 return; 1271 } 1272 1273 SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice)); 1274 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), 1275 &content.entry()->fContent); 1276 1277 // Merge glyph sets from the drawn device. 1278 fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage()); 1279 } 1280 1281 SkImageInfo SkPDFDevice::imageInfo() const { 1282 return fLegacyBitmap.info(); 1283 } 1284 1285 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) { 1286 INHERITED::onAttachToCanvas(canvas); 1287 1288 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 1289 fClipStack = canvas->getClipStack(); 1290 } 1291 1292 void SkPDFDevice::onDetachFromCanvas() { 1293 INHERITED::onDetachFromCanvas(); 1294 1295 fClipStack = NULL; 1296 } 1297 1298 SkSurface* SkPDFDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1299 return SkSurface::NewRaster(info, &props); 1300 } 1301 1302 ContentEntry* SkPDFDevice::getLastContentEntry() { 1303 if (fDrawingArea == kContent_DrawingArea) { 1304 return fLastContentEntry; 1305 } else { 1306 return fLastMarginContentEntry; 1307 } 1308 } 1309 1310 SkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() { 1311 if (fDrawingArea == kContent_DrawingArea) { 1312 return &fContentEntries; 1313 } else { 1314 return &fMarginContentEntries; 1315 } 1316 } 1317 1318 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) { 1319 if (fDrawingArea == kContent_DrawingArea) { 1320 fLastContentEntry = contentEntry; 1321 } else { 1322 fLastMarginContentEntry = contentEntry; 1323 } 1324 } 1325 1326 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) { 1327 // A ScopedContentEntry only exists during the course of a draw call, so 1328 // this can't be called while a ScopedContentEntry exists. 1329 fDrawingArea = drawingArea; 1330 } 1331 1332 SkPDFDict* SkPDFDevice::createResourceDict() const { 1333 SkTDArray<SkPDFObject*> fonts; 1334 fonts.setReserve(fFontResources.count()); 1335 for (SkPDFFont* font : fFontResources) { 1336 fonts.push(font); 1337 } 1338 return SkPDFResourceDict::Create( 1339 &fGraphicStateResources, 1340 &fShaderResources, 1341 &fXObjectResources, 1342 &fonts); 1343 } 1344 1345 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const { 1346 return fFontResources; 1347 } 1348 1349 SkPDFArray* SkPDFDevice::copyMediaBox() const { 1350 // should this be a singleton? 1351 1352 SkAutoTUnref<SkPDFArray> mediaBox(SkNEW(SkPDFArray)); 1353 mediaBox->reserve(4); 1354 mediaBox->appendInt(0); 1355 mediaBox->appendInt(0); 1356 mediaBox->appendInt(fPageSize.fWidth); 1357 mediaBox->appendInt(fPageSize.fHeight); 1358 return mediaBox.detach(); 1359 } 1360 1361 SkStreamAsset* SkPDFDevice::content() const { 1362 SkDynamicMemoryWStream buffer; 1363 this->writeContent(&buffer); 1364 return buffer.detachAsStream(); 1365 } 1366 1367 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, 1368 SkWStream* data) const { 1369 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the 1370 // right thing to pass here. 1371 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); 1372 while (entry != NULL) { 1373 SkPoint translation; 1374 translation.iset(this->getOrigin()); 1375 translation.negate(); 1376 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion, 1377 translation); 1378 gsState.updateMatrix(entry->fState.fMatrix); 1379 gsState.updateDrawingState(entry->fState); 1380 1381 entry->fContent.writeToStream(data); 1382 entry = entry->fNext.get(); 1383 } 1384 gsState.drainStack(); 1385 } 1386 1387 void SkPDFDevice::writeContent(SkWStream* out) const { 1388 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1389 SkPDFUtils::AppendTransform(fInitialTransform, out); 1390 } 1391 1392 // TODO(aayushkumar): Apply clip along the margins. Currently, webkit 1393 // colors the contentArea white before it starts drawing into it and 1394 // that currently acts as our clip. 1395 // Also, think about adding a transform here (or assume that the values 1396 // sent across account for that) 1397 SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), out); 1398 1399 // If the content area is the entire page, then we don't need to clip 1400 // the content area (PDF area clips to the page size). Otherwise, 1401 // we have to clip to the content area; we've already applied the 1402 // initial transform, so just clip to the device size. 1403 if (fPageSize != fContentSize) { 1404 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), 1405 SkIntToScalar(this->height())); 1406 emit_clip(NULL, &r, out); 1407 } 1408 1409 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), out); 1410 } 1411 1412 /* Draws an inverse filled path by using Path Ops to compute the positive 1413 * inverse using the current clip as the inverse bounds. 1414 * Return true if this was an inverse path and was properly handled, 1415 * otherwise returns false and the normal drawing routine should continue, 1416 * either as a (incorrect) fallback or because the path was not inverse 1417 * in the first place. 1418 */ 1419 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, 1420 const SkPaint& paint, bool pathIsMutable, 1421 const SkMatrix* prePathMatrix) { 1422 if (!origPath.isInverseFillType()) { 1423 return false; 1424 } 1425 1426 if (d.fClip->isEmpty()) { 1427 return false; 1428 } 1429 1430 SkPath modifiedPath; 1431 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 1432 SkPaint noInversePaint(paint); 1433 1434 // Merge stroking operations into final path. 1435 if (SkPaint::kStroke_Style == paint.getStyle() || 1436 SkPaint::kStrokeAndFill_Style == paint.getStyle()) { 1437 bool doFillPath = paint.getFillPath(origPath, &modifiedPath); 1438 if (doFillPath) { 1439 noInversePaint.setStyle(SkPaint::kFill_Style); 1440 noInversePaint.setStrokeWidth(0); 1441 pathPtr = &modifiedPath; 1442 } else { 1443 // To be consistent with the raster output, hairline strokes 1444 // are rendered as non-inverted. 1445 modifiedPath.toggleInverseFillType(); 1446 drawPath(d, modifiedPath, paint, NULL, true); 1447 return true; 1448 } 1449 } 1450 1451 // Get bounds of clip in current transform space 1452 // (clip bounds are given in device space). 1453 SkRect bounds; 1454 SkMatrix transformInverse; 1455 SkMatrix totalMatrix = *d.fMatrix; 1456 if (prePathMatrix) { 1457 totalMatrix.preConcat(*prePathMatrix); 1458 } 1459 if (!totalMatrix.invert(&transformInverse)) { 1460 return false; 1461 } 1462 bounds.set(d.fClip->getBounds()); 1463 transformInverse.mapRect(&bounds); 1464 1465 // Extend the bounds by the line width (plus some padding) 1466 // so the edge doesn't cause a visible stroke. 1467 bounds.outset(paint.getStrokeWidth() + SK_Scalar1, 1468 paint.getStrokeWidth() + SK_Scalar1); 1469 1470 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { 1471 return false; 1472 } 1473 1474 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); 1475 return true; 1476 } 1477 1478 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 1479 const SkPaint& p) { 1480 SkAnnotation* annotationInfo = p.getAnnotation(); 1481 if (!annotationInfo) { 1482 return false; 1483 } 1484 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); 1485 if (urlData) { 1486 handleLinkToURL(urlData, r, matrix); 1487 return p.getAnnotation() != NULL; 1488 } 1489 SkData* linkToName = annotationInfo->find( 1490 SkAnnotationKeys::Link_Named_Dest_Key()); 1491 if (linkToName) { 1492 handleLinkToNamedDest(linkToName, r, matrix); 1493 return p.getAnnotation() != NULL; 1494 } 1495 return false; 1496 } 1497 1498 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, 1499 const SkMatrix& matrix, 1500 const SkPaint& paint) { 1501 SkAnnotation* annotationInfo = paint.getAnnotation(); 1502 if (!annotationInfo) { 1503 return false; 1504 } 1505 SkData* nameData = annotationInfo->find( 1506 SkAnnotationKeys::Define_Named_Dest_Key()); 1507 if (nameData) { 1508 for (size_t i = 0; i < count; i++) { 1509 defineNamedDestination(nameData, points[i], matrix); 1510 } 1511 return paint.getAnnotation() != NULL; 1512 } 1513 return false; 1514 } 1515 1516 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { 1517 if (NULL == fAnnotations) { 1518 fAnnotations = SkNEW(SkPDFArray); 1519 } 1520 fAnnotations->appendObject(annotation); 1521 } 1522 1523 static SkPDFDict* create_link_annotation(const SkRect& r, 1524 const SkMatrix& initialTransform, 1525 const SkMatrix& matrix) { 1526 SkMatrix transform = matrix; 1527 transform.postConcat(initialTransform); 1528 SkRect translatedRect; 1529 transform.mapRect(&translatedRect, r); 1530 1531 SkAutoTUnref<SkPDFDict> annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); 1532 annotation->insertName("Subtype", "Link"); 1533 1534 SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); 1535 border->reserve(3); 1536 border->appendInt(0); // Horizontal corner radius. 1537 border->appendInt(0); // Vertical corner radius. 1538 border->appendInt(0); // Width, 0 = no border. 1539 annotation->insertObject("Border", border.detach()); 1540 1541 SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); 1542 rect->reserve(4); 1543 rect->appendScalar(translatedRect.fLeft); 1544 rect->appendScalar(translatedRect.fTop); 1545 rect->appendScalar(translatedRect.fRight); 1546 rect->appendScalar(translatedRect.fBottom); 1547 annotation->insertObject("Rect", rect.detach()); 1548 1549 return annotation.detach(); 1550 } 1551 1552 void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r, 1553 const SkMatrix& matrix) { 1554 SkAutoTUnref<SkPDFDict> annotation( 1555 create_link_annotation(r, fInitialTransform, matrix)); 1556 1557 SkString url(static_cast<const char *>(urlData->data()), 1558 urlData->size() - 1); 1559 SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); 1560 action->insertName("S", "URI"); 1561 action->insertString("URI", url); 1562 annotation->insertObject("A", action.detach()); 1563 this->addAnnotation(annotation.detach()); 1564 } 1565 1566 void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r, 1567 const SkMatrix& matrix) { 1568 SkAutoTUnref<SkPDFDict> annotation( 1569 create_link_annotation(r, fInitialTransform, matrix)); 1570 SkString name(static_cast<const char *>(nameData->data()), 1571 nameData->size() - 1); 1572 annotation->insertName("Dest", name); 1573 this->addAnnotation(annotation.detach()); 1574 } 1575 1576 struct NamedDestination { 1577 const SkData* nameData; 1578 SkPoint point; 1579 1580 NamedDestination(const SkData* nameData, const SkPoint& point) 1581 : nameData(SkRef(nameData)), point(point) {} 1582 1583 ~NamedDestination() { 1584 nameData->unref(); 1585 } 1586 }; 1587 1588 void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point, 1589 const SkMatrix& matrix) { 1590 SkMatrix transform = matrix; 1591 transform.postConcat(fInitialTransform); 1592 SkPoint translatedPoint; 1593 transform.mapXY(point.x(), point.y(), &translatedPoint); 1594 fNamedDestinations.push( 1595 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); 1596 } 1597 1598 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { 1599 int nDest = fNamedDestinations.count(); 1600 for (int i = 0; i < nDest; i++) { 1601 NamedDestination* dest = fNamedDestinations[i]; 1602 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); 1603 pdfDest->reserve(5); 1604 pdfDest->appendObjRef(SkRef(page)); 1605 pdfDest->appendName("XYZ"); 1606 pdfDest->appendScalar(dest->point.x()); 1607 pdfDest->appendScalar(dest->point.y()); 1608 pdfDest->appendInt(0); // Leave zoom unchanged 1609 SkString name(static_cast<const char*>(dest->nameData->data())); 1610 dict->insertObject(name, pdfDest.detach()); 1611 } 1612 } 1613 1614 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { 1615 SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this)); 1616 // We always draw the form xobjects that we create back into the device, so 1617 // we simply preserve the font usage instead of pulling it out and merging 1618 // it back in later. 1619 cleanUp(false); // Reset this device to have no content. 1620 init(); 1621 return xobject; 1622 } 1623 1624 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, 1625 SkPDFFormXObject* mask, 1626 const SkClipStack* clipStack, 1627 const SkRegion& clipRegion, 1628 SkXfermode::Mode mode, 1629 bool invertClip) { 1630 if (clipRegion.isEmpty() && !invertClip) { 1631 return; 1632 } 1633 1634 SkAutoTUnref<SkPDFObject> sMaskGS(SkPDFGraphicState::GetSMaskGraphicState( 1635 mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode)); 1636 1637 SkMatrix identity; 1638 identity.reset(); 1639 SkPaint paint; 1640 paint.setXfermodeMode(mode); 1641 ScopedContentEntry content(this, clipStack, clipRegion, identity, paint); 1642 if (!content.entry()) { 1643 return; 1644 } 1645 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1646 &content.entry()->fContent); 1647 SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent); 1648 1649 sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState()); 1650 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1651 &content.entry()->fContent); 1652 } 1653 1654 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1655 const SkRegion& clipRegion, 1656 const SkMatrix& matrix, 1657 const SkPaint& paint, 1658 bool hasText, 1659 SkPDFFormXObject** dst) { 1660 *dst = NULL; 1661 if (clipRegion.isEmpty()) { 1662 return NULL; 1663 } 1664 1665 // The clip stack can come from an SkDraw where it is technically optional. 1666 SkClipStack synthesizedClipStack; 1667 if (clipStack == NULL) { 1668 if (clipRegion == fExistingClipRegion) { 1669 clipStack = &fExistingClipStack; 1670 } else { 1671 // GraphicStackState::updateClip expects the clip stack to have 1672 // fExistingClip as a prefix, so start there, then set the clip 1673 // to the passed region. 1674 synthesizedClipStack = fExistingClipStack; 1675 SkPath clipPath; 1676 clipRegion.getBoundaryPath(&clipPath); 1677 synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op, 1678 false); 1679 clipStack = &synthesizedClipStack; 1680 } 1681 } 1682 1683 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 1684 if (paint.getXfermode()) { 1685 paint.getXfermode()->asMode(&xfermode); 1686 } 1687 1688 // For the following modes, we want to handle source and destination 1689 // separately, so make an object of what's already there. 1690 if (xfermode == SkXfermode::kClear_Mode || 1691 xfermode == SkXfermode::kSrc_Mode || 1692 xfermode == SkXfermode::kSrcIn_Mode || 1693 xfermode == SkXfermode::kDstIn_Mode || 1694 xfermode == SkXfermode::kSrcOut_Mode || 1695 xfermode == SkXfermode::kDstOut_Mode || 1696 xfermode == SkXfermode::kSrcATop_Mode || 1697 xfermode == SkXfermode::kDstATop_Mode || 1698 xfermode == SkXfermode::kModulate_Mode) { 1699 if (!isContentEmpty()) { 1700 *dst = createFormXObjectFromDevice(); 1701 SkASSERT(isContentEmpty()); 1702 } else if (xfermode != SkXfermode::kSrc_Mode && 1703 xfermode != SkXfermode::kSrcOut_Mode) { 1704 // Except for Src and SrcOut, if there isn't anything already there, 1705 // then we're done. 1706 return NULL; 1707 } 1708 } 1709 // TODO(vandebo): Figure out how/if we can handle the following modes: 1710 // Xor, Plus. 1711 1712 // Dst xfer mode doesn't draw source at all. 1713 if (xfermode == SkXfermode::kDst_Mode) { 1714 return NULL; 1715 } 1716 1717 ContentEntry* entry; 1718 SkAutoTDelete<ContentEntry> newEntry; 1719 1720 ContentEntry* lastContentEntry = getLastContentEntry(); 1721 if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) { 1722 entry = lastContentEntry; 1723 } else { 1724 newEntry.reset(new ContentEntry); 1725 entry = newEntry.get(); 1726 } 1727 1728 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1729 hasText, &entry->fState); 1730 if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode && 1731 entry->fState.compareInitialState(lastContentEntry->fState)) { 1732 return lastContentEntry; 1733 } 1734 1735 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1736 if (!lastContentEntry) { 1737 contentEntries->reset(entry); 1738 setLastContentEntry(entry); 1739 } else if (xfermode == SkXfermode::kDstOver_Mode) { 1740 entry->fNext.reset(contentEntries->detach()); 1741 contentEntries->reset(entry); 1742 } else { 1743 lastContentEntry->fNext.reset(entry); 1744 setLastContentEntry(entry); 1745 } 1746 newEntry.detach(); 1747 return entry; 1748 } 1749 1750 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, 1751 SkPDFFormXObject* dst, 1752 SkPath* shape) { 1753 if (xfermode != SkXfermode::kClear_Mode && 1754 xfermode != SkXfermode::kSrc_Mode && 1755 xfermode != SkXfermode::kDstOver_Mode && 1756 xfermode != SkXfermode::kSrcIn_Mode && 1757 xfermode != SkXfermode::kDstIn_Mode && 1758 xfermode != SkXfermode::kSrcOut_Mode && 1759 xfermode != SkXfermode::kDstOut_Mode && 1760 xfermode != SkXfermode::kSrcATop_Mode && 1761 xfermode != SkXfermode::kDstATop_Mode && 1762 xfermode != SkXfermode::kModulate_Mode) { 1763 SkASSERT(!dst); 1764 return; 1765 } 1766 if (xfermode == SkXfermode::kDstOver_Mode) { 1767 SkASSERT(!dst); 1768 ContentEntry* firstContentEntry = getContentEntries()->get(); 1769 if (firstContentEntry->fContent.getOffset() == 0) { 1770 // For DstOver, an empty content entry was inserted before the rest 1771 // of the content entries. If nothing was drawn, it needs to be 1772 // removed. 1773 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1774 contentEntries->reset(firstContentEntry->fNext.detach()); 1775 } 1776 return; 1777 } 1778 if (!dst) { 1779 SkASSERT(xfermode == SkXfermode::kSrc_Mode || 1780 xfermode == SkXfermode::kSrcOut_Mode); 1781 return; 1782 } 1783 1784 ContentEntry* contentEntries = getContentEntries()->get(); 1785 SkASSERT(dst); 1786 SkASSERT(!contentEntries->fNext.get()); 1787 // Changing the current content into a form-xobject will destroy the clip 1788 // objects which is fine since the xobject will already be clipped. However 1789 // if source has shape, we need to clip it too, so a copy of the clip is 1790 // saved. 1791 SkClipStack clipStack = contentEntries->fState.fClipStack; 1792 SkRegion clipRegion = contentEntries->fState.fClipRegion; 1793 1794 SkMatrix identity; 1795 identity.reset(); 1796 SkPaint stockPaint; 1797 1798 SkAutoTUnref<SkPDFFormXObject> srcFormXObject; 1799 if (isContentEmpty()) { 1800 // If nothing was drawn and there's no shape, then the draw was a 1801 // no-op, but dst needs to be restored for that to be true. 1802 // If there is shape, then an empty source with Src, SrcIn, SrcOut, 1803 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop 1804 // reduces to Dst. 1805 if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode || 1806 xfermode == SkXfermode::kSrcATop_Mode) { 1807 ScopedContentEntry content(this, &fExistingClipStack, 1808 fExistingClipRegion, identity, 1809 stockPaint); 1810 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1811 &content.entry()->fContent); 1812 return; 1813 } else { 1814 xfermode = SkXfermode::kClear_Mode; 1815 } 1816 } else { 1817 SkASSERT(!fContentEntries->fNext.get()); 1818 srcFormXObject.reset(createFormXObjectFromDevice()); 1819 } 1820 1821 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it 1822 // without alpha. 1823 if (xfermode == SkXfermode::kSrcATop_Mode) { 1824 // TODO(vandebo): In order to properly support SrcATop we have to track 1825 // the shape of what's been drawn at all times. It's the intersection of 1826 // the non-transparent parts of the device and the outlines (shape) of 1827 // all images and devices drawn. 1828 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1829 &fExistingClipStack, fExistingClipRegion, 1830 SkXfermode::kSrcOver_Mode, true); 1831 } else { 1832 SkAutoTUnref<SkPDFFormXObject> dstMaskStorage; 1833 SkPDFFormXObject* dstMask = srcFormXObject.get(); 1834 if (shape != NULL) { 1835 // Draw shape into a form-xobject. 1836 SkDraw d; 1837 d.fMatrix = &identity; 1838 d.fClip = &clipRegion; 1839 d.fClipStack = &clipStack; 1840 SkPaint filledPaint; 1841 filledPaint.setColor(SK_ColorBLACK); 1842 filledPaint.setStyle(SkPaint::kFill_Style); 1843 this->drawPath(d, *shape, filledPaint, NULL, true); 1844 1845 dstMaskStorage.reset(createFormXObjectFromDevice()); 1846 dstMask = dstMaskStorage.get(); 1847 } 1848 drawFormXObjectWithMask(addXObjectResource(dst), dstMask, 1849 &fExistingClipStack, fExistingClipRegion, 1850 SkXfermode::kSrcOver_Mode, true); 1851 } 1852 1853 if (xfermode == SkXfermode::kClear_Mode) { 1854 return; 1855 } else if (xfermode == SkXfermode::kSrc_Mode || 1856 xfermode == SkXfermode::kDstATop_Mode) { 1857 ScopedContentEntry content(this, &fExistingClipStack, 1858 fExistingClipRegion, identity, stockPaint); 1859 if (content.entry()) { 1860 SkPDFUtils::DrawFormXObject( 1861 this->addXObjectResource(srcFormXObject.get()), 1862 &content.entry()->fContent); 1863 } 1864 if (xfermode == SkXfermode::kSrc_Mode) { 1865 return; 1866 } 1867 } else if (xfermode == SkXfermode::kSrcATop_Mode) { 1868 ScopedContentEntry content(this, &fExistingClipStack, 1869 fExistingClipRegion, identity, stockPaint); 1870 if (content.entry()) { 1871 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1872 &content.entry()->fContent); 1873 } 1874 } 1875 1876 SkASSERT(xfermode == SkXfermode::kSrcIn_Mode || 1877 xfermode == SkXfermode::kDstIn_Mode || 1878 xfermode == SkXfermode::kSrcOut_Mode || 1879 xfermode == SkXfermode::kDstOut_Mode || 1880 xfermode == SkXfermode::kSrcATop_Mode || 1881 xfermode == SkXfermode::kDstATop_Mode || 1882 xfermode == SkXfermode::kModulate_Mode); 1883 1884 if (xfermode == SkXfermode::kSrcIn_Mode || 1885 xfermode == SkXfermode::kSrcOut_Mode || 1886 xfermode == SkXfermode::kSrcATop_Mode) { 1887 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1888 &fExistingClipStack, fExistingClipRegion, 1889 SkXfermode::kSrcOver_Mode, 1890 xfermode == SkXfermode::kSrcOut_Mode); 1891 } else { 1892 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; 1893 if (xfermode == SkXfermode::kModulate_Mode) { 1894 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), 1895 dst, &fExistingClipStack, 1896 fExistingClipRegion, 1897 SkXfermode::kSrcOver_Mode, false); 1898 mode = SkXfermode::kMultiply_Mode; 1899 } 1900 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), 1901 &fExistingClipStack, fExistingClipRegion, mode, 1902 xfermode == SkXfermode::kDstOut_Mode); 1903 } 1904 } 1905 1906 bool SkPDFDevice::isContentEmpty() { 1907 ContentEntry* contentEntries = getContentEntries()->get(); 1908 if (!contentEntries || contentEntries->fContent.getOffset() == 0) { 1909 SkASSERT(!contentEntries || !contentEntries->fNext.get()); 1910 return true; 1911 } 1912 return false; 1913 } 1914 1915 void SkPDFDevice::populateGraphicStateEntryFromPaint( 1916 const SkMatrix& matrix, 1917 const SkClipStack& clipStack, 1918 const SkRegion& clipRegion, 1919 const SkPaint& paint, 1920 bool hasText, 1921 GraphicStateEntry* entry) { 1922 NOT_IMPLEMENTED(paint.getPathEffect() != NULL, false); 1923 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1924 NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); 1925 1926 entry->fMatrix = matrix; 1927 entry->fClipStack = clipStack; 1928 entry->fClipRegion = clipRegion; 1929 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 1930 entry->fShaderIndex = -1; 1931 1932 // PDF treats a shader as a color, so we only set one or the other. 1933 SkAutoTUnref<SkPDFObject> pdfShader; 1934 const SkShader* shader = paint.getShader(); 1935 SkColor color = paint.getColor(); 1936 if (shader) { 1937 // PDF positions patterns relative to the initial transform, so 1938 // we need to apply the current transform to the shader parameters. 1939 SkMatrix transform = matrix; 1940 transform.postConcat(fInitialTransform); 1941 1942 // PDF doesn't support kClamp_TileMode, so we simulate it by making 1943 // a pattern the size of the current clip. 1944 SkIRect bounds = clipRegion.getBounds(); 1945 1946 // We need to apply the initial transform to bounds in order to get 1947 // bounds in a consistent coordinate system. 1948 SkRect boundsTemp; 1949 boundsTemp.set(bounds); 1950 fInitialTransform.mapRect(&boundsTemp); 1951 boundsTemp.roundOut(&bounds); 1952 1953 SkScalar rasterScale = 1954 SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE; 1955 pdfShader.reset(SkPDFShader::GetPDFShader( 1956 fCanon, fRasterDpi, *shader, transform, bounds, rasterScale)); 1957 1958 if (pdfShader.get()) { 1959 // pdfShader has been canonicalized so we can directly compare 1960 // pointers. 1961 int resourceIndex = fShaderResources.find(pdfShader.get()); 1962 if (resourceIndex < 0) { 1963 resourceIndex = fShaderResources.count(); 1964 fShaderResources.push(pdfShader.get()); 1965 pdfShader.get()->ref(); 1966 } 1967 entry->fShaderIndex = resourceIndex; 1968 } else { 1969 // A color shader is treated as an invalid shader so we don't have 1970 // to set a shader just for a color. 1971 SkShader::GradientInfo gradientInfo; 1972 SkColor gradientColor; 1973 gradientInfo.fColors = &gradientColor; 1974 gradientInfo.fColorOffsets = NULL; 1975 gradientInfo.fColorCount = 1; 1976 if (shader->asAGradient(&gradientInfo) == 1977 SkShader::kColor_GradientType) { 1978 entry->fColor = SkColorSetA(gradientColor, 0xFF); 1979 color = gradientColor; 1980 } 1981 } 1982 } 1983 1984 SkAutoTUnref<SkPDFGraphicState> newGraphicState; 1985 if (color == paint.getColor()) { 1986 newGraphicState.reset( 1987 SkPDFGraphicState::GetGraphicStateForPaint(fCanon, paint)); 1988 } else { 1989 SkPaint newPaint = paint; 1990 newPaint.setColor(color); 1991 newGraphicState.reset( 1992 SkPDFGraphicState::GetGraphicStateForPaint(fCanon, newPaint)); 1993 } 1994 int resourceIndex = addGraphicStateResource(newGraphicState.get()); 1995 entry->fGraphicStateIndex = resourceIndex; 1996 1997 if (hasText) { 1998 entry->fTextScaleX = paint.getTextScaleX(); 1999 entry->fTextFill = paint.getStyle(); 2000 } else { 2001 entry->fTextScaleX = 0; 2002 } 2003 } 2004 2005 int SkPDFDevice::addGraphicStateResource(SkPDFObject* gs) { 2006 // Assumes that gs has been canonicalized (so we can directly compare 2007 // pointers). 2008 int result = fGraphicStateResources.find(gs); 2009 if (result < 0) { 2010 result = fGraphicStateResources.count(); 2011 fGraphicStateResources.push(gs); 2012 gs->ref(); 2013 } 2014 return result; 2015 } 2016 2017 int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) { 2018 // Assumes that xobject has been canonicalized (so we can directly compare 2019 // pointers). 2020 int result = fXObjectResources.find(xObject); 2021 if (result < 0) { 2022 result = fXObjectResources.count(); 2023 fXObjectResources.push(xObject); 2024 xObject->ref(); 2025 } 2026 return result; 2027 } 2028 2029 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 2030 ContentEntry* contentEntry) { 2031 SkTypeface* typeface = paint.getTypeface(); 2032 if (contentEntry->fState.fFont == NULL || 2033 contentEntry->fState.fTextSize != paint.getTextSize() || 2034 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 2035 int fontIndex = getFontResourceIndex(typeface, glyphID); 2036 contentEntry->fContent.writeText("/"); 2037 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 2038 SkPDFResourceDict::kFont_ResourceType, 2039 fontIndex).c_str()); 2040 contentEntry->fContent.writeText(" "); 2041 SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent); 2042 contentEntry->fContent.writeText(" Tf\n"); 2043 contentEntry->fState.fFont = fFontResources[fontIndex]; 2044 } 2045 } 2046 2047 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 2048 SkAutoTUnref<SkPDFFont> newFont( 2049 SkPDFFont::GetFontResource(fCanon, typeface, glyphID)); 2050 int resourceIndex = fFontResources.find(newFont.get()); 2051 if (resourceIndex < 0) { 2052 resourceIndex = fFontResources.count(); 2053 fFontResources.push(newFont.get()); 2054 newFont.get()->ref(); 2055 } 2056 return resourceIndex; 2057 } 2058 2059 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, 2060 const SkClipStack* clipStack, 2061 const SkRegion& origClipRegion, 2062 const SkBitmap& origBitmap, 2063 const SkIRect* srcRect, 2064 const SkPaint& paint) { 2065 SkMatrix matrix = origMatrix; 2066 SkRegion perspectiveBounds; 2067 const SkRegion* clipRegion = &origClipRegion; 2068 SkBitmap perspectiveBitmap; 2069 const SkBitmap* bitmap = &origBitmap; 2070 SkBitmap tmpSubsetBitmap; 2071 2072 // Rasterize the bitmap using perspective in a new bitmap. 2073 if (origMatrix.hasPerspective()) { 2074 if (fRasterDpi == 0) { 2075 return; 2076 } 2077 SkBitmap* subsetBitmap; 2078 if (srcRect) { 2079 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { 2080 return; 2081 } 2082 subsetBitmap = &tmpSubsetBitmap; 2083 } else { 2084 subsetBitmap = &tmpSubsetBitmap; 2085 *subsetBitmap = origBitmap; 2086 } 2087 srcRect = NULL; 2088 2089 // Transform the bitmap in the new space, without taking into 2090 // account the initial transform. 2091 SkPath perspectiveOutline; 2092 perspectiveOutline.addRect( 2093 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2094 SkIntToScalar(subsetBitmap->height()))); 2095 perspectiveOutline.transform(origMatrix); 2096 2097 // TODO(edisonn): perf - use current clip too. 2098 // Retrieve the bounds of the new shape. 2099 SkRect bounds = perspectiveOutline.getBounds(); 2100 2101 // Transform the bitmap in the new space, taking into 2102 // account the initial transform. 2103 SkMatrix total = origMatrix; 2104 total.postConcat(fInitialTransform); 2105 total.postScale(SkIntToScalar(fRasterDpi) / 2106 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), 2107 SkIntToScalar(fRasterDpi) / 2108 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); 2109 SkPath physicalPerspectiveOutline; 2110 physicalPerspectiveOutline.addRect( 2111 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2112 SkIntToScalar(subsetBitmap->height()))); 2113 physicalPerspectiveOutline.transform(total); 2114 2115 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / 2116 bounds.width(); 2117 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / 2118 bounds.height(); 2119 2120 // TODO(edisonn): A better approach would be to use a bitmap shader 2121 // (in clamp mode) and draw a rect over the entire bounding box. Then 2122 // intersect perspectiveOutline to the clip. That will avoid introducing 2123 // alpha to the image while still giving good behavior at the edge of 2124 // the image. Avoiding alpha will reduce the pdf size and generation 2125 // CPU time some. 2126 2127 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().width()); 2128 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().height()); 2129 if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) { 2130 return; 2131 } 2132 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); 2133 2134 SkCanvas canvas(perspectiveBitmap); 2135 2136 SkScalar deltaX = bounds.left(); 2137 SkScalar deltaY = bounds.top(); 2138 2139 SkMatrix offsetMatrix = origMatrix; 2140 offsetMatrix.postTranslate(-deltaX, -deltaY); 2141 offsetMatrix.postScale(scaleX, scaleY); 2142 2143 // Translate the draw in the new canvas, so we perfectly fit the 2144 // shape in the bitmap. 2145 canvas.setMatrix(offsetMatrix); 2146 2147 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); 2148 2149 // Make sure the final bits are in the bitmap. 2150 canvas.flush(); 2151 2152 // In the new space, we use the identity matrix translated 2153 // and scaled to reflect DPI. 2154 matrix.setScale(1 / scaleX, 1 / scaleY); 2155 matrix.postTranslate(deltaX, deltaY); 2156 2157 perspectiveBounds.setRect( 2158 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), 2159 SkScalarFloorToInt(bounds.y()), 2160 SkScalarCeilToInt(bounds.width()), 2161 SkScalarCeilToInt(bounds.height()))); 2162 clipRegion = &perspectiveBounds; 2163 srcRect = NULL; 2164 bitmap = &perspectiveBitmap; 2165 } 2166 2167 SkMatrix scaled; 2168 // Adjust for origin flip. 2169 scaled.setScale(SK_Scalar1, -SK_Scalar1); 2170 scaled.postTranslate(0, SK_Scalar1); 2171 // Scale the image up from 1x1 to WxH. 2172 SkIRect subset = bitmap->bounds(); 2173 scaled.postScale(SkIntToScalar(subset.width()), 2174 SkIntToScalar(subset.height())); 2175 scaled.postConcat(matrix); 2176 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); 2177 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { 2178 return; 2179 } 2180 if (content.needShape()) { 2181 SkPath shape; 2182 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), 2183 SkIntToScalar(subset.height()))); 2184 shape.transform(matrix); 2185 content.setShape(shape); 2186 } 2187 if (!content.needSource()) { 2188 return; 2189 } 2190 2191 SkBitmap subsetBitmap; 2192 // Should extractSubset be done by the SkPDFDevice? 2193 if (!bitmap->extractSubset(&subsetBitmap, subset)) { 2194 return; 2195 } 2196 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); 2197 if (!image) { 2198 return; 2199 } 2200 2201 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), 2202 &content.entry()->fContent); 2203 } 2204