/* -*- 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/. */
// The optimized surface holds a reference to our surface, for GetDataSurface // calls, so we must hold a weak reference to avoid circular dependency.
ThreadSafeWeakPtr<SourceSurface> optimizedSurface;
};
staticbool EnsureSurfaceStoredRecording(DrawEventRecorderPrivate* aRecorder,
SourceSurface* aSurface, constchar* reason) { // It's important that TryAddStoredObject is called first because that will // run any pending processing required by recorded objects that have been // deleted off the main thread. if (!aRecorder->TryAddStoredObject(aSurface)) { // Surface is already stored. returnfalse;
}
aRecorder->StoreSourceSurfaceRecording(aSurface, reason);
aRecorder->AddSourceSurface(aSurface);
IntSize mSize;
SurfaceFormat mFormat;
RefPtr<DrawEventRecorderPrivate> mRecorder; // If a SourceSurfaceRecording is returned from an OptimizeSourceSurface call // we need GetDataSurface to work, so we hold the original surface we // optimized to return its GetDataSurface.
RefPtr<SourceSurface> mOriginalSurface;
};
class GradientStopsRecording : public GradientStops { public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording, override)
class FilterNodeRecording : public FilterNode { public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording, override) using FilterNode::SetAttribute;
UserDataKey* userDataKey = reinterpret_cast<UserDataKey*>(mRecorder.get()); if (mRecorder->WantsExternalFonts()) {
mRecorder->AddScaledFont(aFont);
} elseif (!aFont->GetUserData(userDataKey)) {
UnscaledFont* unscaledFont = aFont->GetUnscaledFont(); if (mRecorder->IncrementUnscaledFontRefCount(unscaledFont) == 0) { // Prefer sending the description, if we can create one. This ensures // we don't record the data of system fonts which saves time and can // prevent duplicate copies from accumulating in the OS cache during // playback.
RecordedFontDescriptor fontDesc(unscaledFont); if (fontDesc.IsValid()) {
RecordEventSkipFlushTransform(fontDesc);
} else {
RecordedFontData fontData(unscaledFont);
RecordedFontDetails fontDetails; if (fontData.GetFontDetails(fontDetails)) { // Try to serialise the whole font, just in case this is a web font // that is not present on the system. if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
RecordEventSkipFlushTransform(fontData);
mRecorder->AddStoredFontData(fontDetails.fontDataKey);
}
RecordEventSkipFlushTransform(
RecordedUnscaledFontCreation(unscaledFont, fontDetails));
} else {
gfxWarning() << "DrawTargetRecording::FillGlyphs failed to serialise " "UnscaledFont";
}
}
}
RecordEventSkipFlushTransform(
RecordedScaledFontCreation(aFont, unscaledFont));
RecordingFontUserData* userData = new RecordingFontUserData;
userData->refPtr = aFont;
userData->unscaledFont = unscaledFont;
userData->recorder = mRecorder;
aFont->AddUserData(userDataKey, userData,
&RecordingFontUserDataDestroyFunc);
userData->recorder->AddScaledFont(aFont);
}
void DrawTargetRecording::PushClip(const Path* aPath) { if (!aPath) { return;
}
// The canvas doesn't have a clipRect API so we always end up in the generic // path. The D2D backend doesn't have a good way of specializing rectangular // clips so we take advantage of the fact that aPath is usually backed by a // SkiaPath which implements AsRect() and specialize it here. auto rect = aPath->AsRect(); if (rect.isSome()) {
PushClipRect(rect.value()); return;
}
already_AddRefed<SourceSurface> DrawTargetRecording::OptimizeSourceSurface(
SourceSurface* aSurface) const { // See if we have a previously optimized surface available. We have to do this // check before the SurfaceType::RECORDING below, because aSurface might be a // SurfaceType::RECORDING from another recorder we have previously optimized. auto* userData = static_cast<RecordingSourceSurfaceUserData*>(
aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))); if (userData) {
RefPtr<SourceSurface> strongRef(userData->optimizedSurface); if (strongRef) { return do_AddRef(strongRef);
}
} else { if (!EnsureSurfaceStoredRecording(mRecorder, aSurface, "OptimizeSourceSurface")) { // Surface was already stored, but doesn't have UserData so must be one // of our recording surfaces.
MOZ_ASSERT(aSurface->GetType() == SurfaceType::RECORDING); return do_AddRef(aSurface);
}
userData = static_cast<RecordingSourceSurfaceUserData*>(
aSurface->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get())));
MOZ_ASSERT(userData, "User data should always have been set by " "EnsureSurfaceStoredRecording.");
}
already_AddRefed<DrawTarget>
DrawTargetRecording::CreateSimilarDrawTargetWithBacking( const IntSize& aSize, SurfaceFormat aFormat) const { if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) { // If the requested similar draw target is too big, then we should try to // rasterize on the content side to avoid duplicating the effort when a // blob image gets tiled. If we fail somehow to produce it, we can fall // back to recording.
constexpr int32_t kRasterThreshold = 256 * 256 * 4;
int32_t stride = aSize.width * BytesPerPixel(aFormat);
int32_t surfaceBytes = aSize.height * stride; if (surfaceBytes >= kRasterThreshold) { auto surface = MakeRefPtr<SourceSurfaceSharedData>(); if (surface->Init(aSize, stride, aFormat)) { auto dt = MakeRefPtr<DrawTargetSkia>(); if (dt->Init(std::move(surface))) { return dt.forget();
} else {
MOZ_ASSERT_UNREACHABLE("Skia should initialize given surface!");
}
}
}
}
return CreateSimilarDrawTarget(aSize, aFormat);
}
already_AddRefed<DrawTarget> DrawTargetRecording::CreateSimilarDrawTarget( const IntSize& aSize, SurfaceFormat aFormat) const {
RefPtr<DrawTargetRecording> similarDT; if (mFinalDT->CanCreateSimilarDrawTarget(aSize, aFormat)) {
similarDT = new DrawTargetRecording(this, IntRect(IntPoint(0, 0), aSize), aFormat);
similarDT->SetOptimizeTransform(mOptimizeTransform);
RecordEventSelfSkipFlushTransform(
RecordedCreateSimilarDrawTarget(similarDT.get(), aSize, aFormat));
} elseif (XRE_IsContentProcess()) { // Crash any content process that calls this function with arguments that // would fail to create a similar draw target. We do this to root out bad // callers. We don't want to crash any important processes though so for // for those we'll just gracefully return nullptr.
MOZ_CRASH( "Content-process DrawTargetRecording can't create requested similar " "drawtarget");
} return similarDT.forget();
}
// It's important that AddStoredObject or TryAddStoredObject is called before // this because that will run any pending processing required by recorded // objects that have been deleted off the main thread.
RecordEventSelfSkipFlushTransform(RecordedPathCreation(pathRecording.get()));
pathRecording->mStoredRecorders.push_back(mRecorder);
return pathRecording.forget();
}
// This should only be called on the 'root' DrawTargetRecording. // Calling it on a child DrawTargetRecordings will cause confusion. void DrawTargetRecording::FlushItem(const IntRect& aBounds) {
mRecorder->FlushItem(aBounds); // Reinitialize the recorder (FlushItem will write a new recording header) // Tell the new recording about our draw target // This code should match what happens in the DrawTargetRecording constructor.
MOZ_DIAGNOSTIC_ASSERT(mRecorder->GetRecorderType() ==
RecorderType::WEBRENDER);
RecordEventSkipFlushTransform(
RecordedDrawTargetCreation(this, mFinalDT->GetBackendType(), mRect,
mFinalDT->GetFormat(), false, nullptr)); // RecordedDrawTargetCreation can actually reuse the base DrawTarget for the // recording, but we cannot conclude that from here, so force the transform // to be recorded.
RecordTransform(mTransform);
mTransformDirty = false;
}
void DrawTargetRecording::EnsurePatternDependenciesStored( const Pattern& aPattern) { switch (aPattern.GetType()) { case PatternType::COLOR: // No dependencies here. return; case PatternType::LINEAR_GRADIENT: {
MOZ_ASSERT_IF( static_cast<const LinearGradientPattern*>(&aPattern)->mStops,
mRecorder->HasStoredObject( static_cast<const LinearGradientPattern*>(&aPattern)->mStops)); return;
} case PatternType::RADIAL_GRADIENT: {
MOZ_ASSERT_IF( static_cast<const RadialGradientPattern*>(&aPattern)->mStops,
mRecorder->HasStoredObject( static_cast<const RadialGradientPattern*>(&aPattern)->mStops)); return;
} case PatternType::CONIC_GRADIENT: {
MOZ_ASSERT_IF( static_cast<const ConicGradientPattern*>(&aPattern)->mStops,
mRecorder->HasStoredObject( static_cast<const ConicGradientPattern*>(&aPattern)->mStops)); return;
} case PatternType::SURFACE: { const SurfacePattern* pat = static_cast<const SurfacePattern*>(&aPattern);
EnsureSurfaceStoredRecording(mRecorder, pat->mSurface, "EnsurePatternDependenciesStored"); return;
}
}
}
} // namespace gfx
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.