Bug 574454 - Add window frame css styles. r=dbaron.
[mozilla-central.git] / gfx / src / thebes / nsThebesFontMetrics.cpp
blob208eec818b90bfb93d022fb01ba6749d169799f2
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"
47 #include "gfxUserFontSet.h"
49 NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
51 #include <stdlib.h>
53 nsThebesFontMetrics::nsThebesFontMetrics()
55 mFontStyle = nsnull;
56 mFontGroup = nsnull;
59 nsThebesFontMetrics::~nsThebesFontMetrics()
61 if (mDeviceContext)
62 mDeviceContext->FontMetricsDeleted(this);
63 delete mFontStyle;
64 //delete mFontGroup;
67 NS_IMETHODIMP
68 nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
69 nsIDeviceContext *aContext,
70 gfxUserFontSet *aUserFontSet)
72 mFont = aFont;
73 mLanguage = aLanguage;
74 mDeviceContext = (nsThebesDeviceContext*)aContext;
75 mP2A = mDeviceContext->AppUnitsPerDevPixel();
76 mIsRightToLeft = PR_FALSE;
77 mTextRunRTL = PR_FALSE;
79 gfxFloat size = gfxFloat(aFont.size) / mP2A;
81 PRBool printerFont = mDeviceContext->IsPrinterSurface();
82 mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, aFont.stretch,
83 size, aLanguage,
84 aFont.sizeAdjust, aFont.systemFont,
85 aFont.familyNameQuirks,
86 printerFont,
87 aFont.featureSettings,
88 aFont.languageOverride);
90 mFontGroup =
91 gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle,
92 aUserFontSet);
93 if (mFontGroup->FontListLength() < 1)
94 return NS_ERROR_UNEXPECTED;
96 return NS_OK;
99 NS_IMETHODIMP
100 nsThebesFontMetrics::Destroy()
102 mDeviceContext = nsnull;
103 return NS_OK;
106 // XXXTODO get rid of this macro
107 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
108 #define CEIL_TO_TWIPS(x) (nscoord)NS_ceil((x) * mP2A)
110 const gfxFont::Metrics& nsThebesFontMetrics::GetMetrics() const
112 return mFontGroup->GetFontAt(0)->GetMetrics();
115 NS_IMETHODIMP
116 nsThebesFontMetrics::GetXHeight(nscoord& aResult)
118 aResult = ROUND_TO_TWIPS(GetMetrics().xHeight);
119 return NS_OK;
122 NS_IMETHODIMP
123 nsThebesFontMetrics::GetSuperscriptOffset(nscoord& aResult)
125 aResult = ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
126 return NS_OK;
129 NS_IMETHODIMP
130 nsThebesFontMetrics::GetSubscriptOffset(nscoord& aResult)
132 aResult = ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
133 return NS_OK;
136 NS_IMETHODIMP
137 nsThebesFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
139 aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
140 aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
141 return NS_OK;
144 NS_IMETHODIMP
145 nsThebesFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
147 aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
148 aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
150 return NS_OK;
153 // GetHeight/GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
154 // text-decoration lines drawable area. See bug 421353.
155 // BE CAREFUL for rounding each values. The logic MUST be same as
156 // nsCSSRendering::GetTextDecorationRectInternal's.
158 static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
159 gfxFontGroup* aFontGroup)
161 gfxFloat offset = NS_floor(-aFontGroup->GetUnderlineOffset() + 0.5);
162 gfxFloat size = NS_round(aMetrics.underlineSize);
163 gfxFloat minDescent = NS_floor(offset + size + 0.5);
164 return PR_MAX(minDescent, aMetrics.maxDescent);
167 static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
169 return NS_floor(aMetrics.maxAscent + 0.5);
172 NS_IMETHODIMP
173 nsThebesFontMetrics::GetHeight(nscoord &aHeight)
175 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
176 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
177 return NS_OK;
180 NS_IMETHODIMP
181 nsThebesFontMetrics::GetInternalLeading(nscoord &aLeading)
183 aLeading = ROUND_TO_TWIPS(GetMetrics().internalLeading);
184 return NS_OK;
187 NS_IMETHODIMP
188 nsThebesFontMetrics::GetExternalLeading(nscoord &aLeading)
190 aLeading = ROUND_TO_TWIPS(GetMetrics().externalLeading);
191 return NS_OK;
194 NS_IMETHODIMP
195 nsThebesFontMetrics::GetEmHeight(nscoord &aHeight)
197 aHeight = ROUND_TO_TWIPS(GetMetrics().emHeight);
198 return NS_OK;
201 NS_IMETHODIMP
202 nsThebesFontMetrics::GetEmAscent(nscoord &aAscent)
204 aAscent = ROUND_TO_TWIPS(GetMetrics().emAscent);
205 return NS_OK;
208 NS_IMETHODIMP
209 nsThebesFontMetrics::GetEmDescent(nscoord &aDescent)
211 aDescent = ROUND_TO_TWIPS(GetMetrics().emDescent);
212 return NS_OK;
215 NS_IMETHODIMP
216 nsThebesFontMetrics::GetMaxHeight(nscoord &aHeight)
218 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
219 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
220 return NS_OK;
223 NS_IMETHODIMP
224 nsThebesFontMetrics::GetMaxAscent(nscoord &aAscent)
226 aAscent = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
227 return NS_OK;
230 NS_IMETHODIMP
231 nsThebesFontMetrics::GetMaxDescent(nscoord &aDescent)
233 aDescent = CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
234 return NS_OK;
237 NS_IMETHODIMP
238 nsThebesFontMetrics::GetMaxAdvance(nscoord &aAdvance)
240 aAdvance = CEIL_TO_TWIPS(GetMetrics().maxAdvance);
241 return NS_OK;
244 NS_IMETHODIMP
245 nsThebesFontMetrics::GetLanguage(nsIAtom** aLanguage)
247 *aLanguage = mLanguage;
248 NS_IF_ADDREF(*aLanguage);
249 return NS_OK;
252 NS_IMETHODIMP
253 nsThebesFontMetrics::GetFontHandle(nsFontHandle &aHandle)
255 return NS_ERROR_NOT_IMPLEMENTED;
258 NS_IMETHODIMP
259 nsThebesFontMetrics::GetAveCharWidth(nscoord& aAveCharWidth)
261 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
262 aAveCharWidth = CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
263 return NS_OK;
266 NS_IMETHODIMP
267 nsThebesFontMetrics::GetSpaceWidth(nscoord& aSpaceCharWidth)
269 aSpaceCharWidth = CEIL_TO_TWIPS(GetMetrics().spaceWidth);
270 return NS_OK;
273 PRInt32
274 nsThebesFontMetrics::GetMaxStringLength()
276 const gfxFont::Metrics& m = GetMetrics();
277 const double x = 32767.0 / m.maxAdvance;
278 PRInt32 len = (PRInt32)floor(x);
279 return PR_MAX(1, len);
282 class StubPropertyProvider : public gfxTextRun::PropertyProvider {
283 public:
284 virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
285 PRPackedBool* aBreakBefore) {
286 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
288 virtual gfxFloat GetHyphenWidth() {
289 NS_ERROR("This shouldn't be called because we never enable hyphens");
290 return 0;
292 virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
293 Spacing* aSpacing) {
294 NS_ERROR("This shouldn't be called because we never enable spacing");
298 nsresult
299 nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth,
300 nsThebesRenderingContext *aContext)
302 if (aLength == 0) {
303 aWidth = 0;
304 return NS_OK;
307 // callers that hit this should not be so stupid
308 if ((aLength == 1) && (aString[0] == ' '))
309 return GetSpaceWidth(aWidth);
311 StubPropertyProvider provider;
312 AutoTextRun textRun(this, aContext, aString, aLength);
313 if (!textRun.get())
314 return NS_ERROR_FAILURE;
316 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
318 return NS_OK;
321 nsresult
322 nsThebesFontMetrics::GetWidth(const PRUnichar* aString, PRUint32 aLength,
323 nscoord& aWidth, PRInt32 *aFontID,
324 nsThebesRenderingContext *aContext)
326 if (aLength == 0) {
327 aWidth = 0;
328 return NS_OK;
331 // callers that hit this should not be so stupid
332 if ((aLength == 1) && (aString[0] == ' '))
333 return GetSpaceWidth(aWidth);
335 StubPropertyProvider provider;
336 AutoTextRun textRun(this, aContext, aString, aLength);
337 if (!textRun.get())
338 return NS_ERROR_FAILURE;
340 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
342 return NS_OK;
345 // Get the text dimensions for this string
346 nsresult
347 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
348 PRUint32 aLength,
349 nsTextDimensions& aDimensions,
350 PRInt32* aFontID)
352 return NS_OK;
355 nsresult
356 nsThebesFontMetrics::GetTextDimensions(const char* aString,
357 PRInt32 aLength,
358 PRInt32 aAvailWidth,
359 PRInt32* aBreaks,
360 PRInt32 aNumBreaks,
361 nsTextDimensions& aDimensions,
362 PRInt32& aNumCharsFit,
363 nsTextDimensions& aLastWordDimensions,
364 PRInt32* aFontID)
366 return NS_OK;
368 nsresult
369 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
370 PRInt32 aLength,
371 PRInt32 aAvailWidth,
372 PRInt32* aBreaks,
373 PRInt32 aNumBreaks,
374 nsTextDimensions& aDimensions,
375 PRInt32& aNumCharsFit,
376 nsTextDimensions& aLastWordDimensions,
377 PRInt32* aFontID)
379 return NS_OK;
382 // Draw a string using this font handle on the surface passed in.
383 nsresult
384 nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
385 nscoord aX, nscoord aY,
386 const nscoord* aSpacing,
387 nsThebesRenderingContext *aContext)
389 if (aLength == 0)
390 return NS_OK;
392 NS_ASSERTION(!aSpacing, "Spacing not supported here");
393 StubPropertyProvider provider;
394 AutoTextRun textRun(this, aContext, aString, aLength);
395 if (!textRun.get())
396 return NS_ERROR_FAILURE;
397 gfxPoint pt(aX, aY);
398 if (mTextRunRTL) {
399 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
401 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
402 nsnull, &provider, nsnull);
403 return NS_OK;
406 nsresult
407 nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
408 nscoord aX, nscoord aY,
409 PRInt32 aFontID,
410 const nscoord* aSpacing,
411 nsThebesRenderingContext *aContext)
413 if (aLength == 0)
414 return NS_OK;
416 NS_ASSERTION(!aSpacing, "Spacing not supported here");
417 StubPropertyProvider provider;
418 AutoTextRun textRun(this, aContext, aString, aLength);
419 if (!textRun.get())
420 return NS_ERROR_FAILURE;
421 gfxPoint pt(aX, aY);
422 if (mTextRunRTL) {
423 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
425 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
426 nsnull, &provider, nsnull);
427 return NS_OK;
430 #ifdef MOZ_MATHML
432 static void
433 GetTextRunBoundingMetrics(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength,
434 nsThebesRenderingContext *aContext,
435 nsBoundingMetrics &aBoundingMetrics)
437 StubPropertyProvider provider;
438 gfxTextRun::Metrics theMetrics =
439 aTextRun->MeasureText(aStart, aLength, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
440 aContext->ThebesContext(), &provider);
441 // note that TIGHT_HINTED_OUTLINE_EXTENTS can be expensive (on Windows)
442 // but this is only used for MathML positioning so it's not critical
444 aBoundingMetrics.leftBearing = NSToCoordFloor(theMetrics.mBoundingBox.X());
445 aBoundingMetrics.rightBearing = NSToCoordCeil(theMetrics.mBoundingBox.XMost());
446 aBoundingMetrics.width = NSToCoordRound(theMetrics.mAdvanceWidth);
447 aBoundingMetrics.ascent = NSToCoordCeil(- theMetrics.mBoundingBox.Y());
448 aBoundingMetrics.descent = NSToCoordCeil(theMetrics.mBoundingBox.YMost());
451 nsresult
452 nsThebesFontMetrics::GetBoundingMetrics(const char *aString, PRUint32 aLength,
453 nsThebesRenderingContext *aContext,
454 nsBoundingMetrics &aBoundingMetrics)
456 if (aLength == 0) {
457 aBoundingMetrics.Clear();
458 return NS_OK;
461 AutoTextRun textRun(this, aContext, aString, aLength);
462 if (!textRun.get())
463 return NS_ERROR_FAILURE;
465 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
466 return NS_OK;
469 nsresult
470 nsThebesFontMetrics::GetBoundingMetrics(const PRUnichar *aString, PRUint32 aLength,
471 nsThebesRenderingContext *aContext,
472 nsBoundingMetrics &aBoundingMetrics)
474 if (aLength == 0) {
475 aBoundingMetrics.Clear();
476 return NS_OK;
479 AutoTextRun textRun(this, aContext, aString, aLength);
480 if (!textRun.get())
481 return NS_ERROR_FAILURE;
483 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
484 return NS_OK;
487 #endif /* MOZ_MATHML */
489 // Set the direction of the text rendering
490 nsresult
491 nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL)
493 mIsRightToLeft = aIsRTL;
494 return NS_OK;
497 // Set the direction of the text rendering
498 PRBool
499 nsThebesFontMetrics::GetRightToLeftText()
501 return mIsRightToLeft;
504 /* virtual */ gfxUserFontSet*
505 nsThebesFontMetrics::GetUserFontSet()
507 return mFontGroup->GetUserFontSet();