Bug 1279654 - Create a PrintTargetRecording subclass of PrintTarget. r=mstange

This commit is contained in:
Jonathan Watt 2016-06-13 17:19:08 +01:00
Родитель 4b40fd1bc1
Коммит f048425035
8 изменённых файлов: 171 добавлений и 67 удалений

Просмотреть файл

@ -52,6 +52,10 @@ PrintTarget::MakeDrawTarget(const IntSize& aSize,
MOZ_ASSERT(mCairoSurface,
"We shouldn't have been constructed without a cairo surface");
MOZ_ASSERT(!aRecorder,
"aRecorder should only be passed to an instance of "
"PrintTargetRecording");
if (cairo_surface_status(mCairoSurface)) {
return nullptr;
}
@ -65,36 +69,6 @@ PrintTarget::MakeDrawTarget(const IntSize& aSize,
return nullptr;
}
if (aRecorder) {
dt = CreateRecordingDrawTarget(aRecorder, dt);
if (!dt || !dt->IsValid()) {
return nullptr;
}
}
return dt.forget();
}
already_AddRefed<DrawTarget>
PrintTarget::CreateRecordingDrawTarget(DrawEventRecorder* aRecorder,
DrawTarget* aDrawTarget)
{
MOZ_ASSERT(aRecorder);
MOZ_ASSERT(aDrawTarget);
RefPtr<DrawTarget> dt;
if (aRecorder) {
// It doesn't really matter what we pass as the DrawTarget here.
dt = gfx::Factory::CreateRecordingDrawTarget(aRecorder, aDrawTarget);
}
if (!dt || !dt->IsValid()) {
gfxCriticalNote
<< "Failed to create a recording DrawTarget for PrintTarget";
return nullptr;
}
return dt.forget();
}

Просмотреть файл

@ -99,8 +99,6 @@ public:
* We'd need to check that our consumers always pass the same aRecorder for
* our entire lifetime.
*
* XXX Once PrintTargetThebes is removed this can become non-virtual.
*
* XXX In the long run, this class and its sub-classes should be converted to
* use STL classes and mozilla::RefCounted<> so the can be moved to Moz2D.
*
@ -119,10 +117,6 @@ protected:
// Protected because we're refcounted
virtual ~PrintTarget();
already_AddRefed<DrawTarget>
CreateRecordingDrawTarget(DrawEventRecorder* aRecorder,
DrawTarget* aDrawTarget);
cairo_surface_t* mCairoSurface;
IntSize mSize;
bool mIsFinished;

