gfx/src/nsFontMetrics.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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.

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

mercurial