diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 29f7722c4ab4..4941dc72f06f 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3149,6 +3149,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess gfxPoint point = mPt; bool rtl = mTextRun->IsRightToLeft(); bool verticalRun = mTextRun->IsVertical(); + bool centerBaseline = mTextRun->UseCenterBaseline(); gfxFloat& inlineCoord = verticalRun ? point.y : point.x; inlineCoord += xOffset; @@ -3217,20 +3218,27 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess if (runs[c].mOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT) { sidewaysRestore.Init(mCtx->mTarget); - // TODO: The baseline adjustment here is kinda ad-hoc; eventually - // perhaps we should check for horizontal and vertical baseline data - // in the font, and adjust accordingly. - // (The same will be true for HTML text layout.) const gfxFont::Metrics& metrics = mTextRun->GetFontGroup()-> GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); - mCtx->mTarget->SetTransform(mCtx->mTarget->GetTransform().Copy(). + + gfx::Matrix mat = mCtx->mTarget->GetTransform().Copy(). PreTranslate(baselineOrigin). // translate origin for rotation PreRotate(gfx::Float(M_PI / 2.0)). // turn 90deg clockwise - PreTranslate(-baselineOrigin). // undo the translation - PreTranslate(Point(0, (metrics.emAscent - metrics.emDescent) / 2))); - // and offset the (alphabetic) baseline of the + PreTranslate(-baselineOrigin); // undo the translation + + if (centerBaseline) { + // TODO: The baseline adjustment here is kinda ad hoc; eventually + // perhaps we should check for horizontal and vertical baseline data + // in the font, and adjust accordingly. + // (The same will be true for HTML text layout.) + float offset = (metrics.emAscent - metrics.emDescent) / 2; + mat = mat.PreTranslate(Point(0, offset)); + // offset the (alphabetic) baseline of the // horizontally-shaped text from the (centered) // default baseline used for vertical + } + + mCtx->mTarget->SetTransform(mat); } RefPtr renderingOptions = font->GetGlyphRenderingOptions(); @@ -3522,39 +3530,45 @@ CanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText, processor.mPt.x -= anchorX * totalWidth; - // offset pt.y based on text baseline + // offset pt.y (or pt.x, for vertical text) based on text baseline processor.mFontgrp->UpdateUserFonts(); // ensure user font generation is current const gfxFont::Metrics& fontMetrics = - processor.mFontgrp->GetFirstValidFont()->GetMetrics( - ((processor.mTextRunFlags & gfxTextRunFactory::TEXT_ORIENT_MASK) == - gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL) - ? gfxFont::eHorizontal : gfxFont::eVertical); + processor.mFontgrp->GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal); - gfxFloat anchorY; + gfxFloat baselineAnchor; switch (state.textBaseline) { case TextBaseline::HANGING: // fall through; best we can do with the information available case TextBaseline::TOP: - anchorY = fontMetrics.emAscent; + baselineAnchor = fontMetrics.emAscent; break; case TextBaseline::MIDDLE: - anchorY = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f; + baselineAnchor = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f; break; case TextBaseline::IDEOGRAPHIC: // fall through; best we can do with the information available case TextBaseline::ALPHABETIC: - anchorY = 0; + baselineAnchor = 0; break; case TextBaseline::BOTTOM: - anchorY = -fontMetrics.emDescent; + baselineAnchor = -fontMetrics.emDescent; break; default: MOZ_CRASH("unexpected TextBaseline"); } - processor.mPt.y += anchorY; + if (processor.mTextRun->IsVertical()) { + if (processor.mTextRun->UseCenterBaseline()) { + // Adjust to account for mTextRun being shaped using center baseline + // rather than alphabetic. + baselineAnchor -= (fontMetrics.emAscent - fontMetrics.emDescent) * .5f; + } + processor.mPt.x -= baselineAnchor; + } else { + processor.mPt.y += baselineAnchor; + } // correct bounding box to get it to be the correct size/position processor.mBoundingBox.width = totalWidth; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 909dbc8ec0d8..f176a4a985e0 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -945,6 +945,12 @@ public: gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL; } + bool UseCenterBaseline() const { + uint32_t orient = GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK; + return orient == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED || + orient == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT; + } + bool IsRightToLeft() const { return (GetFlags() & gfxTextRunFactory::TEXT_IS_RTL) != 0; }