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.

     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 }

mercurial