Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / gfx / src / thebes / nsThebesFontMetrics.cpp
blobedb74ea95afc8cb8bb93a468e520d96469fb78b4
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 delete mFontStyle;
62 //delete mFontGroup;
65 NS_IMETHODIMP
66 nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
67 nsIDeviceContext *aContext,
68 gfxUserFontSet *aUserFontSet)
70 mFont = aFont;
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;
79 nsCString langGroup;
80 if (aLangGroup) {
81 const char* lg;
82 mLangGroup->GetUTF8String(&lg);
83 langGroup.Assign(lg);
86 mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, size, langGroup,
87 aFont.sizeAdjust, aFont.systemFont,
88 aFont.familyNameQuirks);
90 mFontGroup =
91 gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle,
92 aUserFontSet);
94 return NS_OK;
97 NS_IMETHODIMP
98 nsThebesFontMetrics::Destroy()
100 return NS_OK;
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();
112 NS_IMETHODIMP
113 nsThebesFontMetrics::GetXHeight(nscoord& aResult)
115 aResult = ROUND_TO_TWIPS(GetMetrics().xHeight);
116 return NS_OK;
119 NS_IMETHODIMP
120 nsThebesFontMetrics::GetSuperscriptOffset(nscoord& aResult)
122 aResult = ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
123 return NS_OK;
126 NS_IMETHODIMP
127 nsThebesFontMetrics::GetSubscriptOffset(nscoord& aResult)
129 aResult = ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
130 return NS_OK;
133 NS_IMETHODIMP
134 nsThebesFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
136 aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
137 aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
138 return NS_OK;
141 NS_IMETHODIMP
142 nsThebesFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
144 aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
145 aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
147 return NS_OK;
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);
169 NS_IMETHODIMP
170 nsThebesFontMetrics::GetHeight(nscoord &aHeight)
172 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
173 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
174 return NS_OK;
177 NS_IMETHODIMP
178 nsThebesFontMetrics::GetInternalLeading(nscoord &aLeading)
180 aLeading = ROUND_TO_TWIPS(GetMetrics().internalLeading);
181 return NS_OK;
184 NS_IMETHODIMP
185 nsThebesFontMetrics::GetExternalLeading(nscoord &aLeading)
187 aLeading = ROUND_TO_TWIPS(GetMetrics().externalLeading);
188 return NS_OK;
191 NS_IMETHODIMP
192 nsThebesFontMetrics::GetEmHeight(nscoord &aHeight)
194 aHeight = ROUND_TO_TWIPS(GetMetrics().emHeight);
195 return NS_OK;
198 NS_IMETHODIMP
199 nsThebesFontMetrics::GetEmAscent(nscoord &aAscent)
201 aAscent = ROUND_TO_TWIPS(GetMetrics().emAscent);
202 return NS_OK;
205 NS_IMETHODIMP
206 nsThebesFontMetrics::GetEmDescent(nscoord &aDescent)
208 aDescent = ROUND_TO_TWIPS(GetMetrics().emDescent);
209 return NS_OK;
212 NS_IMETHODIMP
213 nsThebesFontMetrics::GetMaxHeight(nscoord &aHeight)
215 aHeight = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
216 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
217 return NS_OK;
220 NS_IMETHODIMP
221 nsThebesFontMetrics::GetMaxAscent(nscoord &aAscent)
223 aAscent = CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
224 return NS_OK;
227 NS_IMETHODIMP
228 nsThebesFontMetrics::GetMaxDescent(nscoord &aDescent)
230 aDescent = CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
231 return NS_OK;
234 NS_IMETHODIMP
235 nsThebesFontMetrics::GetMaxAdvance(nscoord &aAdvance)
237 aAdvance = CEIL_TO_TWIPS(GetMetrics().maxAdvance);
238 return NS_OK;
241 NS_IMETHODIMP
242 nsThebesFontMetrics::GetLangGroup(nsIAtom** aLangGroup)
244 *aLangGroup = mLangGroup;
245 NS_IF_ADDREF(*aLangGroup);
246 return NS_OK;
249 NS_IMETHODIMP
250 nsThebesFontMetrics::GetFontHandle(nsFontHandle &aHandle)
252 return NS_ERROR_NOT_IMPLEMENTED;
255 NS_IMETHODIMP
256 nsThebesFontMetrics::GetAveCharWidth(nscoord& aAveCharWidth)
258 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
259 aAveCharWidth = CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
260 return NS_OK;
263 NS_IMETHODIMP
264 nsThebesFontMetrics::GetSpaceWidth(nscoord& aSpaceCharWidth)
266 aSpaceCharWidth = CEIL_TO_TWIPS(GetMetrics().spaceWidth);
267 return NS_OK;
270 PRInt32
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 {
280 public:
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");
287 return 0;
289 virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
290 Spacing* aSpacing) {
291 NS_ERROR("This shouldn't be called because we never enable spacing");
295 nsresult
296 nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth,
297 nsThebesRenderingContext *aContext)
299 if (aLength == 0) {
300 aWidth = 0;
301 return NS_OK;
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);
310 if (!textRun.get())
311 return NS_ERROR_FAILURE;
313 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
315 return NS_OK;
318 nsresult
319 nsThebesFontMetrics::GetWidth(const PRUnichar* aString, PRUint32 aLength,
320 nscoord& aWidth, PRInt32 *aFontID,
321 nsThebesRenderingContext *aContext)
323 if (aLength == 0) {
324 aWidth = 0;
325 return NS_OK;
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);
334 if (!textRun.get())
335 return NS_ERROR_FAILURE;
337 aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
339 return NS_OK;
342 // Get the text dimensions for this string
343 nsresult
344 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
345 PRUint32 aLength,
346 nsTextDimensions& aDimensions,
347 PRInt32* aFontID)
349 return NS_OK;
352 nsresult
353 nsThebesFontMetrics::GetTextDimensions(const char* aString,
354 PRInt32 aLength,
355 PRInt32 aAvailWidth,
356 PRInt32* aBreaks,
357 PRInt32 aNumBreaks,
358 nsTextDimensions& aDimensions,
359 PRInt32& aNumCharsFit,
360 nsTextDimensions& aLastWordDimensions,
361 PRInt32* aFontID)
363 return NS_OK;
365 nsresult
366 nsThebesFontMetrics::GetTextDimensions(const PRUnichar* aString,
367 PRInt32 aLength,
368 PRInt32 aAvailWidth,
369 PRInt32* aBreaks,
370 PRInt32 aNumBreaks,
371 nsTextDimensions& aDimensions,
372 PRInt32& aNumCharsFit,
373 nsTextDimensions& aLastWordDimensions,
374 PRInt32* aFontID)
376 return NS_OK;
379 // Draw a string using this font handle on the surface passed in.
380 nsresult
381 nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
382 nscoord aX, nscoord aY,
383 const nscoord* aSpacing,
384 nsThebesRenderingContext *aContext)
386 if (aLength == 0)
387 return NS_OK;
389 NS_ASSERTION(!aSpacing, "Spacing not supported here");
390 StubPropertyProvider provider;
391 AutoTextRun textRun(this, aContext, aString, aLength);
392 if (!textRun.get())
393 return NS_ERROR_FAILURE;
394 gfxPoint pt(aX, aY);
395 if (mTextRunRTL) {
396 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
398 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
399 nsnull, &provider, nsnull);
400 return NS_OK;
403 nsresult
404 nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
405 nscoord aX, nscoord aY,
406 PRInt32 aFontID,
407 const nscoord* aSpacing,
408 nsThebesRenderingContext *aContext)
410 if (aLength == 0)
411 return NS_OK;
413 NS_ASSERTION(!aSpacing, "Spacing not supported here");
414 StubPropertyProvider provider;
415 AutoTextRun textRun(this, aContext, aString, aLength);
416 if (!textRun.get())
417 return NS_ERROR_FAILURE;
418 gfxPoint pt(aX, aY);
419 if (mTextRunRTL) {
420 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
422 textRun->Draw(aContext->ThebesContext(), pt, 0, aLength,
423 nsnull, &provider, nsnull);
424 return NS_OK;
427 #ifdef MOZ_MATHML
429 static void
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());
445 nsresult
446 nsThebesFontMetrics::GetBoundingMetrics(const char *aString, PRUint32 aLength,
447 nsThebesRenderingContext *aContext,
448 nsBoundingMetrics &aBoundingMetrics)
450 if (aLength == 0) {
451 aBoundingMetrics.Clear();
452 return NS_OK;
455 AutoTextRun textRun(this, aContext, aString, aLength);
456 if (!textRun.get())
457 return NS_ERROR_FAILURE;
459 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
460 return NS_OK;
463 nsresult
464 nsThebesFontMetrics::GetBoundingMetrics(const PRUnichar *aString, PRUint32 aLength,
465 nsThebesRenderingContext *aContext,
466 nsBoundingMetrics &aBoundingMetrics)
468 if (aLength == 0) {
469 aBoundingMetrics.Clear();
470 return NS_OK;
473 AutoTextRun textRun(this, aContext, aString, aLength);
474 if (!textRun.get())
475 return NS_ERROR_FAILURE;
477 GetTextRunBoundingMetrics(textRun.get(), 0, aLength, aContext, aBoundingMetrics);
478 return NS_OK;
481 #endif /* MOZ_MATHML */
483 // Set the direction of the text rendering
484 nsresult
485 nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL)
487 mIsRightToLeft = aIsRTL;
488 return NS_OK;
491 // Set the direction of the text rendering
492 PRBool
493 nsThebesFontMetrics::GetRightToLeftText()
495 return mIsRightToLeft;