Bug 1111944 - part 1 - Make nsLayoutUtils::DrawString (and the nsFontMetrics methods it calls) handle vertical text. r=smontagu

This commit is contained in:
Jonathan Kew 2015-01-06 20:56:03 +00:00
parent 1403418448
commit 0691189ac6
4 changed files with 91 additions and 18 deletions

View File

@ -57,6 +57,19 @@ private:
if (aMetrics->GetTextRunRTL()) {
flags |= gfxTextRunFactory::TEXT_IS_RTL;
}
if (aMetrics->GetVertical()) {
switch (aMetrics->GetTextOrientation()) {
case NS_STYLE_TEXT_ORIENTATION_MIXED:
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED;
break;
case NS_STYLE_TEXT_ORIENTATION_UPRIGHT:
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
break;
case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_RIGHT:
flags |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
break;
}
}
return flags;
}
@ -95,6 +108,7 @@ public:
nsFontMetrics::nsFontMetrics()
: mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
, mVertical(false), mTextOrientation(0)
{
}
@ -151,9 +165,10 @@ nsFontMetrics::Destroy()
#define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
#define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
const gfxFont::Metrics&
nsFontMetrics::GetMetrics(gfxFont::Orientation aOrientation) const
{
return mFontGroup->GetFirstValidFont()->GetMetrics(mOrientation);
return mFontGroup->GetFirstValidFont()->GetMetrics(aOrientation);
}
nscoord
@ -274,7 +289,14 @@ nsFontMetrics::AveCharWidth()
nscoord
nsFontMetrics::SpaceWidth()
{
return CEIL_TO_TWIPS(GetMetrics().spaceWidth);
// For vertical text with mixed or sideways orientation, we want the
// width of a horizontal space (even if we're using vertical line-spacing
// metrics, as with "writing-mode:vertical-*;text-orientation:mixed").
return CEIL_TO_TWIPS(
GetMetrics(mVertical &&
mTextOrientation == NS_STYLE_TEXT_ORIENTATION_UPRIGHT
? gfxFont::eVertical
: gfxFont::eHorizontal).spaceWidth);
}
int32_t
@ -334,7 +356,11 @@ nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
}
gfxPoint pt(aX, aY);
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
if (mVertical) {
pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
} else {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
}
textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
&provider, nullptr, nullptr);
@ -356,7 +382,11 @@ nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
}
gfxPoint pt(aX, aY);
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
if (mVertical) {
pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
} else {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
}
textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
&provider, nullptr, nullptr);

View File

@ -169,17 +169,17 @@ public:
* Returns the font associated with these metrics. The return value
* is only defined after Init() has been called.
*/
const nsFont &Font() { return mFont; }
const nsFont &Font() const { return mFont; }
/**
* Returns the language associated with these metrics
*/
nsIAtom* Language() { return mLanguage; }
nsIAtom* Language() const { return mLanguage; }
/**
* Returns the orientation (horizontal/vertical) of these metrics.
*/
gfxFont::Orientation Orientation() { return mOrientation; }
gfxFont::Orientation Orientation() const { return mOrientation; }
int32_t GetMaxStringLength();
@ -211,26 +211,53 @@ public:
nsRenderingContext *aContext);
void SetTextRunRTL(bool aIsRTL) { mTextRunRTL = aIsRTL; }
bool GetTextRunRTL() { return mTextRunRTL; }
bool GetTextRunRTL() const { return mTextRunRTL; }
gfxFontGroup* GetThebesFontGroup() { return mFontGroup; }
gfxUserFontSet* GetUserFontSet() { return mFontGroup->GetUserFontSet(); }
void SetVertical(bool aVertical) { mVertical = aVertical; }
bool GetVertical() const { return mVertical; }
int32_t AppUnitsPerDevPixel() { return mP2A; }
void SetTextOrientation(uint8_t aTextOrientation)
{
mTextOrientation = aTextOrientation;
}
uint8_t GetTextOrientation() const { return mTextOrientation; }
gfxFontGroup* GetThebesFontGroup() const { return mFontGroup; }
gfxUserFontSet* GetUserFontSet() const
{
return mFontGroup->GetUserFontSet();
}
int32_t AppUnitsPerDevPixel() const { return mP2A; }
private:
// Private destructor, to discourage deletion outside of Release():
~nsFontMetrics();
const gfxFont::Metrics& GetMetrics() const;
const gfxFont::Metrics& GetMetrics() const {
return GetMetrics(mOrientation);
}
const gfxFont::Metrics&
GetMetrics(const gfxFont::Orientation aFontOrientation) const;
nsFont mFont;
nsRefPtr<gfxFontGroup> mFontGroup;
nsCOMPtr<nsIAtom> mLanguage;
nsDeviceContext *mDeviceContext;
int32_t mP2A;
bool mTextRunRTL;
// The font orientation (horizontal or vertical) for which these metrics
// have been initialized. This determines which line metrics (ascent and
// descent) they will return.
gfxFont::Orientation mOrientation;
// These fields may be set by clients to control the behavior of methods
// like GetWidth and DrawString according to the writing mode, direction
// and text-orientation desired.
bool mTextRunRTL;
bool mVertical;
uint8_t mTextOrientation;
};
#endif /* NSFONTMETRICS__H__ */

View File

@ -2090,10 +2090,16 @@ public:
*mTextRunConstructionContext);
}
virtual void DrawText(nscoord aXOffset,
virtual void DrawText(nscoord aIOffset,
nscoord) MOZ_OVERRIDE
{
mFontMetrics->DrawString(mText, mLength, mPt.x + aXOffset, mPt.y,
nsPoint pt(mPt);
if (mFontMetrics->GetVertical()) {
pt.y += aIOffset;
} else {
pt.x += aIOffset;
}
mFontMetrics->DrawString(mText, mLength, pt.x, pt.y,
mCtx, mTextRunConstructionContext);
}

View File

@ -5115,6 +5115,8 @@ nsLayoutUtils::AppUnitWidthOfStringBidi(const char16_t* aString,
aFontMetrics);
}
aFontMetrics.SetTextRunRTL(false);
aFontMetrics.SetVertical(aFrame->GetWritingMode().IsVertical());
aFontMetrics.SetTextOrientation(aFrame->StyleVisibility()->mTextOrientation);
return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
aContext);
}
@ -5156,11 +5158,19 @@ nsLayoutUtils::DrawString(const nsIFrame* aFrame,
nsStyleContext* aStyleContext)
{
nsresult rv = NS_ERROR_FAILURE;
// If caller didn't pass a style context, use the frame's.
if (!aStyleContext) {
aStyleContext = aFrame->StyleContext();
}
aFontMetrics.SetVertical(WritingMode(aStyleContext).IsVertical());
aFontMetrics.SetTextOrientation(
aStyleContext->StyleVisibility()->mTextOrientation);
nsPresContext* presContext = aFrame->PresContext();
if (presContext->BidiEnabled()) {
nsBidiLevel level =
nsBidiPresUtils::BidiLevelFromStyle(aStyleContext ?
aStyleContext : aFrame->StyleContext());
nsBidiPresUtils::BidiLevelFromStyle(aStyleContext);
rv = nsBidiPresUtils::RenderText(aString, aLength, level,
presContext, *aContext, *aContext,
aFontMetrics,