Bug 1311512 - Use recording draw target for mozPrintCallback canvases. r=jwatt
MozReview-Commit-ID: 8sozCJVwbnR
--- 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;
}