Bug 1728999 - Implement the CanvasRenderingContext2D.direction property. r=lsalzman,emilio

Differential Revision: https://phabricator.services.mozilla.com/D142701
This commit is contained in:
Jonathan Kew 2022-04-05 12:44:42 +00:00
parent 8169edb3db
commit b50d715cc5
3 changed files with 53 additions and 14 deletions

View File

@ -1006,6 +1006,7 @@ CanvasRenderingContext2D::ContextState::ContextState(const ContextState& aOther)
font(aOther.font),
textAlign(aOther.textAlign),
textBaseline(aOther.textBaseline),
textDirection(aOther.textDirection),
shadowColor(aOther.shadowColor),
transform(aOther.transform),
shadowOffset(aOther.shadowOffset),
@ -3534,6 +3535,30 @@ void CanvasRenderingContext2D::GetTextBaseline(nsAString& aTextBaseline) {
}
}
void CanvasRenderingContext2D::SetDirection(const nsAString& aDirection) {
if (aDirection.EqualsLiteral("ltr")) {
CurrentState().textDirection = TextDirection::LTR;
} else if (aDirection.EqualsLiteral("rtl")) {
CurrentState().textDirection = TextDirection::RTL;
} else if (aDirection.EqualsLiteral("inherit")) {
CurrentState().textDirection = TextDirection::INHERIT;
}
}
void CanvasRenderingContext2D::GetDirection(nsAString& aDirection) {
switch (CurrentState().textDirection) {
case TextDirection::LTR:
aDirection.AssignLiteral("ltr");
break;
case TextDirection::RTL:
aDirection.AssignLiteral("rtl");
break;
case TextDirection::INHERIT:
aDirection.AssignLiteral("inherit");
break;
}
}
/*
* Helper function that replaces the whitespace characters in a string
* with U+0020 SPACE. The whitespace characters are defined as U+0020 SPACE,
@ -3689,11 +3714,11 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor
using ContextState = CanvasRenderingContext2D::ContextState;
virtual void SetText(const char16_t* aText, int32_t aLength,
mozilla::intl::BidiDirection aDirection) override {
intl::BidiDirection aDirection) override {
mFontgrp->UpdateUserFonts(); // ensure user font generation is current
// adjust flags for current direction run
gfx::ShapedTextFlags flags = mTextRunFlags;
if (aDirection == mozilla::intl::BidiDirection::RTL) {
if (aDirection == intl::BidiDirection::RTL) {
flags |= gfx::ShapedTextFlags::TEXT_IS_RTL;
} else {
flags &= ~gfx::ShapedTextFlags::TEXT_IS_RTL;
@ -3962,9 +3987,6 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText(
textToDraw.Truncate();
}
// for now, default to ltr if not in doc
bool isRTL = false;
RefPtr<ComputedStyle> canvasStyle;
if (mCanvasElement && mCanvasElement->IsInComposedDoc()) {
// try to find the closest context
@ -3973,11 +3995,25 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText(
aError = NS_ERROR_FAILURE;
return nullptr;
}
}
isRTL = canvasStyle->StyleVisibility()->mDirection == StyleDirection::Rtl;
} else {
isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) ==
IBMBIDI_TEXTDIRECTION_RTL;
// Get text direction, either from the property or inherited from context.
const ContextState& state = CurrentState();
bool isRTL;
switch (state.textDirection) {
case TextDirection::LTR:
isRTL = false;
break;
case TextDirection::RTL:
isRTL = true;
break;
case TextDirection::INHERIT:
isRTL = canvasStyle
? canvasStyle->StyleVisibility()->mDirection ==
StyleDirection::Rtl
: GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) ==
IBMBIDI_TEXTDIRECTION_RTL;
break;
}
// This is only needed to know if we can know the drawing bounding box easily.
@ -4060,8 +4096,7 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText(
// bounding boxes before rendering anything
aError = nsBidiPresUtils::ProcessText(
textToDraw.get(), textToDraw.Length(),
isRTL ? mozilla::intl::BidiEmbeddingLevel::RTL()
: mozilla::intl::BidiEmbeddingLevel::LTR(),
isRTL ? intl::BidiEmbeddingLevel::RTL() : intl::BidiEmbeddingLevel::LTR(),
presShell->GetPresContext(), processor, nsBidiPresUtils::MODE_MEASURE,
nullptr, 0, &totalWidthCoord, &mBidiEngine);
if (aError.Failed()) {
@ -4073,7 +4108,6 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText(
// offset pt.x based on text align
gfxFloat anchorX;
const ContextState& state = CurrentState();
if (state.textAlign == TextAlign::CENTER) {
anchorX = .5;
} else if (state.textAlign == TextAlign::LEFT ||
@ -4203,8 +4237,7 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText(
aError = nsBidiPresUtils::ProcessText(
textToDraw.get(), textToDraw.Length(),
isRTL ? mozilla::intl::BidiEmbeddingLevel::RTL()
: mozilla::intl::BidiEmbeddingLevel::LTR(),
isRTL ? intl::BidiEmbeddingLevel::RTL() : intl::BidiEmbeddingLevel::LTR(),
presShell->GetPresContext(), processor, nsBidiPresUtils::MODE_DRAW,
nullptr, 0, nullptr, &mBidiEngine);

View File

@ -304,6 +304,8 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
void SetTextAlign(const nsAString& aTextAlign);
void GetTextBaseline(nsAString& aTextBaseline);
void SetTextBaseline(const nsAString& aTextBaseline);
void GetDirection(nsAString& aDirection);
void SetDirection(const nsAString& aDirection);
void ClosePath() override {
EnsureWritablePath();
@ -886,6 +888,8 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
enum class TextDrawOperation : uint8_t { FILL, STROKE, MEASURE };
enum class TextDirection : uint8_t { LTR, RTL, INHERIT };
protected:
gfxFontGroup* GetCurrentFontStyle();
@ -953,6 +957,7 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
nsCString font;
TextAlign textAlign = TextAlign::START;
TextBaseline textBaseline = TextBaseline::ALPHABETIC;
TextDirection textDirection = TextDirection::INHERIT;
nscolor shadowColor = 0;

View File

@ -302,6 +302,7 @@ interface mixin CanvasTextDrawingStyles {
attribute UTF8String font; // (default 10px sans-serif)
attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
attribute DOMString direction; // "ltr", "rtl", "inherit" (default: "inherit")
};
interface mixin CanvasPathMethods {