Bug 835381 - Update libnestegg to 38c83d9d4c0c5c84373aa285bd30094a12d6b6f6. r=kinetik
[gecko.git] / gfx / src / nsFontMetrics.cpp
blobfbbcdabd7ad089ff602ab7724a98914f633323cb
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"
11 #include <algorithm>
13 namespace {
15 class AutoTextRun {
16 public:
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,
22 aRC->ThebesContext(),
23 aMetrics->AppUnitsPerDevPixel(),
24 ComputeFlags(aMetrics));
27 AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
28 const PRUnichar* aString, int32_t aLength)
30 mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
31 aString, aLength,
32 aRC->ThebesContext(),
33 aMetrics->AppUnitsPerDevPixel(),
34 ComputeFlags(aMetrics));
37 gfxTextRun *get() { return mTextRun; }
38 gfxTextRun *operator->() { return mTextRun; }
40 private:
41 static uint32_t ComputeFlags(nsFontMetrics* aMetrics) {
42 uint32_t flags = 0;
43 if (aMetrics->GetTextRunRTL()) {
44 flags |= gfxTextRunFactory::TEXT_IS_RTL;
46 return flags;
49 nsAutoPtr<gfxTextRun> mTextRun;
52 class StubPropertyProvider : public gfxTextRun::PropertyProvider {
53 public:
54 virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
55 bool* aBreakBefore) {
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");
64 return 0;
66 virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
67 Spacing* aSpacing) {
68 NS_ERROR("This shouldn't be called because we never enable spacing");
72 } // anon namespace
74 nsFontMetrics::nsFontMetrics()
75 : mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
79 nsFontMetrics::~nsFontMetrics()
81 if (mDeviceContext)
82 mDeviceContext->FontMetricsDeleted(this);
85 nsresult
86 nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
87 nsDeviceContext *aContext,
88 gfxUserFontSet *aUserFontSet)
90 NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
92 mFont = aFont;
93 mLanguage = aLanguage;
94 mDeviceContext = aContext;
95 mP2A = mDeviceContext->AppUnitsPerDevPixel();
97 gfxFontStyle style(aFont.style,
98 aFont.weight,
99 aFont.stretch,
100 gfxFloat(aFont.size) / mP2A,
101 aLanguage,
102 aFont.sizeAdjust,
103 aFont.systemFont,
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;
114 return NS_OK;
117 void
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();
132 nscoord
133 nsFontMetrics::XHeight()
135 return ROUND_TO_TWIPS(GetMetrics().xHeight);
138 nscoord
139 nsFontMetrics::SuperscriptOffset()
141 return ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
144 nscoord
145 nsFontMetrics::SubscriptOffset()
147 return ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
150 void
151 nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
153 aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
154 aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
157 void
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);
183 nscoord
184 nsFontMetrics::InternalLeading()
186 return ROUND_TO_TWIPS(GetMetrics().internalLeading);
189 nscoord
190 nsFontMetrics::ExternalLeading()
192 return ROUND_TO_TWIPS(GetMetrics().externalLeading);
195 nscoord
196 nsFontMetrics::EmHeight()
198 return ROUND_TO_TWIPS(GetMetrics().emHeight);
201 nscoord
202 nsFontMetrics::EmAscent()
204 return ROUND_TO_TWIPS(GetMetrics().emAscent);
207 nscoord
208 nsFontMetrics::EmDescent()
210 return ROUND_TO_TWIPS(GetMetrics().emDescent);
213 nscoord
214 nsFontMetrics::MaxHeight()
216 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
217 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
220 nscoord
221 nsFontMetrics::MaxAscent()
223 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
226 nscoord
227 nsFontMetrics::MaxDescent()
229 return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
232 nscoord
233 nsFontMetrics::MaxAdvance()
235 return CEIL_TO_TWIPS(GetMetrics().maxAdvance);
238 nscoord
239 nsFontMetrics::AveCharWidth()
241 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
242 return CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
245 nscoord
246 nsFontMetrics::SpaceWidth()
248 return CEIL_TO_TWIPS(GetMetrics().spaceWidth);
251 int32_t
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);
260 nscoord
261 nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
262 nsRenderingContext *aContext)
264 if (aLength == 0)
265 return 0;
267 if (aLength == 1 && aString[0] == ' ')
268 return SpaceWidth();
270 StubPropertyProvider provider;
271 AutoTextRun textRun(this, aContext, aString, aLength);
272 return textRun.get() ?
273 NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
276 nscoord
277 nsFontMetrics::GetWidth(const PRUnichar* aString, uint32_t aLength,
278 nsRenderingContext *aContext)
280 if (aLength == 0)
281 return 0;
283 if (aLength == 1 && aString[0] == ' ')
284 return SpaceWidth();
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.
293 void
294 nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
295 nscoord aX, nscoord aY,
296 nsRenderingContext *aContext)
298 if (aLength == 0)
299 return;
301 StubPropertyProvider provider;
302 AutoTextRun textRun(this, aContext, aString, aLength);
303 if (!textRun.get()) {
304 return;
306 gfxPoint pt(aX, aY);
307 if (mTextRunRTL) {
308 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
310 textRun->Draw(aContext->ThebesContext(), pt, gfxFont::GLYPH_FILL, 0, aLength,
311 &provider, nullptr, nullptr);
314 void
315 nsFontMetrics::DrawString(const PRUnichar* aString, uint32_t aLength,
316 nscoord aX, nscoord aY,
317 nsRenderingContext *aContext,
318 nsRenderingContext *aTextRunConstructionContext)
320 if (aLength == 0)
321 return;
323 StubPropertyProvider provider;
324 AutoTextRun textRun(this, aTextRunConstructionContext, aString, aLength);
325 if (!textRun.get()) {
326 return;
328 gfxPoint pt(aX, aY);
329 if (mTextRunRTL) {
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)
340 if (aLength == 0)
341 return nsBoundingMetrics();
343 StubPropertyProvider provider;
344 AutoTextRun textRun(aMetrics, aContext, aString, aLength);
345 nsBoundingMetrics m;
346 if (textRun.get()) {
347 gfxTextRun::Metrics theMetrics =
348 textRun->MeasureText(0, aLength,
349 aType,
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);
358 return m;
361 nsBoundingMetrics
362 nsFontMetrics::GetBoundingMetrics(const PRUnichar *aString, uint32_t aLength,
363 nsRenderingContext *aContext)
365 return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS);
369 nsBoundingMetrics
370 nsFontMetrics::GetInkBoundsForVisualOverflow(const PRUnichar *aString, uint32_t aLength,
371 nsRenderingContext *aContext)
373 return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::LOOSE_INK_EXTENTS);