Files
tubestation/dom/canvas/OffscreenCanvasRenderingContext2D.cpp
Emilio Cobos Álvarez 42a711655b Bug 1773558 - Move fixed-point font types to Rust. r=layout-reviewers,jfkthame
Now that cbindgen and rust support const generics, it seems more simple.

This centralizes all the relevant font constants etc in rust and avoids
conversions when going from rust to C++ and vice versa.

Differential Revision: https://phabricator.services.mozilla.com/D148847
2022-06-13 00:59:23 +00:00

253 lines
8.6 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "OffscreenCanvasRenderingContext2D.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/dom/OffscreenCanvasRenderingContext2DBinding.h"
#include "mozilla/dom/OffscreenCanvas.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/ServoCSSParser.h"
#include "gfxPlatform.h"
#include "gfxTextRun.h"
using namespace mozilla;
namespace mozilla::dom {
class OffscreenCanvasShutdownObserver final {
NS_INLINE_DECL_REFCOUNTING(OffscreenCanvasShutdownObserver)
public:
explicit OffscreenCanvasShutdownObserver(
OffscreenCanvasRenderingContext2D* aOwner)
: mOwner(aOwner) {}
void OnShutdown() {
if (mOwner) {
mOwner->OnShutdown();
mOwner = nullptr;
}
}
void ClearOwner() { mOwner = nullptr; }
private:
~OffscreenCanvasShutdownObserver() = default;
OffscreenCanvasRenderingContext2D* mOwner;
};
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_INHERITED(
OffscreenCanvasRenderingContext2D, CanvasRenderingContext2D)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OffscreenCanvasRenderingContext2D)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END_INHERITING(CanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(OffscreenCanvasRenderingContext2D)
return tmp->HasKnownLiveWrapper();
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(OffscreenCanvasRenderingContext2D)
return tmp->HasKnownLiveWrapper();
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(OffscreenCanvasRenderingContext2D)
return tmp->HasKnownLiveWrapper();
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_IMPL_ADDREF_INHERITED(OffscreenCanvasRenderingContext2D,
CanvasRenderingContext2D)
NS_IMPL_RELEASE_INHERITED(OffscreenCanvasRenderingContext2D,
CanvasRenderingContext2D)
OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(
layers::LayersBackend aCompositorBackend)
: CanvasRenderingContext2D(aCompositorBackend) {}
OffscreenCanvasRenderingContext2D::~OffscreenCanvasRenderingContext2D() =
default;
JSObject* OffscreenCanvasRenderingContext2D::WrapObject(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return OffscreenCanvasRenderingContext2D_Binding::Wrap(aCx, this,
aGivenProto);
}
nsIGlobalObject* OffscreenCanvasRenderingContext2D::GetParentObject() const {
return mOffscreenCanvas->GetOwnerGlobal();
}
NS_IMETHODIMP OffscreenCanvasRenderingContext2D::InitializeWithDrawTarget(
nsIDocShell* aShell, NotNull<gfx::DrawTarget*> aTarget) {
return NS_ERROR_NOT_IMPLEMENTED;
}
static nsAutoCString FamilyListToString(
const StyleFontFamilyList& aFamilyList) {
return StringJoin(","_ns, aFamilyList.list.AsSpan(),
[](nsACString& dst, const StyleSingleFontFamily& name) {
name.AppendToString(dst);
});
}
static void SerializeFontForCanvas(const StyleFontFamilyList& aList,
const gfxFontStyle& aStyle,
nsACString& aUsedFont) {
// Re-serialize the font shorthand as required by the canvas spec.
aUsedFont.Truncate();
if (!aStyle.style.IsNormal()) {
aStyle.style.ToString(aUsedFont);
aUsedFont.Append(" ");
}
// font-weight is serialized as a number
if (!aStyle.weight.IsNormal()) {
aUsedFont.AppendFloat(aStyle.weight.ToFloat());
}
// font-stretch is serialized using CSS Fonts 3 keywords, not percentages.
if (!aStyle.stretch.IsNormal() &&
Servo_FontStretch_SerializeKeyword(&aStyle.stretch, &aUsedFont)) {
aUsedFont.Append(" ");
}
// Serialize the computed (not specified) size, and the family name(s).
aUsedFont.AppendFloat(aStyle.size);
aUsedFont.Append("px ");
aUsedFont.Append(FamilyListToString(aList));
}
bool OffscreenCanvasRenderingContext2D::SetFontInternal(const nsACString& aFont,
ErrorResult& aError) {
// In the OffscreenCanvas case we don't have the context necessary to call
// GetFontStyleForServo(), as we do in the main-thread canvas context, so
// instead we borrow ParseFontShorthandForMatching to parse the attribute.
StyleComputedFontStyleDescriptor style(
StyleComputedFontStyleDescriptor::Normal());
StyleFontFamilyList list;
gfxFontStyle fontStyle;
float size = 0.0f;
if (!ServoCSSParser::ParseFontShorthandForMatching(
aFont, nullptr, list, fontStyle.style, fontStyle.stretch,
fontStyle.weight, &size)) {
return false;
}
fontStyle.size = size;
// TODO: Get a userFontSet from the Worker and pass to the fontGroup
// TODO: Should we be passing a language? Where from?
// TODO: Cache fontGroups in the Worker (use an nsFontCache?)
gfxFontGroup* fontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(nullptr, // aPresContext
list, // aFontFamilyList
&fontStyle, // aStyle
nullptr, // aLanguage
false, // aExplicitLanguage
nullptr, // aTextPerf
nullptr, // aUserFontSet
1.0); // aDevToCssSize
CurrentState().fontGroup = fontGroup;
SerializeFontForCanvas(list, fontStyle, CurrentState().font);
CurrentState().fontFont = nsFont(StyleFontFamily{list, false, false},
StyleCSSPixelLength::FromPixels(size));
CurrentState().fontLanguage = nullptr;
CurrentState().fontExplicitLanguage = false;
return true;
}
void OffscreenCanvasRenderingContext2D::AddShutdownObserver() {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
if (!workerPrivate) {
// We may be using OffscreenCanvas on the main thread.
CanvasRenderingContext2D::AddShutdownObserver();
return;
}
mOffscreenShutdownObserver =
MakeAndAddRef<OffscreenCanvasShutdownObserver>(this);
mWorkerRef = WeakWorkerRef::Create(
workerPrivate,
[observer = mOffscreenShutdownObserver] { observer->OnShutdown(); });
}
void OffscreenCanvasRenderingContext2D::RemoveShutdownObserver() {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
if (!workerPrivate) {
// We may be using OffscreenCanvas on the main thread.
CanvasRenderingContext2D::RemoveShutdownObserver();
return;
}
if (mOffscreenShutdownObserver) {
mOffscreenShutdownObserver->ClearOwner();
}
mOffscreenShutdownObserver = nullptr;
mWorkerRef = nullptr;
}
void OffscreenCanvasRenderingContext2D::OnShutdown() {
if (mOffscreenShutdownObserver) {
mOffscreenShutdownObserver->ClearOwner();
mOffscreenShutdownObserver = nullptr;
}
CanvasRenderingContext2D::OnShutdown();
}
void OffscreenCanvasRenderingContext2D::Commit(ErrorResult& aRv) {
if (!mOffscreenCanvas->IsTransferredFromElement()) {
return;
}
mOffscreenCanvas->CommitFrameToCompositor();
}
void OffscreenCanvasRenderingContext2D::AddZoneWaitingForGC() {
JSObject* wrapper = GetWrapperPreserveColor();
if (wrapper) {
CycleCollectedJSRuntime::Get()->AddZoneWaitingForGC(
JS::GetObjectZone(wrapper));
}
}
void OffscreenCanvasRenderingContext2D::AddAssociatedMemory() {
JSObject* wrapper = GetWrapperMaybeDead();
if (wrapper) {
JS::AddAssociatedMemory(wrapper, BindingJSObjectMallocBytes(this),
JS::MemoryUse::DOMBinding);
}
}
void OffscreenCanvasRenderingContext2D::RemoveAssociatedMemory() {
JSObject* wrapper = GetWrapperMaybeDead();
if (wrapper) {
JS::RemoveAssociatedMemory(wrapper, BindingJSObjectMallocBytes(this),
JS::MemoryUse::DOMBinding);
}
}
size_t BindingJSObjectMallocBytes(OffscreenCanvasRenderingContext2D* aContext) {
gfx::IntSize size = aContext->GetSize();
// TODO: Bug 1552137: No memory will be allocated if either dimension is
// greater than gfxPrefs::gfx_canvas_max_size(). We should check this here
// too.
CheckedInt<uint32_t> bytes =
CheckedInt<uint32_t>(size.width) * size.height * 4;
if (!bytes.isValid()) {
return 0;
}
return bytes.value();
}
} // namespace mozilla::dom