Просмотреть файл

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "PrintTargetRecording.h"
#include "cairo.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
namespace mozilla {
namespace gfx {
PrintTargetRecording::PrintTargetRecording(cairo_surface_t* aCairoSurface,
const IntSize& aSize)
: PrintTarget(aCairoSurface, aSize)
{
}
/* static */ already_AddRefed<PrintTargetRecording>
PrintTargetRecording::CreateOrNull(const IntSize& aSize)
{
if (!Factory::CheckSurfaceSize(aSize)) {
return nullptr;
}
// Perhaps surprisingly, this surface is never actually drawn to. This class
// creates a DrawTargetRecording using CreateRecordingDrawTarget, and that
// needs another DrawTarget to be passed to it. You might expect the type of
// the DrawTarget that is passed to matter because it would seem logical to
// encoded its type in the recording, and on replaying the recording a
// DrawTarget of the same type would be created. However, the passed
// DrawTarget's type doesn't seem to be encoded any more accurately than just
// "BackendType::CAIRO". Even if it were, the code that replays the
// recording is PrintTranslator::TranslateRecording which (indirectly) calls
// MakePrintTarget on the type of nsIDeviceContextSpecProxy that is created
// for the platform that we're running on, and the type of DrawTarget that
// that returns is hardcoded.
//
// The only reason that we use cairo_recording_surface_create here is:
//
// * It's pretty much the only cairo_*_surface_create methods that's both
// available on all platforms and doesn't require allocating a
// potentially large surface.
//
// * Since we need a DrawTarget to pass to CreateRecordingDrawTarget we
// might as well leverage our base class's machinery to create a
// DrawTarget (it's as good a way as any other that will work), and to do
// that we need a cairo_surface_t.
//
// So the fact that this is a "recording" PrintTarget and the function that
// we call here is cairo_recording_surface_create is simply a coincidence. We
// could use any cairo_*_surface_create method and this class would still
// work.
//
cairo_surface_t* surface =
cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, nullptr);
if (cairo_surface_status(surface)) {
return nullptr;
}
// The new object takes ownership of our surface reference.
RefPtr<PrintTargetRecording> target =
new PrintTargetRecording(surface, aSize);
return target.forget();
}
already_AddRefed<DrawTarget>
PrintTargetRecording::MakeDrawTarget(const IntSize& aSize,
DrawEventRecorder* aRecorder)
{
MOZ_ASSERT(aRecorder, "A DrawEventRecorder is required");
if (!aRecorder) {
return nullptr;
}
RefPtr<DrawTarget> dt = PrintTarget::MakeDrawTarget(aSize, nullptr);
if (dt) {
dt = CreateRecordingDrawTarget(aRecorder, dt);
if (!dt || !dt->IsValid()) {
return nullptr;
}
}
return dt.forget();
}
already_AddRefed<DrawTarget>
PrintTargetRecording::CreateRecordingDrawTarget(DrawEventRecorder* aRecorder,
DrawTarget* aDrawTarget)
{
MOZ_ASSERT(aRecorder);
MOZ_ASSERT(aDrawTarget);
RefPtr<DrawTarget> dt;
if (aRecorder) {
// It doesn't really matter what we pass as the DrawTarget here.
dt = gfx::Factory::CreateRecordingDrawTarget(aRecorder, aDrawTarget);
}
if (!dt || !dt->IsValid()) {
gfxCriticalNote
<< "Failed to create a recording DrawTarget for PrintTarget";
return nullptr;
}
return dt.forget();
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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_GFX_PRINTTARGETRECORDING_H
#define MOZILLA_GFX_PRINTTARGETRECORDING_H
#include "PrintTarget.h"
namespace mozilla {
namespace gfx {
/**
* Recording printing target.
*
* This exists for use on e10s's content process in order to record print
* output, send it over to the parent process, and replay it on a DrawTarget
* there for printing.
*/
class PrintTargetRecording final : public PrintTarget
{
public:
static already_AddRefed<PrintTargetRecording>
CreateOrNull(const IntSize& aSize);
virtual already_AddRefed<DrawTarget>
MakeDrawTarget(const IntSize& aSize,
DrawEventRecorder* aRecorder = nullptr) override;
private:
PrintTargetRecording(cairo_surface_t* aCairoSurface,
const IntSize& aSize);
already_AddRefed<DrawTarget>
CreateRecordingDrawTarget(DrawEventRecorder* aRecorder,
DrawTarget* aDrawTarget);
};
} // namespace gfx
} // namespace mozilla
#endif /* MOZILLA_GFX_PRINTTARGETRECORDING_H */

Просмотреть файл

@ -36,19 +36,16 @@ already_AddRefed<DrawTarget>
PrintTargetThebes::MakeDrawTarget(const IntSize& aSize,
DrawEventRecorder* aRecorder)
{
MOZ_ASSERT(!aRecorder,
"aRecorder should only be passed to an instance of "
"PrintTargetRecording");
RefPtr<gfx::DrawTarget> dt =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mGfxSurface, aSize);
if (!dt || !dt->IsValid()) {
return nullptr;
}
if (aRecorder) {
dt = CreateRecordingDrawTarget(aRecorder, dt);
if (!dt || !dt->IsValid()) {
return nullptr;
}
}
return dt.forget();
}

Просмотреть файл

@ -19,9 +19,6 @@ namespace gfx {
* This class should go away once all the logic from the gfxASurface subclasses
* has been moved to new PrintTarget subclasses and we no longer need to
* wrap a gfxASurface.
*
* When removing this class, be sure to make PrintTarget::MakeDrawTarget
* non-virtual!
*/
class PrintTargetThebes final : public PrintTarget {
public:

Просмотреть файл

@ -52,6 +52,7 @@ EXPORTS += [
EXPORTS.mozilla.gfx += [
'PrintTarget.h',
'PrintTargetRecording.h',
'PrintTargetThebes.h',
]
@ -217,6 +218,7 @@ SOURCES += [
'gfxPlatform.cpp',
'gfxPrefs.cpp',
'PrintTarget.cpp',
'PrintTargetRecording.cpp',
'PrintTargetThebes.cpp',
]

Просмотреть файл

@ -6,10 +6,9 @@
#include "nsDeviceContextSpecProxy.h"
#include "gfxASurface.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/gfx/PrintTargetThebes.h"
#include "mozilla/gfx/PrintTargetRecording.h"
#include "mozilla/layout/RemotePrintJobChild.h"
#include "mozilla/RefPtr.h"
#include "mozilla/unused.h"
@ -80,25 +79,7 @@ nsDeviceContextSpecProxy::MakePrintTarget()
width /= TWIPS_PER_POINT_FLOAT;
height /= TWIPS_PER_POINT_FLOAT;
RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(mozilla::gfx::IntSize(width, height),
mozilla::gfx::SurfaceFormat::A8R8G8B8_UINT32);
if (!surface) {
return nullptr;
}
// The type of PrintTarget that we return here doesn't really matter since
// our implementation of GetDrawEventRecorder returns an object, which means
// the DrawTarget returned by the PrintTarget will be a DrawTargetRecording.
// The recording will be serialized and sent over to the parent process where
// PrintTranslator::TranslateRecording will call MakePrintTarget (indirectly
// via PrintTranslator::CreateDrawTarget) on whatever type of
// nsIDeviceContextSpecProxy is created for the platform that we are running
// on. It is that DrawTarget that the recording will be replayed on to
// print.
RefPtr<PrintTarget> target = PrintTargetThebes::CreateOrNull(surface);
return target.forget();
return PrintTargetRecording::CreateOrNull(IntSize(width, height));
}
NS_IMETHODIMP