Bug 1311512 - Use recording draw target for mozPrintCallback canvases. r=jwatt draft printing
authorTobias Schneider <schneider@jancona.com>
Thu, 22 Dec 2016 11:11:15 -0800
branchprinting
changeset 453047 935fef8bd5773b6f58543d9632e056fbe3b6017e
parent 451656 7083c0d30e75fc102c715887af9faec933e936f8
child 724636 23e9d8167a7e1ec34af90ca9266e97d3671054bf
push id39554
push userbmo:tschneider@mozilla.com
push dateThu, 22 Dec 2016 19:11:52 +0000
reviewersjwatt
bugs1311512
milestone53.0a1
Bug 1311512 - Use recording draw target for mozPrintCallback canvases. r=jwatt MozReview-Commit-ID: 8sozCJVwbnR
gfx/2d/DrawTargetRecording.cpp
gfx/2d/DrawTargetRecording.h
gfx/2d/InlineTranslator.cpp
gfx/2d/InlineTranslator.h
gfx/2d/RecordedEvent.h
gfx/2d/moz.build
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicLayersImpl.cpp
layout/generic/nsSimplePageSequenceFrame.cpp
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -70,41 +70,16 @@ EnsureSurfaceStored(DrawEventRecorderPri
   RecordingSourceSurfaceUserData *userData = new RecordingSourceSurfaceUserData;
   userData->refPtr = aSurface;
   userData->recorder = aRecorder;
   aSurface->AddUserData(reinterpret_cast<UserDataKey*>(aRecorder),
                         userData, &RecordingSourceSurfaceUserDataFunc);
   return;
 }
 
-class SourceSurfaceRecording : public SourceSurface
-{
-public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording)
-  SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder)
-    : mFinalSurface(aFinalSurface), mRecorder(aRecorder)
-  {
-    mRecorder->AddStoredObject(this);
-  }
-
-  ~SourceSurfaceRecording()
-  {
-    mRecorder->RemoveStoredObject(this);
-    mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this));
-  }
-
-  virtual SurfaceType GetType() const { return SurfaceType::RECORDING; }
-  virtual IntSize GetSize() const { return mFinalSurface->GetSize(); }
-  virtual SurfaceFormat GetFormat() const { return mFinalSurface->GetFormat(); }
-  virtual already_AddRefed<DataSourceSurface> GetDataSurface() { return mFinalSurface->GetDataSurface(); }
-
-  RefPtr<SourceSurface> mFinalSurface;
-  RefPtr<DrawEventRecorderPrivate> mRecorder;
-};
-
 class GradientStopsRecording : public GradientStops
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording)
   GradientStopsRecording(GradientStops *aFinalGradientStops, DrawEventRecorderPrivate *aRecorder)
     : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder)
   {
     mRecorder->AddStoredObject(this);
--- a/gfx/2d/DrawTargetRecording.h
+++ b/gfx/2d/DrawTargetRecording.h
@@ -326,12 +326,37 @@ private:
   Path *GetPathForPathRecording(const Path *aPath) const;
   already_AddRefed<PathRecording> EnsurePathStored(const Path *aPath);
   void EnsurePatternDependenciesStored(const Pattern &aPattern);
 
   RefPtr<DrawEventRecorderPrivate> mRecorder;
   RefPtr<DrawTarget> mFinalDT;
 };
 
