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

Side by Side Diff: core/fxge/skia/fx_skia_device.cpp

Issue 2064753002: add local caching for skia draws (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@master
Patch Set: fix text case Created 4 years, 5 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
OLDNEW
1 // Copyright 2014 PDFium Authors. All rights reserved. 1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/fxge/include/fx_ge.h"
6
7 #if defined(_SKIA_SUPPORT_) 5 #if defined(_SKIA_SUPPORT_)
8 #include <algorithm> 6 #include <algorithm>
9 #include <vector> 7 #include <vector>
10 8
11 #include "core/fxcodec/include/fx_codec.h" 9 #include "core/fxcodec/include/fx_codec.h"
12 10
13 #include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h" 11 #include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h"
14 #include "core/fpdfapi/fpdf_page/pageint.h" 12 #include "core/fpdfapi/fpdf_page/pageint.h"
15 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" 13 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h"
16 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" 14 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h"
17 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h" 15 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h"
18 #include "core/fxge/skia/fx_skia_device.h" 16 #include "core/fxge/skia/fx_skia_device.h"
19 17
20 #include "third_party/skia/include/core/SkCanvas.h" 18 #include "third_party/skia/include/core/SkCanvas.h"
21 #include "third_party/skia/include/core/SkColorFilter.h" 19 #include "third_party/skia/include/core/SkColorFilter.h"
22 #include "third_party/skia/include/core/SkColorPriv.h" 20 #include "third_party/skia/include/core/SkColorPriv.h"
23 #include "third_party/skia/include/core/SkPaint.h" 21 #include "third_party/skia/include/core/SkPaint.h"
24 #include "third_party/skia/include/core/SkPath.h" 22 #include "third_party/skia/include/core/SkPath.h"
25 #include "third_party/skia/include/core/SkPictureRecorder.h" 23 #include "third_party/skia/include/core/SkPictureRecorder.h"
26 #include "third_party/skia/include/core/SkStream.h" 24 #include "third_party/skia/include/core/SkStream.h"
27 #include "third_party/skia/include/core/SkTypeface.h" 25 #include "third_party/skia/include/core/SkTypeface.h"
28 #include "third_party/skia/include/effects/SkDashPathEffect.h" 26 #include "third_party/skia/include/effects/SkDashPathEffect.h"
29 #include "third_party/skia/include/effects/SkGradientShader.h" 27 #include "third_party/skia/include/effects/SkGradientShader.h"
30 #include "third_party/skia/include/pathops/SkPathOps.h" 28 #include "third_party/skia/include/pathops/SkPathOps.h"
31 29
30 #ifdef SK_DEBUG
31 #include "third_party/skia/include/core/SkClipStack.h"
32 #endif
33
32 namespace { 34 namespace {
33 35
34 #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents 36 #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents
35 #define DRAW_SKIA_CLIP 0 // set to 1 to draw a green rectangle around the clip 37 #define DRAW_SKIA_CLIP 0 // set to 1 to draw a green rectangle around the clip
36 38
37 void DebugShowSkiaPath(const SkPath& path) { 39 void DebugShowSkiaPath(const SkPath& path) {
38 #if SHOW_SKIA_PATH 40 #if SHOW_SKIA_PATH
39 char buffer[4096]; 41 char buffer[4096];
40 sk_bzero(buffer, sizeof(buffer)); 42 sk_bzero(buffer, sizeof(buffer));
41 SkMemoryWStream stream(buffer, sizeof(buffer)); 43 SkMemoryWStream stream(buffer, sizeof(buffer));
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the 471 // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the
470 // gradient that goes through startEdgePt, endEdgePt. 472 // gradient that goes through startEdgePt, endEdgePt.
471 clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt)); 473 clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt));
472 clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt)); 474 clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt));
473 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt)); 475 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt));
474 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt)); 476 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt));
475 } 477 }
476 478
477 } // namespace 479 } // namespace
478 480
481 // Encapsulate the state used for successive text and path draws so that
482 // they can be combined
dsinclair 2016/06/29 13:22:28 nit: . at end of sentence.
caryclark 2016/06/29 13:55:10 Done.
483 class SkiaState {
484 public:
485 enum class Clip {
486 kSave,
487 kPath,
488 };
489
490 // mark all cached state as uninitialized
491 SkiaState() {
dsinclair 2016/06/29 13:22:28 Initializer list? SkiaState() : m_pFont(nullptr),
caryclark 2016/06/29 13:55:10 Done.
492 m_pFont = nullptr;
493 m_pCache = nullptr;
494 m_fontSize = 0;
495 m_fillColor = 0;
496 m_strokeColor = 0;
497 m_blendType = 0;
498 m_commandIndex = 0;
499 m_drawText = false;
500 m_drawPath = false;
501 m_fillPath = false;
502 m_debugDisable = false;
503 }
504
505 bool DrawPath(const CFX_PathData* pPathData,
506 const CFX_Matrix* pMatrix,
507 const CFX_GraphStateData* pDrawState,
508 uint32_t fill_color,
509 uint32_t stroke_color,
510 int fill_mode,
511 int blend_type,
512 CFX_SkiaDeviceDriver* pDriver) {
513 if (m_debugDisable)
514 return false;
515 if (m_commandIndex < m_commands.count())
516 FlushCommands(pDriver);
517 if (m_drawText)
518 FlushText(pDriver);
519 if (m_drawPath && DrawChanged(pMatrix, pDrawState, fill_color, stroke_color,
520 fill_mode, blend_type)) {
521 FlushPath(pDriver);
522 }
523 if (!m_drawPath) {
524 m_skPath.reset();
525 m_fillPath = (fill_mode & 3) && fill_color;
526 m_skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
527 ? SkPath::kEvenOdd_FillType
528 : SkPath::kWinding_FillType);
529 m_drawState = *pDrawState;
530 m_fillColor = fill_color;
531 m_strokeColor = stroke_color;
532 m_blendType = blend_type;
533 m_drawMatrix = *pMatrix;
534 }
535 SkPath skPath = BuildPath(pPathData);
536 SkPoint delta;
537 if (MatrixOffset(pMatrix, &delta))
538 skPath.offset(delta.fX, delta.fY);
539 m_skPath.addPath(skPath);
540 m_drawPath = true;
541 return true;
542 }
543
544 void FlushPath(CFX_SkiaDeviceDriver* pDriver) {
545 SkMatrix skMatrix = ToSkMatrix(m_drawMatrix);
546 SkPaint skPaint;
547 skPaint.setAntiAlias(true);
548 int stroke_alpha = FXARGB_A(m_strokeColor);
549 if (stroke_alpha)
550 pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix);
551 SkCanvas* skCanvas = pDriver->SkiaCanvas();
552 skCanvas->save();
553 skCanvas->concat(skMatrix);
554 if (m_fillPath) {
555 SkPath strokePath;
556 const SkPath* fillPath = &m_skPath;
557 if (stroke_alpha) {
558 SkAlpha fillA = SkColorGetA(m_fillColor);
559 SkAlpha strokeA = SkColorGetA(m_strokeColor);
560 if (fillA && fillA < 0xFF && strokeA && strokeA < 0xFF) {
561 skPaint.getFillPath(m_skPath, &strokePath);
562 if (Op(m_skPath, strokePath, SkPathOp::kDifference_SkPathOp,
563 &strokePath)) {
564 fillPath = &strokePath;
565 }
566 }
567 }
568 skPaint.setStyle(SkPaint::kFill_Style);
569 skPaint.setColor(m_fillColor);
570 skCanvas->drawPath(*fillPath, skPaint);
571 }
572 if (stroke_alpha) {
573 DebugShowSkiaPath(m_skPath);
574 DebugShowCanvasMatrix(skCanvas);
575 skPaint.setStyle(SkPaint::kStroke_Style);
576 skPaint.setColor(m_strokeColor);
577 skCanvas->drawPath(m_skPath, skPaint);
578 }
579 skCanvas->restore();
580 m_drawPath = false;
581 }
582
583 bool DrawText(int nChars,
584 const FXTEXT_CHARPOS* pCharPos,
585 CFX_Font* pFont,
586 CFX_FontCache* pCache,
587 const CFX_Matrix* pMatrix,
588 FX_FLOAT font_size,
589 uint32_t color,
590 CFX_SkiaDeviceDriver* pDriver) {
591 if (m_debugDisable)
592 return false;
593 if (m_commandIndex < m_commands.count())
594 FlushCommands(pDriver);
595 if (m_drawPath)
596 FlushPath(pDriver);
597 if (m_drawText && FontChanged(pFont, pCache, pMatrix, font_size, color))
598 FlushText(pDriver);
599 if (!m_drawText) {
600 m_positions.setCount(0);
601 m_glyphs.setCount(0);
602 m_pFont = pFont;
603 m_pCache = pCache;
604 m_fontSize = font_size;
605 m_fillColor = color;
606 m_drawMatrix = *pMatrix;
607 }
608 int count = m_positions.count();
609 m_positions.setCount(nChars + count);
610 m_glyphs.setCount(nChars + count);
611 for (int index = 0; index < nChars; ++index) {
612 const FXTEXT_CHARPOS& cp = pCharPos[index];
613 m_positions[index + count] = {cp.m_OriginX, cp.m_OriginY};
614 m_glyphs[index + count] = (uint16_t)cp.m_GlyphIndex;
615 }
616 SkPoint delta;
617 if (MatrixOffset(pMatrix, &delta)) {
618 for (int index = 0; index < nChars; ++index)
619 m_positions[index + count].offset(delta.fX, -delta.fY);
620 }
621 m_drawText = true;
622 return true;
623 }
624
625 void FlushText(CFX_SkiaDeviceDriver* pDriver) {
626 SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix);
627 SkPaint skPaint;
628 skPaint.setAntiAlias(true);
629 skPaint.setColor(m_fillColor);
630 if (m_pFont->GetFace()) { // exclude placeholder test fonts
631 sk_sp<SkTypeface> typeface(SkSafeRef(m_pCache->GetDeviceCache(m_pFont)));
632 skPaint.setTypeface(typeface);
633 }
634 skPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
635 skPaint.setTextSize(m_fontSize);
636 skPaint.setSubpixelText(true);
637 SkCanvas* skCanvas = pDriver->SkiaCanvas();
638 skCanvas->save();
639 skCanvas->concat(skMatrix);
640 skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2,
641 m_positions.begin(), skPaint);
642 skCanvas->restore();
643 m_drawText = false;
644 }
645
646 bool SetClipFill(const CFX_PathData* pPathData,
647 const CFX_Matrix* pMatrix,
648 int fill_mode,
649 CFX_SkiaDeviceDriver* pDriver) {
650 if (m_debugDisable)
651 return false;
652 SkPath skClipPath = BuildPath(pPathData);
653 skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
654 ? SkPath::kEvenOdd_FillType
655 : SkPath::kWinding_FillType);
656 SkMatrix skMatrix = ToSkMatrix(*pMatrix);
657 skClipPath.transform(skMatrix);
658 return SetClip(skClipPath, pDriver);
659 }
660
661 bool SetClip(const SkPath& skClipPath, CFX_SkiaDeviceDriver* pDriver) {
662 if (m_commandIndex < m_commands.count()) {
663 if (m_commands[m_commandIndex] == Clip::kPath &&
664 m_clips[m_commandIndex] == skClipPath) {
665 ++m_commandIndex;
666 return true;
667 }
668 FlushCommands(pDriver);
669 }
670 Flush(pDriver);
671 m_commands.push(Clip::kPath);
672 ++m_commandIndex;
673 m_clips.push_back(skClipPath);
674 return false;
675 }
676
677 bool SetClipStroke(const CFX_PathData* pPathData,
678 const CFX_Matrix* pMatrix,
679 const CFX_GraphStateData* pGraphState,
680 CFX_SkiaDeviceDriver* pDriver) {
681 if (m_debugDisable)
682 return false;
683 SkPath skPath = BuildPath(pPathData);
684 SkMatrix skMatrix = ToSkMatrix(*pMatrix);
685 SkPaint skPaint;
686 pDriver->PaintStroke(&skPaint, pGraphState, skMatrix);
687 SkPath dst_path;
688 skPaint.getFillPath(skPath, &dst_path);
689 dst_path.transform(skMatrix);
690 return SetClip(dst_path, pDriver);
691 }
692
693 bool MatrixOffset(const CFX_Matrix* pMatrix, SkPoint* delta) {
694 delta->set(pMatrix->e - m_drawMatrix.e, pMatrix->f - m_drawMatrix.f);
695 if (!delta->fX && !delta->fY)
696 return true;
697 SkMatrix drawMatrix = ToSkMatrix(m_drawMatrix);
698 if (!(drawMatrix.getType() & ~SkMatrix::kTranslate_Mask))
699 return true;
700 SkMatrix invDrawMatrix;
701 if (!drawMatrix.invert(&invDrawMatrix))
702 return false;
703 SkMatrix invNewMatrix;
704 SkMatrix newMatrix = ToSkMatrix(*pMatrix);
705 if (!newMatrix.invert(&invNewMatrix))
706 return false;
707 delta->set(invDrawMatrix.getTranslateX() - invNewMatrix.getTranslateX(),
708 invDrawMatrix.getTranslateY() - invNewMatrix.getTranslateY());
709 return true;
710 }
711
712 // start here; more work to do thinking through flushing
dsinclair 2016/06/29 13:22:28 Is this still relevant? If so, can you add a TODO(
caryclark 2016/06/29 13:55:10 Removed (Done).
713
714 void FlushCommands(CFX_SkiaDeviceDriver* pDriver) {
715 if (m_commandIndex == m_commands.count())
716 return;
717 if (m_commandIndex < m_commands.count())
718 pDriver->SkiaCanvas()->restore();
719 int index = m_commands.count() - 1;
720 if (m_commandIndex == index && m_commands[index] == Clip::kSave)
721 return;
722 for (; index > m_commandIndex; --index) {
723 if (m_commands[index] == Clip::kSave)
724 pDriver->SkiaCanvas()->restore();
725 }
726
727 if (m_commandIndex > 0)
728 pDriver->SkiaCanvas()->save();
dsinclair 2016/06/29 13:22:28 There is a save() but no restore below()?
caryclark 2016/06/29 13:55:10 That's correct. The save here is balanced by a sub
729 while (index > 0 && m_commands[index] != Clip::kSave)
730 --index;
731 while (++index < m_commandIndex) {
732 SkASSERT(m_commands[index] == Clip::kPath);
733 pDriver->SkiaCanvas()->clipPath(m_clips[index], SkRegion::kIntersect_Op,
734 true);
735 }
736 m_commands.setCount(m_commandIndex);
737 m_clips.resize_back(m_commandIndex);
738 }
739
740 // returns true if caller should apply command to skia canvas
741 bool ClipSave(CFX_SkiaDeviceDriver* pDriver) {
742 if (m_debugDisable)
743 return false;
744 int count = m_commands.count();
745 if (m_commandIndex < count) {
746 if (m_commands[m_commandIndex] == Clip::kSave) {
747 ++m_commandIndex;
748 return true;
749 }
750 FlushCommands(pDriver);
751 }
752 Flush(pDriver);
753 m_commands.push(Clip::kSave);
754 ++m_commandIndex;
755 m_clips.push_back(m_skEmptyPath);
756 return false;
757 }
758
759 bool ClipRestore(CFX_SkiaDeviceDriver* pDriver) {
760 if (m_debugDisable)
761 return false;
762 while (m_commandIndex > 0) {
763 if (m_commands[--m_commandIndex] == Clip::kSave)
764 return true;
765 }
766 Flush(pDriver);
767 return false;
768 }
769
770 bool DrawChanged(const CFX_Matrix* pMatrix,
771 const CFX_GraphStateData* pState,
772 uint32_t fill_color,
773 uint32_t stroke_color,
774 int fill_mode,
775 int blend_type) {
776 return MatrixChanged(pMatrix, m_drawMatrix) ||
777 StateChanged(pState, m_drawState) || fill_color != m_fillColor ||
778 stroke_color != m_strokeColor ||
779 ((fill_mode & 3) == FXFILL_ALTERNATE) !=
780 (m_skPath.getFillType() == SkPath::kEvenOdd_FillType) ||
781 blend_type != m_blendType;
782 }
783
784 bool FontChanged(CFX_Font* pFont,
785 CFX_FontCache* pCache,
786 const CFX_Matrix* pMatrix,
787 FX_FLOAT font_size,
788 uint32_t color) {
789 return pFont != m_pFont || pCache != m_pCache ||
790 MatrixChanged(pMatrix, m_drawMatrix) || font_size != m_fontSize ||
791 color != m_fillColor;
792 }
793
794 bool MatrixChanged(const CFX_Matrix* pMatrix, const CFX_Matrix& refMatrix) {
795 return pMatrix->a != refMatrix.a || pMatrix->b != refMatrix.b ||
796 pMatrix->c != refMatrix.c || pMatrix->d != refMatrix.d;
797 }
798
799 bool StateChanged(const CFX_GraphStateData* pState,
800 const CFX_GraphStateData& refState) {
801 return pState->m_LineWidth != refState.m_LineWidth ||
802 pState->m_LineCap != refState.m_LineCap ||
803 pState->m_LineJoin != refState.m_LineJoin ||
804 pState->m_MiterLimit != refState.m_MiterLimit ||
805 DashChanged(pState, refState);
806 }
807
808 bool DashChanged(const CFX_GraphStateData* pState,
809 const CFX_GraphStateData& refState) {
810 if (!pState->m_DashArray && !refState.m_DashArray)
dsinclair 2016/06/29 13:22:28 Can't this just be removed in favour of the check
caryclark 2016/06/29 13:55:10 The first condition returns false when both items
dsinclair 2016/06/29 13:58:34 I can't read, I mis-read the second statement as r
811 return false;
812 if (!pState->m_DashArray || !refState.m_DashArray)
813 return true;
814 if (pState->m_DashPhase != refState.m_DashPhase ||
815 pState->m_DashCount != refState.m_DashCount) {
816 return true;
817 }
818 for (int index = 0; index < pState->m_DashCount; ++index) {
819 if (pState->m_DashArray[index] != refState.m_DashArray[index])
820 return false;
821 }
822 return true;
823 }
824
825 void Flush(CFX_SkiaDeviceDriver* pDriver) {
826 if (m_drawPath)
827 FlushPath(pDriver);
828 if (m_drawText)
829 FlushText(pDriver);
830 }
831
832 #ifdef SK_DEBUG
833 void Dump(CFX_SkiaDeviceDriver* pDriver) {
834 SkDebugf("\n\nSkia Save Count %d:\n", pDriver->m_pCanvas->getSaveCount());
835 pDriver->m_pCanvas->getClipStack()->dump();
836 SkDebugf("Cache:\n");
837 for (int index = 0; index < m_commands.count(); ++index) {
838 SkDebugf("%s ", m_commandIndex == index ? "-->" : " ");
839 switch (m_commands[index]) {
840 case Clip::kSave:
841 SkDebugf("Save\n");
842 break;
843 case Clip::kPath:
844 m_clips[index].dump();
845 break;
846 default:
847 SkDebugf("unknown\n");
848 }
849 }
850 if (m_commandIndex == m_commands.count())
851 SkDebugf("-->\n");
852 }
853 #endif
854
855 private:
856 SkTArray<SkPath> m_clips; // stack of clips that may be reused
857 SkTDArray<Clip> m_commands; // stack of clip-related commands
858 SkTDArray<SkPoint> m_positions; // accumulator for text positions
859 SkTDArray<uint16_t> m_glyphs; // accumulator for text glyphs
860 SkPath m_skPath; // accumulator for path contours
861 SkPath m_skEmptyPath; // used as placehold in the clips array
862 CFX_Matrix m_drawMatrix;
863 CFX_GraphStateData m_clipState;
864 CFX_GraphStateData m_drawState;
865 CFX_Matrix m_clipMatrix;
866 CFX_Font* m_pFont;
867 CFX_FontCache* m_pCache;
868 FX_FLOAT m_fontSize;
869 uint32_t m_fillColor;
870 uint32_t m_strokeColor;
871 int m_blendType;
872 int m_commandIndex; // active position in clip command stack
873 bool m_drawText;
874 bool m_drawPath;
875 bool m_fillPath;
876 bool m_debugDisable; // turn off cache for debugging
877 };
878
479 // convert a stroking path to scanlines 879 // convert a stroking path to scanlines
480 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, 880 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint,
481 const CFX_GraphStateData* pGraphState, 881 const CFX_GraphStateData* pGraphState,
482 const SkMatrix& matrix) { 882 const SkMatrix& matrix) {
483 SkPaint::Cap cap; 883 SkPaint::Cap cap;
484 switch (pGraphState->m_LineCap) { 884 switch (pGraphState->m_LineCap) {
485 case CFX_GraphStateData::LineCapRound: 885 case CFX_GraphStateData::LineCapRound:
486 cap = SkPaint::kRound_Cap; 886 cap = SkPaint::kRound_Cap;
487 break; 887 break;
488 case CFX_GraphStateData::LineCapSquare: 888 case CFX_GraphStateData::LineCapSquare:
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 spaint->setStrokeJoin(join); 941 spaint->setStrokeJoin(join);
542 } 942 }
543 943
544 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, 944 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap,
545 FX_BOOL bRgbByteOrder, 945 FX_BOOL bRgbByteOrder,
546 CFX_DIBitmap* pOriDevice, 946 CFX_DIBitmap* pOriDevice,
547 FX_BOOL bGroupKnockout) 947 FX_BOOL bGroupKnockout)
548 : m_pBitmap(pBitmap), 948 : m_pBitmap(pBitmap),
549 m_pOriDevice(pOriDevice), 949 m_pOriDevice(pOriDevice),
550 m_pRecorder(nullptr), 950 m_pRecorder(nullptr),
951 m_pCache(new SkiaState),
551 m_bRgbByteOrder(bRgbByteOrder), 952 m_bRgbByteOrder(bRgbByteOrder),
552 m_bGroupKnockout(bGroupKnockout) { 953 m_bGroupKnockout(bGroupKnockout) {
553 SkBitmap skBitmap; 954 SkBitmap skBitmap;
554 SkASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32); 955 SkASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32);
555 SkImageInfo imageInfo = SkImageInfo::Make( 956 SkImageInfo imageInfo = SkImageInfo::Make(
556 pBitmap->GetWidth(), pBitmap->GetHeight(), 957 pBitmap->GetWidth(), pBitmap->GetHeight(),
557 pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType, 958 pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType,
558 kOpaque_SkAlphaType); 959 kOpaque_SkAlphaType);
559 skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch(), 960 skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch(),
560 nullptr, /* to do : set color table */ 961 nullptr, /* to do : set color table */
561 nullptr, nullptr); 962 nullptr, nullptr);
562 m_pCanvas = new SkCanvas(skBitmap); 963 m_pCanvas = new SkCanvas(skBitmap);
563 if (m_bGroupKnockout) 964 if (m_bGroupKnockout)
564 SkDebugf(""); // FIXME(caryclark) suppress 'm_bGroupKnockout is unused' 965 SkDebugf(""); // FIXME(caryclark) suppress 'm_bGroupKnockout is unused'
565 } 966 }
566 967
567 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y) 968 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y)
568 : m_pBitmap(nullptr), 969 : m_pBitmap(nullptr),
569 m_pOriDevice(nullptr), 970 m_pOriDevice(nullptr),
570 m_pRecorder(new SkPictureRecorder), 971 m_pRecorder(new SkPictureRecorder),
972 m_pCache(new SkiaState),
571 m_bRgbByteOrder(FALSE), 973 m_bRgbByteOrder(FALSE),
572 m_bGroupKnockout(FALSE) { 974 m_bGroupKnockout(FALSE) {
573 m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y)); 975 m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y));
574 m_pCanvas = m_pRecorder->getRecordingCanvas(); 976 m_pCanvas = m_pRecorder->getRecordingCanvas();
575 } 977 }
576 978
577 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder) 979 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder)
578 : m_pBitmap(nullptr), 980 : m_pBitmap(nullptr),
579 m_pOriDevice(nullptr), 981 m_pOriDevice(nullptr),
580 m_pRecorder(recorder), 982 m_pRecorder(recorder),
983 m_pCache(new SkiaState),
581 m_bRgbByteOrder(FALSE), 984 m_bRgbByteOrder(FALSE),
582 m_bGroupKnockout(FALSE) { 985 m_bGroupKnockout(FALSE) {
583 m_pCanvas = m_pRecorder->getRecordingCanvas(); 986 m_pCanvas = m_pRecorder->getRecordingCanvas();
584 } 987 }
585 988
586 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() { 989 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
990 Flush();
587 if (!m_pRecorder) 991 if (!m_pRecorder)
588 delete m_pCanvas; 992 delete m_pCanvas;
993 delete m_pCache;
dsinclair 2016/06/29 13:22:28 Not needed with unique_ptr
caryclark 2016/06/29 13:55:10 Done.
994 }
995
996 void CFX_SkiaDeviceDriver::Flush() {
997 m_pCache->Flush(this);
998 m_pCache->FlushCommands(this);
589 } 999 }
590 1000
591 FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, 1001 FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars,
592 const FXTEXT_CHARPOS* pCharPos, 1002 const FXTEXT_CHARPOS* pCharPos,
593 CFX_Font* pFont, 1003 CFX_Font* pFont,
594 CFX_FontCache* pCache, 1004 CFX_FontCache* pCache,
595 const CFX_Matrix* pObject2Device, 1005 const CFX_Matrix* pObject2Device,
596 FX_FLOAT font_size, 1006 FX_FLOAT font_size,
597 uint32_t color) { 1007 uint32_t color) {
1008 if (m_pCache->DrawText(nChars, pCharPos, pFont, pCache, pObject2Device,
1009 font_size, color, this)) {
1010 return TRUE;
1011 }
598 sk_sp<SkTypeface> typeface(SkSafeRef(pCache->GetDeviceCache(pFont))); 1012 sk_sp<SkTypeface> typeface(SkSafeRef(pCache->GetDeviceCache(pFont)));
599 SkPaint paint; 1013 SkPaint paint;
600 paint.setAntiAlias(true); 1014 paint.setAntiAlias(true);
601 paint.setColor(color); 1015 paint.setColor(color);
602 paint.setTypeface(typeface); 1016 paint.setTypeface(typeface);
603 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1017 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
604 paint.setTextSize(font_size); 1018 paint.setTextSize(font_size);
605 paint.setSubpixelText(true); 1019 paint.setSubpixelText(true);
606 m_pCanvas->save(); 1020 m_pCanvas->save();
607 SkMatrix skMatrix = ToFlippedSkMatrix(*pObject2Device); 1021 SkMatrix skMatrix = ToFlippedSkMatrix(*pObject2Device);
(...skipping 27 matching lines...) Expand all
635 return 0; 1049 return 0;
636 case FXDC_RENDER_CAPS: 1050 case FXDC_RENDER_CAPS:
637 return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | 1051 return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
638 FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT | 1052 FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
639 FXRC_FILLSTROKE_PATH | FXRC_SHADING; 1053 FXRC_FILLSTROKE_PATH | FXRC_SHADING;
640 } 1054 }
641 return 0; 1055 return 0;
642 } 1056 }
643 1057
644 void CFX_SkiaDeviceDriver::SaveState() { 1058 void CFX_SkiaDeviceDriver::SaveState() {
645 m_pCanvas->save(); 1059 if (!m_pCache->ClipSave(this))
1060 m_pCanvas->save();
646 } 1061 }
647 1062
648 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) { 1063 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) {
649 m_pCanvas->restore(); 1064 if (!m_pCache->ClipRestore(this))
1065 m_pCanvas->restore();
650 if (bKeepSaved) 1066 if (bKeepSaved)
651 m_pCanvas->save(); 1067 SaveState();
652 } 1068 }
653 1069
654 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill( 1070 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill(
655 const CFX_PathData* pPathData, // path info 1071 const CFX_PathData* pPathData, // path info
656 const CFX_Matrix* pObject2Device, // flips object's y-axis 1072 const CFX_Matrix* pObject2Device, // flips object's y-axis
657 int fill_mode // fill mode, WINDING or ALTERNATE 1073 int fill_mode // fill mode, WINDING or ALTERNATE
658 ) { 1074 ) {
1075 CFX_Matrix identity;
1076 const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity;
1077 if (m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode, this))
1078 return TRUE;
659 if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) { 1079 if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) {
660 CFX_FloatRect rectf; 1080 CFX_FloatRect rectf;
661 if (pPathData->IsRect(pObject2Device, &rectf)) { 1081 if (pPathData->IsRect(deviceMatrix, &rectf)) {
662 rectf.Intersect( 1082 rectf.Intersect(
663 CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), 1083 CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH),
664 (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); 1084 (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
665 // note that PDF's y-axis goes up; Skia's y-axis goes down 1085 // note that PDF's y-axis goes up; Skia's y-axis goes down
666 SkRect skClipRect = 1086 SkRect skClipRect =
667 SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top); 1087 SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top);
668 DebugDrawSkiaClipRect(m_pCanvas, skClipRect); 1088 DebugDrawSkiaClipRect(m_pCanvas, skClipRect);
669 m_pCanvas->clipRect(skClipRect); 1089 m_pCanvas->clipRect(skClipRect, SkRegion::kIntersect_Op, true);
670 return TRUE; 1090 return TRUE;
671 } 1091 }
672 } 1092 }
673 SkPath skClipPath = BuildPath(pPathData); 1093 SkPath skClipPath = BuildPath(pPathData);
674 skClipPath.setFillType((fill_mode & 3) == FXFILL_WINDING 1094 skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
675 ? SkPath::kWinding_FillType 1095 ? SkPath::kEvenOdd_FillType
676 : SkPath::kEvenOdd_FillType); 1096 : SkPath::kWinding_FillType);
677 SkMatrix skMatrix = ToSkMatrix(*pObject2Device); 1097 SkMatrix skMatrix = ToSkMatrix(*deviceMatrix);
678 skClipPath.transform(skMatrix); 1098 skClipPath.transform(skMatrix);
679 DebugShowSkiaPath(skClipPath); 1099 DebugShowSkiaPath(skClipPath);
680 DebugDrawSkiaClipPath(m_pCanvas, skClipPath); 1100 DebugDrawSkiaClipPath(m_pCanvas, skClipPath);
681 m_pCanvas->clipPath(skClipPath); 1101 m_pCanvas->clipPath(skClipPath, SkRegion::kIntersect_Op, true);
682 1102
683 return TRUE; 1103 return TRUE;
684 } 1104 }
685 1105
686 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke( 1106 FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke(
687 const CFX_PathData* pPathData, // path info 1107 const CFX_PathData* pPathData, // path info
688 const CFX_Matrix* pObject2Device, // optional transformation 1108 const CFX_Matrix* pObject2Device, // optional transformation
689 const CFX_GraphStateData* pGraphState // graphic state, for pen attributes 1109 const CFX_GraphStateData* pGraphState // graphic state, for pen attributes
690 ) { 1110 ) {
1111 if (m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState, this))
1112 return TRUE;
691 // build path data 1113 // build path data
692 SkPath skPath = BuildPath(pPathData); 1114 SkPath skPath = BuildPath(pPathData);
693 skPath.setFillType(SkPath::kWinding_FillType);
694
695 SkMatrix skMatrix = ToSkMatrix(*pObject2Device); 1115 SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
696 SkPaint spaint; 1116 SkPaint skPaint;
697 PaintStroke(&spaint, pGraphState, skMatrix); 1117 PaintStroke(&skPaint, pGraphState, skMatrix);
698 SkPath dst_path; 1118 SkPath dst_path;
699 spaint.getFillPath(skPath, &dst_path); 1119 skPaint.getFillPath(skPath, &dst_path);
700 dst_path.transform(skMatrix); 1120 dst_path.transform(skMatrix);
701 DebugDrawSkiaClipPath(m_pCanvas, dst_path); 1121 DebugDrawSkiaClipPath(m_pCanvas, dst_path);
702 m_pCanvas->clipPath(dst_path); 1122 m_pCanvas->clipPath(dst_path, SkRegion::kIntersect_Op, true);
703 return TRUE; 1123 return TRUE;
704 } 1124 }
705 1125
706 FX_BOOL CFX_SkiaDeviceDriver::DrawPath( 1126 FX_BOOL CFX_SkiaDeviceDriver::DrawPath(
707 const CFX_PathData* pPathData, // path info 1127 const CFX_PathData* pPathData, // path info
708 const CFX_Matrix* pObject2Device, // optional transformation 1128 const CFX_Matrix* pObject2Device, // optional transformation
709 const CFX_GraphStateData* pGraphState, // graphic state, for pen attributes 1129 const CFX_GraphStateData* pGraphState, // graphic state, for pen attributes
710 uint32_t fill_color, // fill color 1130 uint32_t fill_color, // fill color
711 uint32_t stroke_color, // stroke color 1131 uint32_t stroke_color, // stroke color
712 int fill_mode, // fill mode, WINDING or ALTERNATE. 0 for not filled 1132 int fill_mode, // fill mode, WINDING or ALTERNATE. 0 for not filled
713 int blend_type) { 1133 int blend_type) {
1134 if (m_pCache->DrawPath(pPathData, pObject2Device, pGraphState, fill_color,
1135 stroke_color, fill_mode, blend_type, this)) {
1136 return TRUE;
1137 }
714 SkIRect rect; 1138 SkIRect rect;
715 rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), 1139 rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
716 GetDeviceCaps(FXDC_PIXEL_HEIGHT)); 1140 GetDeviceCaps(FXDC_PIXEL_HEIGHT));
717 SkMatrix skMatrix; 1141 SkMatrix skMatrix;
718 if (pObject2Device) 1142 if (pObject2Device)
719 skMatrix = ToSkMatrix(*pObject2Device); 1143 skMatrix = ToSkMatrix(*pObject2Device);
720 else 1144 else
721 skMatrix.setIdentity(); 1145 skMatrix.setIdentity();
722 SkPaint skPaint; 1146 SkPaint skPaint;
723 skPaint.setAntiAlias(true); 1147 skPaint.setAntiAlias(true);
724 int stroke_alpha = FXARGB_A(stroke_color); 1148 int stroke_alpha = FXARGB_A(stroke_color);
725 if (pGraphState && stroke_alpha) 1149 if (pGraphState && stroke_alpha)
726 PaintStroke(&skPaint, pGraphState, skMatrix); 1150 PaintStroke(&skPaint, pGraphState, skMatrix);
727 SkPath skPath = BuildPath(pPathData); 1151 SkPath skPath = BuildPath(pPathData);
728 m_pCanvas->save(); 1152 m_pCanvas->save();
729 m_pCanvas->concat(skMatrix); 1153 m_pCanvas->concat(skMatrix);
730 if ((fill_mode & 3) && fill_color) { 1154 if ((fill_mode & 3) && fill_color) {
731 skPath.setFillType((fill_mode & 3) == FXFILL_WINDING 1155 skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
732 ? SkPath::kWinding_FillType 1156 ? SkPath::kEvenOdd_FillType
733 : SkPath::kEvenOdd_FillType); 1157 : SkPath::kWinding_FillType);
734 SkPath strokePath; 1158 SkPath strokePath;
735 const SkPath* fillPath = &skPath; 1159 const SkPath* fillPath = &skPath;
736 if (pGraphState && stroke_alpha) { 1160 if (pGraphState && stroke_alpha) {
737 SkAlpha fillA = SkColorGetA(fill_color); 1161 SkAlpha fillA = SkColorGetA(fill_color);
738 SkAlpha strokeA = SkColorGetA(stroke_color); 1162 SkAlpha strokeA = SkColorGetA(stroke_color);
739 if (fillA && fillA < 0xFF && strokeA && strokeA < 0xFF) { 1163 if (fillA && fillA < 0xFF && strokeA && strokeA < 0xFF) {
740 skPaint.getFillPath(skPath, &strokePath); 1164 skPaint.getFillPath(skPath, &strokePath);
741 if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp, 1165 if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp,
742 &strokePath)) { 1166 &strokePath)) {
743 fillPath = &strokePath; 1167 fillPath = &strokePath;
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 skClip.transform(skMatrix); 1326 skClip.transform(skMatrix);
903 } 1327 }
904 SkMatrix inverse; 1328 SkMatrix inverse;
905 if (!skMatrix.invert(&inverse)) 1329 if (!skMatrix.invert(&inverse))
906 return false; 1330 return false;
907 skPath.addRect(skRect); 1331 skPath.addRect(skRect);
908 skPath.transform(inverse); 1332 skPath.transform(inverse);
909 } 1333 }
910 m_pCanvas->save(); 1334 m_pCanvas->save();
911 if (!skClip.isEmpty()) 1335 if (!skClip.isEmpty())
912 m_pCanvas->clipPath(skClip); 1336 m_pCanvas->clipPath(skClip, SkRegion::kIntersect_Op, true);
913 m_pCanvas->concat(skMatrix); 1337 m_pCanvas->concat(skMatrix);
914 m_pCanvas->drawPath(skPath, paint); 1338 m_pCanvas->drawPath(skPath, paint);
915 m_pCanvas->restore(); 1339 m_pCanvas->restore();
916 return true; 1340 return true;
917 } 1341 }
918 1342
919 uint8_t* CFX_SkiaDeviceDriver::GetBuffer() const { 1343 uint8_t* CFX_SkiaDeviceDriver::GetBuffer() const {
920 return m_pBitmap->GetBuffer(); 1344 return m_pBitmap->GetBuffer();
921 } 1345 }
922 1346
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 uint32_t flags, 1417 uint32_t flags,
994 int blend_type) { 1418 int blend_type) {
995 if (!m_pBitmap->GetBuffer()) 1419 if (!m_pBitmap->GetBuffer())
996 return TRUE; 1420 return TRUE;
997 CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left, 1421 CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left,
998 dest_top + dest_height); 1422 dest_top + dest_height);
999 1423
1000 m_pCanvas->save(); 1424 m_pCanvas->save();
1001 SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom, 1425 SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom,
1002 pClipRect->right, pClipRect->top); 1426 pClipRect->right, pClipRect->top);
1003 m_pCanvas->clipRect(skClipRect); 1427 m_pCanvas->clipRect(skClipRect, SkRegion::kIntersect_Op, true);
1004 void* dummy; 1428 void* dummy;
1005 FX_BOOL result = StartDIBits(pSource, 0xFF, argb, &m, 0, dummy, blend_type); 1429 FX_BOOL result = StartDIBits(pSource, 0xFF, argb, &m, 0, dummy, blend_type);
1006 m_pCanvas->restore(); 1430 m_pCanvas->restore();
1007 1431
1008 return result; 1432 return result;
1009 } 1433 }
1010 1434
1011 FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, 1435 FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
1012 int bitmap_alpha, 1436 int bitmap_alpha,
1013 uint32_t argb, 1437 uint32_t argb,
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1118 SkImageInfo unpremultipliedInfo = 1542 SkImageInfo unpremultipliedInfo =
1119 SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType); 1543 SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
1120 SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes); 1544 SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
1121 SkImageInfo premultipliedInfo = 1545 SkImageInfo premultipliedInfo =
1122 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType); 1546 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
1123 SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes); 1547 SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
1124 unpremultiplied.readPixels(premultiplied); 1548 unpremultiplied.readPixels(premultiplied);
1125 DebugVerifyBitmapIsPreMultiplied(buffer, width, height); 1549 DebugVerifyBitmapIsPreMultiplied(buffer, width, height);
1126 } 1550 }
1127 1551
1552 void CFX_SkiaDeviceDriver::Dump() {
1553 #ifdef SK_DEBUG
1554 if (m_pCache)
1555 m_pCache->Dump(this);
1556 #endif
1557 }
1558
1128 CFX_FxgeDevice::CFX_FxgeDevice() { 1559 CFX_FxgeDevice::CFX_FxgeDevice() {
1129 m_bOwnedBitmap = FALSE; 1560 m_bOwnedBitmap = FALSE;
1130 } 1561 }
1131 1562
1132 SkPictureRecorder* CFX_FxgeDevice::CreateRecorder(int size_x, int size_y) { 1563 SkPictureRecorder* CFX_FxgeDevice::CreateRecorder(int size_x, int size_y) {
1133 CFX_SkiaDeviceDriver* skDriver = new CFX_SkiaDeviceDriver(size_x, size_y); 1564 CFX_SkiaDeviceDriver* skDriver = new CFX_SkiaDeviceDriver(size_x, size_y);
1134 SetDeviceDriver(skDriver); 1565 SetDeviceDriver(skDriver);
1135 return skDriver->GetRecorder(); 1566 return skDriver->GetRecorder();
1136 } 1567 }
1137 1568
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1174 CFX_FxgeDevice::~CFX_FxgeDevice() { 1605 CFX_FxgeDevice::~CFX_FxgeDevice() {
1175 if (m_bOwnedBitmap && GetBitmap()) 1606 if (m_bOwnedBitmap && GetBitmap())
1176 delete GetBitmap(); 1607 delete GetBitmap();
1177 } 1608 }
1178 1609
1179 void CFX_FxgeDevice::PreMultiply() { 1610 void CFX_FxgeDevice::PreMultiply() {
1180 (static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver()))->PreMultiply(); 1611 (static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver()))->PreMultiply();
1181 } 1612 }
1182 1613
1183 #endif 1614 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698