Bug 1720152 - Recurse into replay for dependencies, rather than using a temp surface. r=jrmuizel,bobowen,emilio

Differential Revision: https://phabricator.services.mozilla.com/D120050
This commit is contained in:
Matt Woodrow 2021-08-09 22:07:36 +00:00
Родитель 4a06fcb21e
Коммит ec9b5dd838
18 изменённых файлов: 135 добавлений и 117 удалений

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

@ -1158,10 +1158,7 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
* This is considered fallible, and replaying this without making the surface
* available to the replay will just skip the draw.
*/
virtual void DrawDependentSurface(
uint64_t aId, const Rect& aDest,
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
const DrawOptions& aOptions = DrawOptions()) {
virtual void DrawDependentSurface(uint64_t aId, const Rect& aDest) {
MOZ_CRASH("GFX: DrawDependentSurface");
}

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

@ -375,12 +375,10 @@ void DrawTargetRecording::DrawSurface(SourceSurface* aSurface,
aSurfOptions, aOptions));
}
void DrawTargetRecording::DrawDependentSurface(
uint64_t aId, const Rect& aDest, const DrawSurfaceOptions& aSurfOptions,
const DrawOptions& aOptions) {
void DrawTargetRecording::DrawDependentSurface(uint64_t aId,
const Rect& aDest) {
mRecorder->AddDependentSurface(aId);
mRecorder->RecordEvent(
RecordedDrawDependentSurface(this, aId, aDest, aSurfOptions, aOptions));
mRecorder->RecordEvent(RecordedDrawDependentSurface(this, aId, aDest));
}
void DrawTargetRecording::DrawSurfaceWithShadow(

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

@ -62,10 +62,7 @@ class DrawTargetRecording : public DrawTarget {
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void DrawDependentSurface(
uint64_t aId, const Rect& aDest,
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void DrawDependentSurface(uint64_t aId, const Rect& aDest) override;
virtual void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
const Point& aDestPoint,

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

@ -493,12 +493,10 @@ void DrawTargetWrapAndRecord::DrawSurface(
aSurfOptions, aOptions);
}
void DrawTargetWrapAndRecord::DrawDependentSurface(
uint64_t aId, const Rect& aDest, const DrawSurfaceOptions& aSurfOptions,
const DrawOptions& aOptions) {
void DrawTargetWrapAndRecord::DrawDependentSurface(uint64_t aId,
const Rect& aDest) {
mRecorder->AddDependentSurface(aId);
mRecorder->RecordEvent(
RecordedDrawDependentSurface(this, aId, aDest, aSurfOptions, aOptions));
mRecorder->RecordEvent(RecordedDrawDependentSurface(this, aId, aDest));
}
void DrawTargetWrapAndRecord::DrawSurfaceWithShadow(

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

@ -59,10 +59,7 @@ class DrawTargetWrapAndRecord : public DrawTarget {
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void DrawDependentSurface(
uint64_t aId, const Rect& aDest,
const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void DrawDependentSurface(uint64_t aId, const Rect& aDest) override;
virtual void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
const Point& aDestPoint,

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

@ -111,35 +111,11 @@ already_AddRefed<DrawTarget> InlineTranslator::CreateDrawTarget(
already_AddRefed<SourceSurface> InlineTranslator::LookupExternalSurface(
uint64_t aKey) {
if (mExternalSurfaces) {
if (!mExternalSurfaces) {
return nullptr;
}
RefPtr<SourceSurface> surface = mExternalSurfaces->Get(aKey);
if (surface) {
return surface.forget();
}
}
if (!mDependentSurfaces) {
return nullptr;
}
RefPtr<RecordedDependentSurface> recordedSurface =
mDependentSurfaces->Get(aKey);
if (!recordedSurface) {
return nullptr;
}
RefPtr<DrawTarget> newDT = GetReferenceDrawTarget()->CreateSimilarDrawTarget(
recordedSurface->mSize, SurfaceFormat::B8G8R8A8);
InlineTranslator translator(newDT, nullptr);
translator.SetDependentSurfaces(mDependentSurfaces);
if (!translator.TranslateRecording((char*)recordedSurface->mRecording.mData,
recordedSurface->mRecording.mLen)) {
return nullptr;
}
RefPtr<SourceSurface> snapshot = newDT->Snapshot();
return snapshot.forget();
}
} // namespace mozilla::gfx

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

@ -13,7 +13,6 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Filters.h"
#include "mozilla/gfx/RecordedEvent.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace gfx {
@ -40,10 +39,8 @@ class InlineTranslator : public Translator {
nsRefPtrHashtable<nsUint64HashKey, SourceSurface>* aExternalSurfaces) {
mExternalSurfaces = aExternalSurfaces;
}
void SetDependentSurfaces(
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
aDependentSurfaces) {
mDependentSurfaces = aDependentSurfaces;
void SetReferenceDrawTargetTransform(const Matrix& aTransform) {
mBaseDTTransform = aTransform;
}
DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) final {
@ -163,12 +160,14 @@ class InlineTranslator : public Translator {
MOZ_ASSERT(mBaseDT, "mBaseDT has not been initialized.");
return mBaseDT;
}
Matrix GetReferenceDrawTargetTransform() final { return mBaseDTTransform; }
void* GetFontContext() final { return mFontContext; }
std::string GetError() { return mError; }
protected:
RefPtr<DrawTarget> mBaseDT;
Matrix mBaseDTTransform;
nsRefPtrHashtable<nsPtrHashKey<void>, DrawTarget> mDrawTargets;
private:
@ -184,8 +183,6 @@ class InlineTranslator : public Translator {
nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
nsRefPtrHashtable<nsUint64HashKey, SourceSurface>* mExternalSurfaces =
nullptr;
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
mDependentSurfaces = nullptr;
};
} // namespace gfx

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

@ -13,6 +13,7 @@
#include "Logging.h"
#include "ScaledFontBase.h"
#include "SFNTData.h"
#include "InlineTranslator.h"
namespace mozilla {
namespace gfx {
@ -170,5 +171,39 @@ already_AddRefed<DrawTarget> Translator::CreateDrawTarget(
return newDT.forget();
}
void Translator::DrawDependentSurface(ReferencePtr aDrawTarget, uint64_t aKey,
const Rect& aRect) {
if (!mDependentSurfaces) {
return;
}
DrawTarget* dt = LookupDrawTarget(aDrawTarget);
if (!dt) {
return;
}
RefPtr<RecordedDependentSurface> recordedSurface =
mDependentSurfaces->Get(aKey);
if (!recordedSurface) {
return;
}
dt->PushClipRect(aRect);
// Construct a new translator, so we can recurse into translating this
// sub-recording into the same DT. Set an initial transform for the
// translator, so that all commands get moved into the rect we want to draw.
Matrix transform = dt->GetTransform();
transform.PreTranslate(aRect.TopLeft());
InlineTranslator translator(dt, nullptr);
translator.SetReferenceDrawTargetTransform(transform);
translator.SetDependentSurfaces(mDependentSurfaces);
translator.TranslateRecording((char*)recordedSurface->mRecording.mData,
recordedSurface->mRecording.mLen);
dt->PopClip();
}
} // namespace gfx
} // namespace mozilla

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

@ -17,6 +17,7 @@
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ipc/ByteBuf.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace gfx {
@ -101,6 +102,8 @@ class Translator {
virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) {
return nullptr;
}
void DrawDependentSurface(ReferencePtr aDrawTarget, uint64_t aKey,
const Rect& aRect);
virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0;
virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0;
virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0;
@ -137,7 +140,17 @@ class Translator {
const IntSize& aSize,
SurfaceFormat aFormat);
virtual DrawTarget* GetReferenceDrawTarget() = 0;
virtual Matrix GetReferenceDrawTargetTransform() { return Matrix(); }
virtual void* GetFontContext() { return nullptr; }
void SetDependentSurfaces(
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
aDependentSurfaces) {
mDependentSurfaces = aDependentSurfaces;
}
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>*
mDependentSurfaces = nullptr;
};
struct ColorPatternStorage {

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

@ -706,14 +706,10 @@ class RecordedDrawSurface : public RecordedDrawingEvent<RecordedDrawSurface> {
class RecordedDrawDependentSurface
: public RecordedDrawingEvent<RecordedDrawDependentSurface> {
public:
RecordedDrawDependentSurface(DrawTarget* aDT, uint64_t aId, const Rect& aDest,
const DrawSurfaceOptions& aDSOptions,
const DrawOptions& aOptions)
RecordedDrawDependentSurface(DrawTarget* aDT, uint64_t aId, const Rect& aDest)
: RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aDT),
mId(aId),
mDest(aDest),
mDSOptions(aDSOptions),
mOptions(aOptions) {}
mDest(aDest) {}
bool PlayEvent(Translator* aTranslator) const override;
@ -731,8 +727,6 @@ class RecordedDrawDependentSurface
uint64_t mId;
Rect mDest;
DrawSurfaceOptions mDSOptions;
DrawOptions mOptions;
};
class RecordedDrawSurfaceWithShadow
@ -2780,7 +2774,16 @@ inline bool RecordedSetTransform::PlayEvent(Translator* aTranslator) const {
return false;
}
// If we're drawing to the reference DT, then we need to manually apply
// its initial transform, otherwise we'll just clobber it with only the
// the transform that was visible to the code doing the recording.
if (dt == aTranslator->GetReferenceDrawTarget()) {
dt->SetTransform(mTransform *
aTranslator->GetReferenceDrawTargetTransform());
} else {
dt->SetTransform(mTransform);
}
return true;
}
@ -2846,20 +2849,7 @@ inline void RecordedDrawSurface::OutputSimpleEventInfo(
inline bool RecordedDrawDependentSurface::PlayEvent(
Translator* aTranslator) const {
DrawTarget* dt = aTranslator->LookupDrawTarget(mDT);
if (!dt) {
return false;
}
// We still return true even if this fails, since dependent surfaces are
// used for cross-origin iframe drawing and can fail.
RefPtr<SourceSurface> surface = aTranslator->LookupExternalSurface(mId);
if (!surface) {
return true;
}
dt->DrawSurface(surface, mDest, Rect(Point(), Size(surface->GetSize())),
mDSOptions, mOptions);
aTranslator->DrawDependentSurface(mDT, mId, mDest);
return true;
}
@ -2868,8 +2858,6 @@ void RecordedDrawDependentSurface::Record(S& aStream) const {
RecordedDrawingEvent::Record(aStream);
WriteElement(aStream, mId);
WriteElement(aStream, mDest);
WriteElement(aStream, mDSOptions);
WriteElement(aStream, mOptions);
}
template <class S>
@ -2877,8 +2865,6 @@ RecordedDrawDependentSurface::RecordedDrawDependentSurface(S& aStream)
: RecordedDrawingEvent(DRAWDEPENDENTSURFACE, aStream) {
ReadElement(aStream, mId);
ReadElement(aStream, mDest);
ReadDrawSurfaceOptions(aStream, mDSOptions);
ReadDrawOptions(aStream, mOptions);
}
inline void RecordedDrawDependentSurface::OutputSimpleEventInfo(

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

@ -1372,9 +1372,19 @@ void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
return;
}
// Rendering the inner document will apply a scale to account for its
// app units per dev pixel ratio. We want to apply the inverse scaling
// using our app units per dev pixel ratio, so that no actual scaling
// will be applied if they match. For in-process rendering,
// nsSubDocumentFrame creates an nsDisplayZoom item if the app units
// per dev pixel ratio changes.
int32_t appUnitsPerDevPixel = pc->AppUnitsPerDevPixel();
gfxFloat scale = gfxFloat(AppUnitsPerCSSPixel()) / appUnitsPerDevPixel;
gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
aCtx->Multiply(gfxMatrix::Scaling(scale, scale));
Rect destRect =
NSRectToSnappedRect(GetContentRect(), appUnitsPerDevPixel, *target);
NSRectToSnappedRect(GetContentRect(), AppUnitsPerCSSPixel(), *target);
target->DrawDependentSurface(mPaintData.mTabId, destRect);
}

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

@ -82,26 +82,5 @@ already_AddRefed<DrawTarget> PrintTranslator::CreateDrawTarget(
return drawTarget.forget();
}
already_AddRefed<SourceSurface> PrintTranslator::LookupExternalSurface(
uint64_t aKey) {
RefPtr<RecordedDependentSurface> surface = mDependentSurfaces.Get(aKey);
if (!surface) {
return nullptr;
}
RefPtr<DrawTarget> newDT = GetReferenceDrawTarget()->CreateSimilarDrawTarget(
surface->mSize, SurfaceFormat::B8G8R8A8);
InlineTranslator translator(newDT, nullptr);
translator.SetDependentSurfaces(&mDependentSurfaces);
if (!translator.TranslateRecording((char*)surface->mRecording.mData,
surface->mRecording.mLen)) {
return nullptr;
}
RefPtr<SourceSurface> snapshot = newDT->Snapshot();
return snapshot.forget();
}
} // namespace layout
} // namespace mozilla

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

@ -13,7 +13,6 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Filters.h"
#include "mozilla/gfx/RecordedEvent.h"
#include "nsRefPtrHashtable.h"
class nsDeviceContext;
@ -38,12 +37,6 @@ class PrintTranslator final : public Translator {
bool TranslateRecording(PRFileDescStream& aRecording);
void SetDependentSurfaces(
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>&&
aDependentSurfaces) {
mDependentSurfaces = std::move(aDependentSurfaces);
}
DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) final {
DrawTarget* result = mDrawTargets.GetWeak(aRefPtr);
MOZ_ASSERT(result);
@ -91,8 +84,6 @@ class PrintTranslator final : public Translator {
return result;
}
already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) final;
void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) final {
mDrawTargets.InsertOrUpdate(aRefPtr, RefPtr{aDT});
}
@ -171,8 +162,6 @@ class PrintTranslator final : public Translator {
nsRefPtrHashtable<nsPtrHashKey<void>, ScaledFont> mScaledFonts;
nsRefPtrHashtable<nsPtrHashKey<void>, UnscaledFont> mUnscaledFonts;
nsRefPtrHashtable<nsUint64HashKey, NativeFontResource> mNativeFontResources;
nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>
mDependentSurfaces;
};
} // namespace layout

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

@ -162,11 +162,13 @@ nsresult RemotePrintJobParent::PrintPage(
return rv;
}
if (aFragments) {
mPrintTranslator->SetDependentSurfaces(std::move(*aFragments));
mPrintTranslator->SetDependentSurfaces(aFragments);
}
if (!mPrintTranslator->TranslateRecording(aRecording)) {
mPrintTranslator->SetDependentSurfaces(nullptr);
return NS_ERROR_FAILURE;
}
mPrintTranslator->SetDependentSurfaces(nullptr);
rv = mPrintDeviceContext->EndPage();
if (NS_WARN_IF(NS_FAILED(rv))) {

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

@ -0,0 +1,3 @@
[iframe-cross-origin-scaled-print.sub.html]
expected:
if fission and (os == "linux"): FAIL

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

@ -0,0 +1,17 @@
<!doctype html>
<link rel=match href="iframe-nested-scaled-print-ref.html">
<style>
body { margin: 0 }
div {
transform-origin: top left;
transform: scale(2);
overflow: hidden;
}
iframe {
width: 100px;
height: 50px;
}
</style>
<div>
<iframe frameborder=0 scrolling=no src="//{{hosts[alt][www]}}:{{ports[http][0]}}{{location[path]}}/../resources/iframe-nested-printing-pass.html"></iframe>
</div>

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

@ -0,0 +1,15 @@
<!doctype html>
<style>
body { margin: 0 }
div {
transform-origin: top left;
transform: scale(2);
}
iframe {
width: 100px;
height: 50px;
}
</style>
<div>
<iframe frameborder=0 scrolling=no src="resources/iframe-nested-printing-pass.html"></iframe>
</div>

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

@ -0,0 +1,9 @@
<!doctype html>
<style>
body {
margin: calc(0.5px * 2 / 3);
}
</style>
<body>
PASS
</body>