+class SourceSurfaceRecording : public SourceSurface
+{
+public:
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording)
+  SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder)
+    : mFinalSurface(aFinalSurface), mRecorder(aRecorder)
+  {
+    mRecorder->AddStoredObject(this);
+  }
+
+  ~SourceSurfaceRecording()
+  {
+    mRecorder->RemoveStoredObject(this);
+    mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this));
+  }
+
+  virtual SurfaceType GetType() const { return SurfaceType::RECORDING; }
+  virtual IntSize GetSize() const { return mFinalSurface->GetSize(); }
+  virtual SurfaceFormat GetFormat() const { return mFinalSurface->GetFormat(); }
+  virtual already_AddRefed<DataSourceSurface> GetDataSurface() { return mFinalSurface->GetDataSurface(); }
+
+  RefPtr<SourceSurface> mFinalSurface;
+  RefPtr<DrawEventRecorderPrivate> mRecorder;
+};
+
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_DRAWTARGETRECORDING_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/2d/InlineTranslator.cpp
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InlineTranslator.h"
+
+#include "gfxContext.h"
+#include "nsDeviceContext.h"
+#include "mozilla/gfx/RecordedEvent.h"
+#include "mozilla/gfx/RecordingTypes.h"
+#include "mozilla/UniquePtr.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace gfx {
+
+InlineTranslator::InlineTranslator(DrawTarget* aDT, Matrix aMatrix)
+{
+  mBaseDT = aDT;
+  mBaseTransform = aMatrix;
+}
+
+bool
+InlineTranslator::TranslateRecording(std::istream& aRecording)
+{
+  uint32_t magicInt;
+  ReadElement(aRecording, magicInt);
+  if (magicInt != mozilla::gfx::kMagicInt) {
+    return false;
+  }
+
+  uint16_t majorRevision;
+  ReadElement(aRecording, majorRevision);
+  if (majorRevision != kMajorRevision) {
+    return false;
+  }
+
+  uint16_t minorRevision;
+  ReadElement(aRecording, minorRevision);
+  if (minorRevision > kMinorRevision) {
+    return false;
+  }
+
+  int32_t eventType;
+  ReadElement(aRecording, eventType);
+  while (aRecording.good()) {
+    UniquePtr<RecordedEvent> recordedEvent(
+      RecordedEvent::LoadEventFromStream(aRecording,
+      static_cast<RecordedEvent::EventType>(eventType)));
+
+    // Make sure that the whole event was read from the stream successfully.
+    if (!aRecording.good() || !recordedEvent) {
+      return false;
+    }
+
+    if (recordedEvent->GetType() == RecordedEvent::SETTRANSFORM) {
+      RecordedSetTransform* event = static_cast<RecordedSetTransform*>(recordedEvent.get());
+      mBaseDT->SetTransform(event->mTransform * mBaseTransform);
+    } else {
+      if (!recordedEvent->PlayEvent(this)) {
+        return false;
+      }
+    }
+
+    ReadElement(aRecording, eventType);
+  }
+
+  return true;
+}
+
+already_AddRefed<DrawTarget>
+InlineTranslator::CreateDrawTarget(ReferencePtr aRefPtr,
+                                  const gfx::IntSize &aSize,
+                                  gfx::SurfaceFormat aFormat)
+{
+  RefPtr<DrawTarget> drawTarget = mBaseDT;
+  return drawTarget.forget();
+}
+
+FontType
+InlineTranslator::GetDesiredFontType()
+{
+  switch (mBaseDT->GetBackendType()) {
+    case BackendType::DIRECT2D:
+      return FontType::DWRITE;
+    case BackendType::CAIRO:
+      return FontType::CAIRO;
+    case BackendType::SKIA:
+      return FontType::SKIA;
+    default:
+      return FontType::CAIRO;
+  }
+}
+
+} // namespace gfx
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/2d/InlineTranslator.h
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layout_InlineTranslator_h
+#define mozilla_layout_InlineTranslator_h
+
+#include <istream>
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Filters.h"
+#include "mozilla/gfx/RecordedEvent.h"
+#include "nsRefPtrHashtable.h"
+
+namespace mozilla {
+namespace gfx {
+
+using gfx::Translator;
+using gfx::ReferencePtr;
+using gfx::DrawTarget;
+using gfx::Path;
+using gfx::SourceSurface;
+using gfx::FilterNode;
+using gfx::GradientStops;
+using gfx::ScaledFont;
+using gfx::NativeFontResource;
+
+class InlineTranslator final : public Translator
+{
+public:
+  explicit InlineTranslator(DrawTarget* aDT, Matrix aMatrix);
+
+  bool TranslateRecording(std::istream& aRecording);
+
+  DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) final
+  {
+    return mBaseDT;
+  }
+
+  Path* LookupPath(ReferencePtr aRefPtr) final
+  {
+    Path* result = mPaths.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) final
+  {
+    SourceSurface* result = mSourceSurfaces.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  FilterNode* LookupFilterNode(ReferencePtr aRefPtr) final
+  {
+    FilterNode* result = mFilterNodes.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  GradientStops* LookupGradientStops(ReferencePtr aRefPtr) final
+  {
+    GradientStops* result =  mGradientStops.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) final
+  {
+    ScaledFont* result = mScaledFonts.GetWeak(aRefPtr);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  NativeFontResource* LookupNativeFontResource(uint64_t aKey) final
+  {
+    NativeFontResource* result = mNativeFontResources.GetWeak(aKey);
+    MOZ_ASSERT(result);
+    return result;
+  }
+
+  void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) final { }
+
+  void AddPath(ReferencePtr aRefPtr, Path *aPath) final
+  {
+    mPaths.Put(aRefPtr, aPath);
+  }
+
+  void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aSurface) final
+  {
+    mSourceSurfaces.Put(aRefPtr, aSurface);
+  }
+
+  void AddFilterNode(ReferencePtr aRefPtr, FilterNode *aFilter) final
+  {
+    mFilterNodes.Put(aRefPtr, aFilter);
+  }
+
+  void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aStops) final
+  {
+    mGradientStops.Put(aRefPtr, aStops);
+  }
+
+  void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) final
+  {
+    mScaledFonts.Put(aRefPtr, aScaledFont);
+  }
+
+  void AddNativeFontResource(uint64_t aKey,
+                             NativeFontResource *aScaledFontResouce) final
+  {
+    mNativeFontResources.Put(aKey, aScaledFontResouce);
+  }
+
+  void RemoveDrawTarget(ReferencePtr aRefPtr) final { }
+
+  void RemovePath(ReferencePtr aRefPtr) final
+  {
+    mPaths.Remove(aRefPtr);
+  }
+
+  void RemoveSourceSurface(ReferencePtr aRefPtr) final
+  {
+    mSourceSurfaces.Remove(aRefPtr);
+  }
+
+  void RemoveFilterNode(ReferencePtr aRefPtr) final
+  {
+    mFilterNodes.Remove(aRefPtr);
+  }
+
+  void RemoveGradientStops(ReferencePtr aRefPtr) final
+  {
+    mGradientStops.Remove(aRefPtr);
+  }
+
+  void RemoveScaledFont(ReferencePtr aRefPtr) final
+  {
+    mScaledFonts.Remove(aRefPtr);
+  }
+
+  already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr,
+                                                const gfx::IntSize &aSize,
+                                                gfx::SurfaceFormat aFormat) final;
+
+  mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; }
+
+  mozilla::gfx::FontType GetDesiredFontType() final;
+
+private:
+  RefPtr<DrawTarget> mBaseDT;
+  Matrix             mBaseTransform;
+
+  nsRefPtrHashtable<nsPtrHashKey<void>, Path> mPaths;
+  nsRefPtrHashtable<nsPtrHashKey<void>, SourceSurface> mSourceSurfaces;
+  nsRefPtrHashtable<nsPtrHashKey<void>, FilterNode> mFilterNodes;
+  nsRefPtrHashtable<nsPtrHashKey<void>, GradientStops> mGradientStops;
+  nsRefPtrHashtable<nsPtrHashKey<void>, ScaledFont> mScaledFonts;
+  nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_layout_InlineTranslator_h
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -693,22 +693,22 @@ public:
   }
 
   virtual bool PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "SetTransform"; }
