Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 <math.h> // for floor, ceil
8 #include <algorithm> // for max
9 #include "gfxPlatform.h" // for gfxPlatform
10 #include "gfxPoint.h" // for gfxPoint
11 #include "gfxRect.h" // for gfxRect
12 #include "gfxTypes.h" // for gfxFloat
13 #include "nsBoundingMetrics.h" // for nsBoundingMetrics
14 #include "nsDebug.h" // for NS_ERROR, NS_ABORT_IF_FALSE
15 #include "nsDeviceContext.h" // for nsDeviceContext
16 #include "nsIAtom.h" // for nsIAtom
17 #include "nsMathUtils.h" // for NS_round
18 #include "nsRenderingContext.h" // for nsRenderingContext
19 #include "nsString.h" // for nsString
20 #include "nsStyleConsts.h" // for NS_STYLE_HYPHENS_NONE
22 class gfxUserFontSet;
24 namespace {
26 class AutoTextRun {
27 public:
28 AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
29 const char* aString, int32_t aLength)
30 {
31 mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
32 reinterpret_cast<const uint8_t*>(aString), aLength,
33 aRC->ThebesContext(),
34 aMetrics->AppUnitsPerDevPixel(),
35 ComputeFlags(aMetrics));
36 }
38 AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
39 const char16_t* aString, int32_t aLength)
40 {
41 mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
42 aString, aLength,
43 aRC->ThebesContext(),
44 aMetrics->AppUnitsPerDevPixel(),
45 ComputeFlags(aMetrics));
46 }
48 gfxTextRun *get() { return mTextRun; }
49 gfxTextRun *operator->() { return mTextRun; }
51 private:
52 static uint32_t ComputeFlags(nsFontMetrics* aMetrics) {
53 uint32_t flags = 0;
54 if (aMetrics->GetTextRunRTL()) {
55 flags |= gfxTextRunFactory::TEXT_IS_RTL;
56 }
57 return flags;
58 }
60 nsAutoPtr<gfxTextRun> mTextRun;
61 };
63 class StubPropertyProvider : public gfxTextRun::PropertyProvider {
64 public:
65 virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
66 bool* aBreakBefore) {
67 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
68 }
69 virtual int8_t GetHyphensOption() {
70 NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
71 return NS_STYLE_HYPHENS_NONE;
72 }
73 virtual gfxFloat GetHyphenWidth() {
74 NS_ERROR("This shouldn't be called because we never enable hyphens");
75 return 0;
76 }
77 virtual already_AddRefed<gfxContext> GetContext() {
78 NS_ERROR("This shouldn't be called because we never enable hyphens");
79 return nullptr;
80 }
81 virtual uint32_t GetAppUnitsPerDevUnit() {
82 NS_ERROR("This shouldn't be called because we never enable hyphens");
83 return 60;
84 }
85 virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
86 Spacing* aSpacing) {
87 NS_ERROR("This shouldn't be called because we never enable spacing");
88 }
89 };
91 } // anon namespace
93 nsFontMetrics::nsFontMetrics()
94 : mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
95 {
96 }
98 nsFontMetrics::~nsFontMetrics()
99 {
100 if (mDeviceContext)
101 mDeviceContext->FontMetricsDeleted(this);
102 }
104 nsresult
105 nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
106 nsDeviceContext *aContext,
107 gfxUserFontSet *aUserFontSet,
108 gfxTextPerfMetrics *aTextPerf)
109 {
110 NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
112 mFont = aFont;
113 mLanguage = aLanguage;
114 mDeviceContext = aContext;
115 mP2A = mDeviceContext->AppUnitsPerDevPixel();
117 gfxFontStyle style(aFont.style,
118 aFont.weight,
119 aFont.stretch,
120 gfxFloat(aFont.size) / mP2A,
121 aLanguage,
122 aFont.sizeAdjust,
123 aFont.systemFont,
124 mDeviceContext->IsPrinterSurface(),
125 aFont.languageOverride);
127 aFont.AddFontFeaturesToStyle(&style);
129 mFontGroup = gfxPlatform::GetPlatform()->
130 CreateFontGroup(aFont.name, &style, aUserFontSet);
131 mFontGroup->SetTextPerfMetrics(aTextPerf);
132 if (mFontGroup->FontListLength() < 1)
133 return NS_ERROR_UNEXPECTED;
135 return NS_OK;
136 }
138 void
139 nsFontMetrics::Destroy()
140 {
141 mDeviceContext = nullptr;
142 }
144 // XXXTODO get rid of this macro
145 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
146 #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
148 const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
149 {
150 return mFontGroup->GetFontAt(0)->GetMetrics();
151 }
153 nscoord
154 nsFontMetrics::XHeight()
155 {
156 return ROUND_TO_TWIPS(GetMetrics().xHeight);
157 }
159 nscoord
160 nsFontMetrics::SuperscriptOffset()
161 {
162 return ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
163 }
165 nscoord
166 nsFontMetrics::SubscriptOffset()
167 {
168 return ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
169 }
171 void
172 nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
173 {
174 aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
175 aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
176 }
178 void
179 nsFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
180 {
181 aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
182 aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
183 }
185 // GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
186 // text-decoration lines drawable area. See bug 421353.
187 // BE CAREFUL for rounding each values. The logic MUST be same as
188 // nsCSSRendering::GetTextDecorationRectInternal's.
190 static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
191 gfxFontGroup* aFontGroup)
192 {
193 gfxFloat offset = floor(-aFontGroup->GetUnderlineOffset() + 0.5);
194 gfxFloat size = NS_round(aMetrics.underlineSize);
195 gfxFloat minDescent = floor(offset + size + 0.5);
196 return std::max(minDescent, aMetrics.maxDescent);
197 }
199 static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
200 {
201 return floor(aMetrics.maxAscent + 0.5);
202 }
204 nscoord
205 nsFontMetrics::InternalLeading()
206 {
207 return ROUND_TO_TWIPS(GetMetrics().internalLeading);
208 }
210 nscoord
211 nsFontMetrics::ExternalLeading()
212 {
213 return ROUND_TO_TWIPS(GetMetrics().externalLeading);
214 }
216 nscoord
217 nsFontMetrics::EmHeight()
218 {
219 return ROUND_TO_TWIPS(GetMetrics().emHeight);
220 }
222 nscoord
223 nsFontMetrics::EmAscent()
224 {
225 return ROUND_TO_TWIPS(GetMetrics().emAscent);
226 }
228 nscoord
229 nsFontMetrics::EmDescent()
230 {
231 return ROUND_TO_TWIPS(GetMetrics().emDescent);
232 }
234 nscoord
235 nsFontMetrics::MaxHeight()
236 {
237 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
238 CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
239 }
241 nscoord
242 nsFontMetrics::MaxAscent()
243 {
244 return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
245 }
247 nscoord
248 nsFontMetrics::MaxDescent()
249 {
250 return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
251 }
253 nscoord
254 nsFontMetrics::MaxAdvance()
255 {
256 return CEIL_TO_TWIPS(GetMetrics().maxAdvance);
257 }
259 nscoord
260 nsFontMetrics::AveCharWidth()
261 {
262 // Use CEIL instead of ROUND for consistency with GetMaxAdvance
263 return CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
264 }
266 nscoord
267 nsFontMetrics::SpaceWidth()
268 {
269 return CEIL_TO_TWIPS(GetMetrics().spaceWidth);
270 }
272 int32_t
273 nsFontMetrics::GetMaxStringLength()
274 {
275 const gfxFont::Metrics& m = GetMetrics();
276 const double x = 32767.0 / m.maxAdvance;
277 int32_t len = (int32_t)floor(x);
278 return std::max(1, len);
279 }
281 nscoord
282 nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
283 nsRenderingContext *aContext)
284 {
285 if (aLength == 0)
286 return 0;
288 if (aLength == 1 && aString[0] == ' ')
289 return SpaceWidth();
291 StubPropertyProvider provider;
292 AutoTextRun textRun(this, aContext, aString, aLength);
293 return textRun.get() ?
294 NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
295 }
297 nscoord
298 nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
299 nsRenderingContext *aContext)
300 {
301 if (aLength == 0)
302 return 0;
304 if (aLength == 1 && aString[0] == ' ')
305 return SpaceWidth();
307 StubPropertyProvider provider;
308 AutoTextRun textRun(this, aContext, aString, aLength);
309 return textRun.get() ?
310 NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
311 }
313 // Draw a string using this font handle on the surface passed in.
314 void
315 nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
316 nscoord aX, nscoord aY,
317 nsRenderingContext *aContext)
318 {
319 if (aLength == 0)
320 return;
322 StubPropertyProvider provider;
323 AutoTextRun textRun(this, aContext, aString, aLength);
324 if (!textRun.get()) {
325 return;
326 }
327 gfxPoint pt(aX, aY);
328 if (mTextRunRTL) {
329 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
330 }
331 textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
332 &provider, nullptr, nullptr);
333 }
335 void
336 nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
337 nscoord aX, nscoord aY,
338 nsRenderingContext *aContext,
339 nsRenderingContext *aTextRunConstructionContext)
340 {
341 if (aLength == 0)
342 return;
344 StubPropertyProvider provider;
345 AutoTextRun textRun(this, aTextRunConstructionContext, aString, aLength);
346 if (!textRun.get()) {
347 return;
348 }
349 gfxPoint pt(aX, aY);
350 if (mTextRunRTL) {
351 pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
352 }
353 textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
354 &provider, nullptr, nullptr);
355 }
357 static nsBoundingMetrics
358 GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t *aString, uint32_t aLength,
359 nsRenderingContext *aContext, gfxFont::BoundingBoxType aType)
360 {
361 if (aLength == 0)
362 return nsBoundingMetrics();
364 StubPropertyProvider provider;
365 AutoTextRun textRun(aMetrics, aContext, aString, aLength);
366 nsBoundingMetrics m;
367 if (textRun.get()) {
368 gfxTextRun::Metrics theMetrics =
369 textRun->MeasureText(0, aLength,
370 aType,
371 aContext->ThebesContext(), &provider);
373 m.leftBearing = NSToCoordFloor( theMetrics.mBoundingBox.X());
374 m.rightBearing = NSToCoordCeil( theMetrics.mBoundingBox.XMost());
375 m.ascent = NSToCoordCeil( -theMetrics.mBoundingBox.Y());
376 m.descent = NSToCoordCeil( theMetrics.mBoundingBox.YMost());
377 m.width = NSToCoordRound( theMetrics.mAdvanceWidth);
378 }
379 return m;
380 }
382 nsBoundingMetrics
383 nsFontMetrics::GetBoundingMetrics(const char16_t *aString, uint32_t aLength,
384 nsRenderingContext *aContext)
385 {
386 return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS);
388 }
390 nsBoundingMetrics
391 nsFontMetrics::GetInkBoundsForVisualOverflow(const char16_t *aString, uint32_t aLength,
392 nsRenderingContext *aContext)
393 {
394 return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::LOOSE_INK_EXTENTS);
395 }