1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsFontMetrics.h"
7 #include "nsBoundingMetrics.h"
8 #include "nsRenderingContext.h"
9 #include "nsDeviceContext.h"
10 #include "nsStyleConsts.h"
17 AutoTextRun(nsFontMetrics
* aMetrics
, nsRenderingContext
* aRC
,
18 const char* aString
, int32_t aLength
)
20 mTextRun
= aMetrics
->GetThebesFontGroup()->MakeTextRun(
21 reinterpret_cast<const uint8_t*>(aString
), aLength
,
23 aMetrics
->AppUnitsPerDevPixel(),
24 ComputeFlags(aMetrics
));
27 AutoTextRun(nsFontMetrics
* aMetrics
, nsRenderingContext
* aRC
,
28 const PRUnichar
* aString
, int32_t aLength
)
30 mTextRun
= aMetrics
->GetThebesFontGroup()->MakeTextRun(
33 aMetrics
->AppUnitsPerDevPixel(),
34 ComputeFlags(aMetrics
));
37 gfxTextRun
*get() { return mTextRun
; }
38 gfxTextRun
*operator->() { return mTextRun
; }
41 static uint32_t ComputeFlags(nsFontMetrics
* aMetrics
) {
43 if (aMetrics
->GetTextRunRTL()) {
44 flags
|= gfxTextRunFactory::TEXT_IS_RTL
;
49 nsAutoPtr
<gfxTextRun
> mTextRun
;
52 class StubPropertyProvider
: public gfxTextRun::PropertyProvider
{
54 virtual void GetHyphenationBreaks(uint32_t aStart
, uint32_t aLength
,
56 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
58 virtual int8_t GetHyphensOption() {
59 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
60 return NS_STYLE_HYPHENS_NONE
;
62 virtual gfxFloat
GetHyphenWidth() {
63 NS_ERROR("This shouldn't be called because we never enable hyphens");
66 virtual void GetSpacing(uint32_t aStart
, uint32_t aLength
,
68 NS_ERROR("This shouldn't be called because we never enable spacing");
74 nsFontMetrics::nsFontMetrics()
75 : mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
79 nsFontMetrics::~nsFontMetrics()
82 mDeviceContext
->FontMetricsDeleted(this);
86 nsFontMetrics::Init(const nsFont
& aFont
, nsIAtom
* aLanguage
,
87 nsDeviceContext
*aContext
,
88 gfxUserFontSet
*aUserFontSet
)
90 NS_ABORT_IF_FALSE(mP2A
== 0, "already initialized");
93 mLanguage
= aLanguage
;
94 mDeviceContext
= aContext
;
95 mP2A
= mDeviceContext
->AppUnitsPerDevPixel();
97 gfxFontStyle
style(aFont
.style
,
100 gfxFloat(aFont
.size
) / mP2A
,
104 mDeviceContext
->IsPrinterSurface(),
105 aFont
.languageOverride
);
107 aFont
.AddFontFeaturesToStyle(&style
);
109 mFontGroup
= gfxPlatform::GetPlatform()->
110 CreateFontGroup(aFont
.name
, &style
, aUserFontSet
);
111 if (mFontGroup
->FontListLength() < 1)
112 return NS_ERROR_UNEXPECTED
;
118 nsFontMetrics::Destroy()
120 mDeviceContext
= nullptr;
123 // XXXTODO get rid of this macro
124 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
125 #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
127 const gfxFont::Metrics
& nsFontMetrics::GetMetrics() const
129 return mFontGroup
->GetFontAt(0)->GetMetrics();
133 nsFontMetrics::XHeight()
135 return ROUND_TO_TWIPS(GetMetrics().xHeight
);
139 nsFontMetrics::SuperscriptOffset()
141 return ROUND_TO_TWIPS(GetMetrics().superscriptOffset
);
145 nsFontMetrics::SubscriptOffset()
147 return ROUND_TO_TWIPS(GetMetrics().subscriptOffset
);
151 nsFontMetrics::GetStrikeout(nscoord
& aOffset
, nscoord
& aSize
)
153 aOffset
= ROUND_TO_TWIPS(GetMetrics().strikeoutOffset
);
154 aSize
= ROUND_TO_TWIPS(GetMetrics().strikeoutSize
);
158 nsFontMetrics::GetUnderline(nscoord
& aOffset
, nscoord
& aSize
)
160 aOffset
= ROUND_TO_TWIPS(mFontGroup
->GetUnderlineOffset());
161 aSize
= ROUND_TO_TWIPS(GetMetrics().underlineSize
);
164 // GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
165 // text-decoration lines drawable area. See bug 421353.
166 // BE CAREFUL for rounding each values. The logic MUST be same as
167 // nsCSSRendering::GetTextDecorationRectInternal's.
169 static gfxFloat
ComputeMaxDescent(const gfxFont::Metrics
& aMetrics
,
170 gfxFontGroup
* aFontGroup
)
172 gfxFloat offset
= floor(-aFontGroup
->GetUnderlineOffset() + 0.5);
173 gfxFloat size
= NS_round(aMetrics
.underlineSize
);
174 gfxFloat minDescent
= floor(offset
+ size
+ 0.5);
175 return std::max(minDescent
, aMetrics
.maxDescent
);
178 static gfxFloat
ComputeMaxAscent(const gfxFont::Metrics
& aMetrics
)
180 return floor(aMetrics
.maxAscent
+ 0.5);
184 nsFontMetrics::InternalLeading()
186 return ROUND_TO_TWIPS(GetMetrics().internalLeading
);
190 nsFontMetrics::ExternalLeading()
192 return ROUND_TO_TWIPS(GetMetrics().externalLeading
);
196 nsFontMetrics::EmHeight()
198 return ROUND_TO_TWIPS(GetMetrics().emHeight
);
202 nsFontMetrics::EmAscent()
204 return ROUND_TO_TWIPS(GetMetrics().emAscent
);
208 nsFontMetrics::EmDescent()
210 return ROUND_TO_TWIPS(GetMetrics().emDescent
);
214 nsFontMetrics::MaxHeight()
216 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
217 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup
));
221 nsFontMetrics::MaxAscent()
223 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
227 nsFontMetrics::MaxDescent()
229 return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup
));
233 nsFontMetrics::MaxAdvance()
235 return CEIL_TO_TWIPS(GetMetrics().maxAdvance
);
239 nsFontMetrics::AveCharWidth()
241 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
242 return CEIL_TO_TWIPS(GetMetrics().aveCharWidth
);
246 nsFontMetrics::SpaceWidth()
248 return CEIL_TO_TWIPS(GetMetrics().spaceWidth
);
252 nsFontMetrics::GetMaxStringLength()
254 const gfxFont::Metrics
& m
= GetMetrics();
255 const double x
= 32767.0 / m
.maxAdvance
;
256 int32_t len
= (int32_t)floor(x
);
257 return std::max(1, len
);
261 nsFontMetrics::GetWidth(const char* aString
, uint32_t aLength
,
262 nsRenderingContext
*aContext
)
267 if (aLength
== 1 && aString
[0] == ' ')
270 StubPropertyProvider provider
;
271 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
272 return textRun
.get() ?
273 NSToCoordRound(textRun
->GetAdvanceWidth(0, aLength
, &provider
)) : 0;
277 nsFontMetrics::GetWidth(const PRUnichar
* aString
, uint32_t aLength
,
278 nsRenderingContext
*aContext
)
283 if (aLength
== 1 && aString
[0] == ' ')
286 StubPropertyProvider provider
;
287 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
288 return textRun
.get() ?
289 NSToCoordRound(textRun
->GetAdvanceWidth(0, aLength
, &provider
)) : 0;
292 // Draw a string using this font handle on the surface passed in.
294 nsFontMetrics::DrawString(const char *aString
, uint32_t aLength
,
295 nscoord aX
, nscoord aY
,
296 nsRenderingContext
*aContext
)
301 StubPropertyProvider provider
;
302 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
303 if (!textRun
.get()) {
308 pt
.x
+= textRun
->GetAdvanceWidth(0, aLength
, &provider
);
310 textRun
->Draw(aContext
->ThebesContext(), pt
, gfxFont::GLYPH_FILL
, 0, aLength
,
311 &provider
, nullptr, nullptr);
315 nsFontMetrics::DrawString(const PRUnichar
* aString
, uint32_t aLength
,
316 nscoord aX
, nscoord aY
,
317 nsRenderingContext
*aContext
,
318 nsRenderingContext
*aTextRunConstructionContext
)
323 StubPropertyProvider provider
;
324 AutoTextRun
textRun(this, aTextRunConstructionContext
, aString
, aLength
);
325 if (!textRun
.get()) {
330 pt
.x
+= textRun
->GetAdvanceWidth(0, aLength
, &provider
);
332 textRun
->Draw(aContext
->ThebesContext(), pt
, gfxFont::GLYPH_FILL
, 0, aLength
,
333 &provider
, nullptr, nullptr);
336 static nsBoundingMetrics
337 GetTextBoundingMetrics(nsFontMetrics
* aMetrics
, const PRUnichar
*aString
, uint32_t aLength
,
338 nsRenderingContext
*aContext
, gfxFont::BoundingBoxType aType
)
341 return nsBoundingMetrics();
343 StubPropertyProvider provider
;
344 AutoTextRun
textRun(aMetrics
, aContext
, aString
, aLength
);
347 gfxTextRun::Metrics theMetrics
=
348 textRun
->MeasureText(0, aLength
,
350 aContext
->ThebesContext(), &provider
);
352 m
.leftBearing
= NSToCoordFloor( theMetrics
.mBoundingBox
.X());
353 m
.rightBearing
= NSToCoordCeil( theMetrics
.mBoundingBox
.XMost());
354 m
.ascent
= NSToCoordCeil( -theMetrics
.mBoundingBox
.Y());
355 m
.descent
= NSToCoordCeil( theMetrics
.mBoundingBox
.YMost());
356 m
.width
= NSToCoordRound( theMetrics
.mAdvanceWidth
);
362 nsFontMetrics::GetBoundingMetrics(const PRUnichar
*aString
, uint32_t aLength
,
363 nsRenderingContext
*aContext
)
365 return GetTextBoundingMetrics(this, aString
, aLength
, aContext
, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS
);
370 nsFontMetrics::GetInkBoundsForVisualOverflow(const PRUnichar
*aString
, uint32_t aLength
,
371 nsRenderingContext
*aContext
)
373 return GetTextBoundingMetrics(this, aString
, aLength
, aContext
, gfxFont::LOOSE_INK_EXTENTS
);