+
+  Matrix mTransform;
 private:
   friend class RecordedEvent;
 
    MOZ_IMPLICIT RecordedSetTransform(std::istream &aStream);
-
-  Matrix mTransform;
 };
 
 class RecordedDrawSurface : public RecordedDrawingEvent {
 public:
   RecordedDrawSurface(DrawTarget *aDT, ReferencePtr aRefSource, const Rect &aDest,
                       const Rect &aSource, const DrawSurfaceOptions &aDSOptions,
                       const DrawOptions &aOptions)
     : RecordedDrawingEvent(DRAWSURFACE, aDT), mRefSource(aRefSource), mDest(aDest)
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -19,20 +19,22 @@ EXPORTS.mozilla.gfx += [
     'BaseSize.h',
     'BezierUtils.h',
     'Blur.h',
     'BorrowedContext.h',
     'Coord.h',
     'CriticalSection.h',
     'DataSurfaceHelpers.h',
     'DrawEventRecorder.h',
+    'DrawTargetRecording.h',
     'DrawTargetTiled.h',
     'Filters.h',
     'Helpers.h',
     'HelpersCairo.h',
+    'InlineTranslator.h',
     'IterableArena.h',
     'JobScheduler.h',
     'JobScheduler_posix.h',
     'JobScheduler_win32.h',
     'Logging.h',
     'LoggingConstants.h',
     'Matrix.h',
     'MatrixFwd.h',
@@ -173,16 +175,17 @@ UNIFIED_SOURCES += [
     'SFNTData.cpp',
     'SFNTNameTable.cpp',
     'SourceSurfaceCairo.cpp',
     'SourceSurfaceRawData.cpp',
 ]
 
 SOURCES += [
     'Factory.cpp', # Need to suppress warnings in Skia header files.
+    'InlineTranslator.cpp',
 ]
 
 if CONFIG['CLANG_CXX']:
     SOURCES['Factory.cpp'].flags += ['-Wno-implicit-fallthrough']
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
 
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -105,18 +105,18 @@ BasicCanvasLayer::Paint(DrawTarget* aDT,
   }
 
   const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft);
 
   Matrix oldTM;
   if (needsYFlip) {
     oldTM = aDT->GetTransform();
     aDT->SetTransform(Matrix(oldTM).
-                        PreTranslate(0.0f, mBounds.height).
-                        PreScale(1.0f, -1.0f));
+                      PreTranslate(0.0f, mBounds.height).
+                      PreScale(1.0f, -1.0f));
   }
 
   FillRectWithMask(aDT, aDeviceOffset,
                    Rect(0, 0, mBounds.width, mBounds.height),
                    surface, mSamplingFilter,
                    DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                    aMaskLayer);
 
