1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
23 * Stuart Parmenter <pavlov@pavlov.net>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsThebesFontMetrics.h"
45 #include "gfxTextRunCache.h"
46 #include "gfxPlatform.h"
47 #include "gfxUserFontSet.h"
49 NS_IMPL_ISUPPORTS1(nsThebesFontMetrics
, nsIFontMetrics
)
53 nsThebesFontMetrics::nsThebesFontMetrics()
59 nsThebesFontMetrics::~nsThebesFontMetrics()
66 nsThebesFontMetrics::Init(const nsFont
& aFont
, nsIAtom
* aLangGroup
,
67 nsIDeviceContext
*aContext
,
68 gfxUserFontSet
*aUserFontSet
)
71 mLangGroup
= aLangGroup
;
72 mDeviceContext
= (nsThebesDeviceContext
*)aContext
;
73 mP2A
= mDeviceContext
->AppUnitsPerDevPixel();
74 mIsRightToLeft
= PR_FALSE
;
75 mTextRunRTL
= PR_FALSE
;
77 gfxFloat size
= gfxFloat(aFont
.size
) / mP2A
;
82 mLangGroup
->GetUTF8String(&lg
);
86 mFontStyle
= new gfxFontStyle(aFont
.style
, aFont
.weight
, size
, langGroup
,
87 aFont
.sizeAdjust
, aFont
.systemFont
,
88 aFont
.familyNameQuirks
);
91 gfxPlatform::GetPlatform()->CreateFontGroup(aFont
.name
, mFontStyle
,
98 nsThebesFontMetrics::Destroy()
103 // XXXTODO get rid of this macro
104 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
105 #define CEIL_TO_TWIPS(x) (nscoord)NS_ceil((x) * mP2A)
107 const gfxFont::Metrics
& nsThebesFontMetrics::GetMetrics() const
109 return mFontGroup
->GetFontAt(0)->GetMetrics();
113 nsThebesFontMetrics::GetXHeight(nscoord
& aResult
)
115 aResult
= ROUND_TO_TWIPS(GetMetrics().xHeight
);
120 nsThebesFontMetrics::GetSuperscriptOffset(nscoord
& aResult
)
122 aResult
= ROUND_TO_TWIPS(GetMetrics().superscriptOffset
);
127 nsThebesFontMetrics::GetSubscriptOffset(nscoord
& aResult
)
129 aResult
= ROUND_TO_TWIPS(GetMetrics().subscriptOffset
);
134 nsThebesFontMetrics::GetStrikeout(nscoord
& aOffset
, nscoord
& aSize
)
136 aOffset
= ROUND_TO_TWIPS(GetMetrics().strikeoutOffset
);
137 aSize
= ROUND_TO_TWIPS(GetMetrics().strikeoutSize
);
142 nsThebesFontMetrics::GetUnderline(nscoord
& aOffset
, nscoord
& aSize
)
144 aOffset
= ROUND_TO_TWIPS(mFontGroup
->GetUnderlineOffset());
145 aSize
= ROUND_TO_TWIPS(GetMetrics().underlineSize
);
150 // GetHeight/GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
151 // text-decoration lines drawable area. See bug 421353.
152 // BE CAREFUL for rounding each values. The logic MUST be same as
153 // nsCSSRendering::GetTextDecorationRectInternal's.
155 static gfxFloat
ComputeMaxDescent(const gfxFont::Metrics
& aMetrics
,
156 gfxFontGroup
* aFontGroup
)
158 gfxFloat offset
= NS_floor(-aFontGroup
->GetUnderlineOffset() + 0.5);
159 gfxFloat size
= NS_round(aMetrics
.underlineSize
);
160 gfxFloat minDescent
= NS_floor(offset
+ size
+ 0.5);
161 return PR_MAX(minDescent
, aMetrics
.maxDescent
);
164 static gfxFloat
ComputeMaxAscent(const gfxFont::Metrics
& aMetrics
)
166 return NS_floor(aMetrics
.maxAscent
+ 0.5);
170 nsThebesFontMetrics::GetHeight(nscoord
&aHeight
)
172 aHeight
= CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
173 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup
));
178 nsThebesFontMetrics::GetInternalLeading(nscoord
&aLeading
)
180 aLeading
= ROUND_TO_TWIPS(GetMetrics().internalLeading
);
185 nsThebesFontMetrics::GetExternalLeading(nscoord
&aLeading
)
187 aLeading
= ROUND_TO_TWIPS(GetMetrics().externalLeading
);
192 nsThebesFontMetrics::GetEmHeight(nscoord
&aHeight
)
194 aHeight
= ROUND_TO_TWIPS(GetMetrics().emHeight
);
199 nsThebesFontMetrics::GetEmAscent(nscoord
&aAscent
)
201 aAscent
= ROUND_TO_TWIPS(GetMetrics().emAscent
);
206 nsThebesFontMetrics::GetEmDescent(nscoord
&aDescent
)
208 aDescent
= ROUND_TO_TWIPS(GetMetrics().emDescent
);
213 nsThebesFontMetrics::GetMaxHeight(nscoord
&aHeight
)
215 aHeight
= CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
216 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup
));
221 nsThebesFontMetrics::GetMaxAscent(nscoord
&aAscent
)
223 aAscent
= CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
228 nsThebesFontMetrics::GetMaxDescent(nscoord
&aDescent
)
230 aDescent
= CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup
));
235 nsThebesFontMetrics::GetMaxAdvance(nscoord
&aAdvance
)
237 aAdvance
= CEIL_TO_TWIPS(GetMetrics().maxAdvance
);
242 nsThebesFontMetrics::GetLangGroup(nsIAtom
** aLangGroup
)
244 *aLangGroup
= mLangGroup
;
245 NS_IF_ADDREF(*aLangGroup
);
250 nsThebesFontMetrics::GetFontHandle(nsFontHandle
&aHandle
)
252 return NS_ERROR_NOT_IMPLEMENTED
;
256 nsThebesFontMetrics::GetAveCharWidth(nscoord
& aAveCharWidth
)
258 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
259 aAveCharWidth
= CEIL_TO_TWIPS(GetMetrics().aveCharWidth
);
264 nsThebesFontMetrics::GetSpaceWidth(nscoord
& aSpaceCharWidth
)
266 aSpaceCharWidth
= CEIL_TO_TWIPS(GetMetrics().spaceWidth
);
271 nsThebesFontMetrics::GetMaxStringLength()
273 const gfxFont::Metrics
& m
= GetMetrics();
274 const double x
= 32767.0 / m
.maxAdvance
;
275 PRInt32 len
= (PRInt32
)floor(x
);
276 return PR_MAX(1, len
);
279 class StubPropertyProvider
: public gfxTextRun::PropertyProvider
{
281 virtual void GetHyphenationBreaks(PRUint32 aStart
, PRUint32 aLength
,
282 PRPackedBool
* aBreakBefore
) {
283 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
285 virtual gfxFloat
GetHyphenWidth() {
286 NS_ERROR("This shouldn't be called because we never enable hyphens");
289 virtual void GetSpacing(PRUint32 aStart
, PRUint32 aLength
,
291 NS_ERROR("This shouldn't be called because we never enable spacing");
296 nsThebesFontMetrics::GetWidth(const char* aString
, PRUint32 aLength
, nscoord
& aWidth
,
297 nsThebesRenderingContext
*aContext
)
304 // callers that hit this should not be so stupid
305 if ((aLength
== 1) && (aString
[0] == ' '))
306 return GetSpaceWidth(aWidth
);
308 StubPropertyProvider provider
;
309 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
311 return NS_ERROR_FAILURE
;
313 aWidth
= NSToCoordRound(textRun
->GetAdvanceWidth(0, aLength
, &provider
));
319 nsThebesFontMetrics::GetWidth(const PRUnichar
* aString
, PRUint32 aLength
,
320 nscoord
& aWidth
, PRInt32
*aFontID
,
321 nsThebesRenderingContext
*aContext
)
328 // callers that hit this should not be so stupid
329 if ((aLength
== 1) && (aString
[0] == ' '))
330 return GetSpaceWidth(aWidth
);
332 StubPropertyProvider provider
;
333 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
335 return NS_ERROR_FAILURE
;
337 aWidth
= NSToCoordRound(textRun
->GetAdvanceWidth(0, aLength
, &provider
));
342 // Get the text dimensions for this string
344 nsThebesFontMetrics::GetTextDimensions(const PRUnichar
* aString
,
346 nsTextDimensions
& aDimensions
,
353 nsThebesFontMetrics::GetTextDimensions(const char* aString
,
358 nsTextDimensions
& aDimensions
,
359 PRInt32
& aNumCharsFit
,
360 nsTextDimensions
& aLastWordDimensions
,
366 nsThebesFontMetrics::GetTextDimensions(const PRUnichar
* aString
,
371 nsTextDimensions
& aDimensions
,
372 PRInt32
& aNumCharsFit
,
373 nsTextDimensions
& aLastWordDimensions
,
379 // Draw a string using this font handle on the surface passed in.
381 nsThebesFontMetrics::DrawString(const char *aString
, PRUint32 aLength
,
382 nscoord aX
, nscoord aY
,
383 const nscoord
* aSpacing
,
384 nsThebesRenderingContext
*aContext
)
389 NS_ASSERTION(!aSpacing
, "Spacing not supported here");
390 StubPropertyProvider provider
;
391 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
393 return NS_ERROR_FAILURE
;
396 pt
.x
+= textRun
->GetAdvanceWidth(0, aLength
, &provider
);
398 textRun
->Draw(aContext
->ThebesContext(), pt
, 0, aLength
,
399 nsnull
, &provider
, nsnull
);
404 nsThebesFontMetrics::DrawString(const PRUnichar
* aString
, PRUint32 aLength
,
405 nscoord aX
, nscoord aY
,
407 const nscoord
* aSpacing
,
408 nsThebesRenderingContext
*aContext
)
413 NS_ASSERTION(!aSpacing
, "Spacing not supported here");
414 StubPropertyProvider provider
;
415 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
417 return NS_ERROR_FAILURE
;
420 pt
.x
+= textRun
->GetAdvanceWidth(0, aLength
, &provider
);
422 textRun
->Draw(aContext
->ThebesContext(), pt
, 0, aLength
,
423 nsnull
, &provider
, nsnull
);
430 GetTextRunBoundingMetrics(gfxTextRun
*aTextRun
, PRUint32 aStart
, PRUint32 aLength
,
431 nsThebesRenderingContext
*aContext
,
432 nsBoundingMetrics
&aBoundingMetrics
)
434 StubPropertyProvider provider
;
435 gfxTextRun::Metrics theMetrics
=
436 aTextRun
->MeasureText(aStart
, aLength
, PR_TRUE
, aContext
->ThebesContext(), &provider
);
438 aBoundingMetrics
.leftBearing
= NSToCoordFloor(theMetrics
.mBoundingBox
.X());
439 aBoundingMetrics
.rightBearing
= NSToCoordCeil(theMetrics
.mBoundingBox
.XMost());
440 aBoundingMetrics
.width
= NSToCoordRound(theMetrics
.mAdvanceWidth
);
441 aBoundingMetrics
.ascent
= NSToCoordCeil(- theMetrics
.mBoundingBox
.Y());
442 aBoundingMetrics
.descent
= NSToCoordCeil(theMetrics
.mBoundingBox
.YMost());
446 nsThebesFontMetrics::GetBoundingMetrics(const char *aString
, PRUint32 aLength
,
447 nsThebesRenderingContext
*aContext
,
448 nsBoundingMetrics
&aBoundingMetrics
)
451 aBoundingMetrics
.Clear();
455 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
457 return NS_ERROR_FAILURE
;
459 GetTextRunBoundingMetrics(textRun
.get(), 0, aLength
, aContext
, aBoundingMetrics
);
464 nsThebesFontMetrics::GetBoundingMetrics(const PRUnichar
*aString
, PRUint32 aLength
,
465 nsThebesRenderingContext
*aContext
,
466 nsBoundingMetrics
&aBoundingMetrics
)
469 aBoundingMetrics
.Clear();
473 AutoTextRun
textRun(this, aContext
, aString
, aLength
);
475 return NS_ERROR_FAILURE
;
477 GetTextRunBoundingMetrics(textRun
.get(), 0, aLength
, aContext
, aBoundingMetrics
);
481 #endif /* MOZ_MATHML */
483 // Set the direction of the text rendering
485 nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL
)
487 mIsRightToLeft
= aIsRTL
;
491 // Set the direction of the text rendering
493 nsThebesFontMetrics::GetRightToLeftText()
495 return mIsRightToLeft
;