Bug 426214, automatically sync Firefox's blocklist.xml from AMO (running on egg like...
[mozilla-1.9.git] / gfx / src / thebes / nsThebesFontMetrics.cpp
blob10d6755e5ecf49993b78121debf73443867e4ef2
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
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * mozilla.org.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
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"
40 #include "nsFont.h"
42 #include "nsString.h"
43 #include <stdio.h>
45 #include "gfxTextRunCache.h"
46 #include "gfxPlatform.h"
48 NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
50 #include <stdlib.h>
52 nsThebesFontMetrics::nsThebesFontMetrics()
54 mFontStyle = nsnull;
55 mFontGroup = nsnull;
58 nsThebesFontMetrics::~nsThebesFontMetrics()
60 delete mFontStyle;
61 //delete mFontGroup;
64 NS_IMETHODIMP
65 nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
66 nsIDeviceContext *aContext)
68 mFont = aFont;
69 mLangGroup = aLangGroup;
70 mDeviceContext = (nsThebesDeviceContext*)aContext;
71 mP2A = mDeviceContext->AppUnitsPerDevPixel();
72 mIsRightToLeft = PR_FALSE;
73 mTextRunRTL = PR_FALSE;
75 gfxFloat size = gfxFloat(aFont.size) / mP2A;
77 nsCString langGroup;
78 if (aLangGroup) {
79 const char* lg;
80 mLangGroup->GetUTF8String(&lg);
81 langGroup.Assign(lg);
84 mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, size, langGroup,
85 aFont.sizeAdjust, aFont.systemFont,
86 aFont.familyNameQuirks);
88 mFontGroup =
89 gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle);
91 return NS_OK;
94 NS_IMETHODIMP
95 nsThebesFontMetrics::Destroy()
97 return NS_OK;
100 // XXXTODO get rid of this macro
101 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
102 #define CEIL_TO_TWIPS(x) (nscoord)NS_ceil((x) * mP2A)
104 const gfxFont::Metrics& nsThebesFontMetrics::GetMetrics() const
106 return mFontGroup->GetFontAt(0)->GetMetrics();
109 NS_IMETHODIMP
110 nsThebesFontMetrics::GetXHeight(nscoord& aResult)
112 aResult = ROUND_TO_TWIPS(GetMetrics().xHeight);
113 return NS_OK;
116 NS_IMETHODIMP
117 nsThebesFontMetrics::GetSuperscriptOffset(nscoord& aResult)
119 aResult = ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
120 return NS_OK;
123 NS_IMETHODIMP
124 nsThebesFontMetrics::GetSubscriptOffset(nscoord& aResult)
126 aResult = ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
127 return NS_OK;
130 NS_IMETHODIMP
131 nsThebesFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
133 aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
134 aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
135 return NS_OK;
138 NS_IMETHODIMP
139 nsThebesFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
141 aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
142 aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
144 return NS_OK;
147 // GetHeight/GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
148 // text-decoration lines drawable area. See bug 421353.
149 // BE CAREFUL for rounding each values. The logic MUST be same as
150 // nsCSSRendering::GetTextDecorationRectInternal's.
152 static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
153 gfxFontGroup* aFontGroup)
155 gfxFloat offset = NS_floor(-aFontGroup->GetUnderlineOffset() + 0.5);
156 gfxFloat size = NS_round(aMetrics.underlineSize);
157 gfxFloat minDescent = NS_floor(offset + size + 0.5);
158 return PR_MAX(minDescent, aMetrics.maxDescent);
161 static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
163 return NS_floor(aMetrics.maxAscent + 0.5);
166 NS_IMETHODIMP
167 nsThebesFontMetrics::GetHeight(nscoord &aHeight)
169 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
170 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
171 return NS_OK;
174 NS_IMETHODIMP
175 nsThebesFontMetrics::GetInternalLeading(nscoord &aLeading)
177 aLeading = ROUND_TO_TWIPS(GetMetrics().internalLeading);
178 return NS_OK;
181 NS_IMETHODIMP
182 nsThebesFontMetrics::GetExternalLeading(nscoord &aLeading)
184 aLeading = ROUND_TO_TWIPS(GetMetrics().externalLeading);
185 return NS_OK;
188 NS_IMETHODIMP
189 nsThebesFontMetrics::GetEmHeight(nscoord &aHeight)
191 aHeight = ROUND_TO_TWIPS(GetMetrics().emHeight);
192 return NS_OK;
195 NS_IMETHODIMP
196 nsThebesFontMetrics::GetEmAscent(nscoord &aAscent)
198 aAscent = ROUND_TO_TWIPS(GetMetrics().emAscent);
199 return NS_OK;
202 NS_IMETHODIMP
203 nsThebesFontMetrics::GetEmDescent(nscoord &aDescent)
205 aDescent = ROUND_TO_TWIPS(GetMetrics().emDescent);
206 return NS_OK;
209 NS_IMETHODIMP
210 nsThebesFontMetrics::GetMaxHeight(nscoord &aHeight)
212 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
213 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
214 return NS_OK;
217 NS_IMETHODIMP
218 nsThebesFontMetrics::GetMaxAscent(nscoord &aAscent)
220 aAscent = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
221 return NS_OK;
224 NS_IMETHODIMP
225 nsThebesFontMetrics::GetMaxDescent(nscoord &aDescent)
227 aDescent = CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
228 return NS_OK;
231 NS_IMETHODIMP
232 nsThebesFontMetrics::GetMaxAdvance(nscoord &aAdvance)
234 aAdvance = CEIL_TO_TWIPS(GetMetrics().maxAdvance);
235 return NS_OK;
238 NS_IMETHODIMP
239 nsThebesFontMetrics::GetLangGroup(nsIAtom** aLangGroup)
241 *aLangGroup = mLangGroup;
242 NS_IF_ADDREF(*aLangGroup);
243 return NS_OK;
246 NS_IMETHODIMP
247 nsThebesFontMetrics::GetFontHandle(nsFontHandle &aHandle)
249 return NS_ERROR_NOT_IMPLEMENTED;
252 NS_IMETHODIMP
253 nsThebesFontMetrics::GetAveCharWidth(nscoord& aAveCharWidth)
255 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
256 aAveCharWidth = CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
257 return NS_OK;
260 NS_IMETHODIMP
261 nsThebesFontMetrics::GetSpaceWidth(nscoord& aSpaceCharWidth)
263 aSpaceCharWidth = CEIL_TO_TWIPS(GetMetrics().spaceWidth);
264 return NS_OK;
267 PRInt32
268 nsThebesFontMetrics::GetMaxStringLength()
270 const gfxFont::Metrics& m = GetMetrics();
271 const double x = 32767.0 / m.maxAdvance;
272 PRInt32 len = (PRInt32)floor(x);
273 return PR_MAX(1, len);
276 class StubPropertyProvider : public gfxTextRun::PropertyProvider {
277 public:
278 virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
279 PRPackedBool* aBreakBefore) {
280 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
282 virtual gfxFloat GetHyphenWidth() {
283 NS_ERROR("This shouldn't be called because we never enable hyphens");
284 return 0;
286 virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
287 Spacing* aSpacing) {
288 NS_ERROR("This shouldn't be called because we never enable spacing");
292 nsresult
293 nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth,
294 nsThebesRenderingContext *aContext)
296 if (aLength == 0) {
297 aWidth = 0;
298 return NS_OK;
301 // callers that hit this should not be so stupid
302 if ((aLength == 1) && (aString[0] == ' '))
303 return GetSpaceWidth(aWidth);
305 StubPropertyProvider provider;
306 AutoTextRun textRun(this, aContext, aString, aLength);
307 if (!textRun.get())
308 return NS_ERROR_FAILURE;
310 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
312 return NS_OK;
315 nsresult
316 nsThebesFontMetrics::GetWidth(const PRUnichar* aString, PRUint32 aLength,
317 nscoord& aWidth, PRInt32 *aFontID,
318 nsThebesRenderingContext *aContext)
320 if (aLength == 0) {
321 aWidth = 0;
322 return NS_OK;
325 // callers that hit this should not be so stupid
326 if ((aLength == 1) && (aString[0] == ' '))
327 return GetSpaceWidth(aWidth);
329 StubPropertyProvider provider;
330 AutoTextRun textRun(this, aContext, aString, aLength);
331 if (!textRun.get())
332 return NS_ERROR_FAILURE;
334 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
336 return NS_OK;
339 // Get the text dimensions for this string
340 nsresult
341 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
342 PRUint32 aLength,
343 nsTextDimensions& aDimensions,
344 PRInt32* aFontID)
346 return NS_OK;
349 nsresult
350 nsThebesFontMetrics::GetTextDimensions(const char* aString,
351 PRInt32 aLength,
352 PRInt32 aAvailWidth,
353 PRInt32* aBreaks,
354 PRInt32 aNumBreaks,
355 nsTextDimensions& aDimensions,
356 PRInt32& aNumCharsFit,
357 nsTextDimensions& aLastWordDimensions,
358 PRInt32* aFontID)
360 return NS_OK;
362 nsresult
363 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
364 PRInt32 aLength,
365 PRInt32 aAvailWidth,
366 PRInt32* aBreaks,
367 PRInt32 aNumBreaks,
368 nsTextDimensions& aDimensions,
369 PRInt32& aNumCharsFit,
370 nsTextDimensions& aLastWordDimensions,
371 PRInt32* aFontID)
373 return NS_OK;
376 // Draw a string using this font handle on the surface passed in.
377 nsresult
378 nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
379 nscoord aX, nscoord aY,
380 const nscoord* aSpacing,
381 nsThebesRenderingContext *aContext)
383 if (aLength == 0)
384 return NS_OK;
386 NS_ASSERTION(!aSpacing, "Spacing not supported here");
387 StubPropertyProvider provider;
388 AutoTextRun textRun(this, aContext, aString, aLength);
389 if (!textRun.get())
390 return NS_ERROR_FAILURE;
391 gfxPoint pt(aX, aY);
392 if (mTextRunRTL) {
393 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
395 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
396 nsnull, &provider, nsnull);
397 return NS_OK;
400 nsresult
401 nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
402 nscoord aX, nscoord aY,
403 PRInt32 aFontID,
404 const nscoord* aSpacing,
405 nsThebesRenderingContext *aContext)
407 if (aLength == 0)
408 return NS_OK;
410 NS_ASSERTION(!aSpacing, "Spacing not supported here");
411 StubPropertyProvider provider;
412 AutoTextRun textRun(this, aContext, aString, aLength);
413 if (!textRun.get())
414 return NS_ERROR_FAILURE;
415 gfxPoint pt(aX, aY);
416 if (mTextRunRTL) {
417 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
419 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
420 nsnull, &provider, nsnull);
421 return NS_OK;
424 #ifdef MOZ_MATHML
426 static void
427 GetTextRunBoundingMetrics(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength,
428 nsThebesRenderingContext *aContext,
429 nsBoundingMetrics &aBoundingMetrics)
431 StubPropertyProvider provider;
432 gfxTextRun::Metrics theMetrics =
433 aTextRun->MeasureText(aStart, aLength, PR_TRUE, aContext->ThebesContext(), &provider);
435 aBoundingMetrics.leftBearing = NSToCoordFloor(theMetrics.mBoundingBox.X());
436 aBoundingMetrics.rightBearing = NSToCoordCeil(theMetrics.mBoundingBox.XMost());
437 aBoundingMetrics.width = NSToCoordRound(theMetrics.mAdvanceWidth);
438 aBoundingMetrics.ascent = NSToCoordCeil(- theMetrics.mBoundingBox.Y());
439 aBoundingMetrics.descent = NSToCoordCeil(theMetrics.mBoundingBox.YMost());
442 nsresult
443 nsThebesFontMetrics::GetBoundingMetrics(const char *aString, PRUint32 aLength,
444 nsThebesRenderingContext *aContext,
445 nsBoundingMetrics &aBoundingMetrics)
447 if (aLength == 0) {
448 aBoundingMetrics.Clear();
449 return NS_OK;
452 AutoTextRun textRun(this, aContext, aString, aLength);
453 if (!textRun.get())
454 return NS_ERROR_FAILURE;
456 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
457 return NS_OK;
460 nsresult
461 nsThebesFontMetrics::GetBoundingMetrics(const PRUnichar *aString, PRUint32 aLength,
462 nsThebesRenderingContext *aContext,
463 nsBoundingMetrics &aBoundingMetrics)
465 if (aLength == 0) {
466 aBoundingMetrics.Clear();
467 return NS_OK;
470 AutoTextRun textRun(this, aContext, aString, aLength);
471 if (!textRun.get())
472 return NS_ERROR_FAILURE;
474 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
475 return NS_OK;
478 #endif /* MOZ_MATHML */
480 // Set the direction of the text rendering
481 nsresult
482 nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL)
484 mIsRightToLeft = aIsRTL;
485 return NS_OK;
488 // Set the direction of the text rendering
489 PRBool
490 nsThebesFontMetrics::GetRightToLeftText()
492 return mIsRightToLeft;