--- a/gfx/layers/basic/BasicLayersImpl.cpp
+++ b/gfx/layers/basic/BasicLayersImpl.cpp
@@ -7,16 +7,18 @@
 #include <new>                          // for operator new
 #include "Layers.h"                     // for Layer, etc
 #include "basic/BasicImplData.h"        // for BasicImplData
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "AutoMaskData.h"
+#include "mozilla/gfx/InlineTranslator.h"
+#include "mozilla/gfx/DrawTargetRecording.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 bool
 GetMaskData(Layer* aMaskLayer,
@@ -117,32 +119,65 @@ FillRectWithMask(DrawTarget* aDT,
                  SourceSurface* aSurface,
                  SamplingFilter aSamplingFilter,
                  const DrawOptions& aOptions,
                  ExtendMode aExtendMode,
                  SourceSurface* aMaskSource,
                  const Matrix* aMaskTransform,
                  const Matrix* aSurfaceTransform)
 {
+  MOZ_ASSERT((aMaskSource && aMaskTransform) ||
+             (!aMaskSource && !aMaskTransform),
+             "Either both or neither must be specified");
+
   if (aMaskSource && aMaskTransform) {
     aDT->PushClipRect(aRect);
     Matrix oldTransform = aDT->GetTransform();
 
     Matrix inverseMask = *aMaskTransform;
     inverseMask.Invert();
 
     Matrix transform = oldTransform * inverseMask;
     if (aSurfaceTransform) {
       transform = (*aSurfaceTransform) * transform;
     }
 
     SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
 
     aDT->SetTransform(*aMaskTransform);
     aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
+
+    aDT->SetTransform(oldTransform);
+    aDT->PopClip();
+    return;
+  }
+
+  if (aSurface->GetType() == SurfaceType::RECORDING) {
+    MOZ_ASSERT(aOptions.mAlpha == 1.0 &&
+               aOptions.mCompositionOp == CompositionOp::OP_OVER);
+
+    aDT->PushClipRect(aRect);
+    Matrix oldTransform = aDT->GetTransform();
+
+    Matrix transform = oldTransform;
+    if (aSurfaceTransform) {
+      transform = (*aSurfaceTransform) * transform;
+    }
+
+    InlineTranslator* translator = new InlineTranslator(aDT, transform);
+    SourceSurfaceRecording* ss = static_cast<SourceSurfaceRecording*>(aSurface);
+    DrawEventRecorderMemory* mr = static_cast<DrawEventRecorderMemory*>(ss->mRecorder.get());
+
+    size_t size = mr->RecordingSize();
+    char* buffer = new char[size];
+    mr->CopyRecording(buffer, size);
+    std::istringstream recording(std::string(buffer, size));
+
+    translator->TranslateRecording(recording);
+
     aDT->SetTransform(oldTransform);
     aDT->PopClip();
     return;
   }
 
   aDT->FillRect(aRect,
                 SurfacePattern(aSurface, aExtendMode,
                                aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
--- a/layout/generic/nsSimplePageSequenceFrame.cpp
+++ b/layout/generic/nsSimplePageSequenceFrame.cpp
@@ -16,16 +16,17 @@
 #include "nsPageFrame.h"
 #include "nsSubDocumentFrame.h"
 #include "nsRegion.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsHTMLCanvasFrame.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
+#include "mozilla/gfx/DrawEventRecorder.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsIDateTimeFormat.h"
 #include "nsServiceManagerUtils.h"
 #include <algorithm>
 
 #define OFFSET_NOT_SET -1
 
 using namespace mozilla;
@@ -632,18 +633,22 @@ nsSimplePageSequenceFrame::PrePrintNextP
       if (NS_WARN_IF(!drawTarget)) {
         return NS_ERROR_FAILURE;
       }
 
       for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
         HTMLCanvasElement* canvas = mCurrentCanvasList[i];
         nsIntSize size = canvas->GetSize();
 
+        RefPtr<mozilla::gfx::DrawEventRecorder> recorder =
+          new mozilla::gfx::DrawEventRecorderMemory();
         RefPtr<DrawTarget> canvasTarget =
           drawTarget->CreateSimilarDrawTarget(size, drawTarget->GetFormat());
+        canvasTarget =
+          mozilla::gfx::Factory::CreateRecordingDrawTarget(recorder, canvasTarget);
         if (!canvasTarget) {
           continue;
         }
 
         nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
         if (!ctx) {
           continue;
         }