LCOV - code coverage report
Current view: top level - gfx/src - nsFontMetrics.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 112 203 55.2 %
Date: 2017-07-14 16:53:18 Functions: 24 43 55.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #include "nsFontMetrics.h"
       7             : #include <math.h>                       // for floor, ceil
       8             : #include <algorithm>                    // for max
       9             : #include "gfxContext.h"                 // for gfxContext
      10             : #include "gfxFontConstants.h"           // for NS_FONT_SYNTHESIS_*
      11             : #include "gfxPlatform.h"                // for gfxPlatform
      12             : #include "gfxPoint.h"                   // for gfxPoint
      13             : #include "gfxRect.h"                    // for gfxRect
      14             : #include "gfxTypes.h"                   // for gfxFloat
      15             : #include "nsBoundingMetrics.h"          // for nsBoundingMetrics
      16             : #include "nsDebug.h"                    // for NS_ERROR
      17             : #include "nsDeviceContext.h"            // for nsDeviceContext
      18             : #include "nsIAtom.h"                    // for nsIAtom
      19             : #include "nsMathUtils.h"                // for NS_round
      20             : #include "nsString.h"                   // for nsString
      21             : #include "nsStyleConsts.h"              // for StyleHyphens::None
      22             : #include "mozilla/Assertions.h"         // for MOZ_ASSERT
      23             : #include "mozilla/UniquePtr.h"          // for UniquePtr
      24             : 
      25             : class gfxUserFontSet;
      26             : using namespace mozilla;
      27             : 
      28             : namespace {
      29             : 
      30          62 : class AutoTextRun {
      31             : public:
      32             :     typedef mozilla::gfx::DrawTarget DrawTarget;
      33             : 
      34           0 :     AutoTextRun(nsFontMetrics* aMetrics, DrawTarget* aDrawTarget,
      35             :                 const char* aString, int32_t aLength)
      36           0 :     {
      37           0 :         mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
      38             :             reinterpret_cast<const uint8_t*>(aString), aLength,
      39             :             aDrawTarget,
      40             :             aMetrics->AppUnitsPerDevPixel(),
      41             :             ComputeFlags(aMetrics), nsTextFrameUtils::Flags(),
      42           0 :             nullptr);
      43           0 :     }
      44             : 
      45          62 :     AutoTextRun(nsFontMetrics* aMetrics, DrawTarget* aDrawTarget,
      46             :                 const char16_t* aString, int32_t aLength)
      47          62 :     {
      48         124 :         mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
      49             :             aString, aLength,
      50             :             aDrawTarget,
      51             :             aMetrics->AppUnitsPerDevPixel(),
      52             :             ComputeFlags(aMetrics), nsTextFrameUtils::Flags(),
      53          62 :             nullptr);
      54          62 :     }
      55             : 
      56          62 :     gfxTextRun *get() { return mTextRun.get(); }
      57          62 :     gfxTextRun *operator->() { return mTextRun.get(); }
      58             : 
      59             : private:
      60          62 :     static gfx::ShapedTextFlags ComputeFlags(nsFontMetrics* aMetrics) {
      61          62 :         gfx::ShapedTextFlags flags = gfx::ShapedTextFlags();
      62          62 :         if (aMetrics->GetTextRunRTL()) {
      63           0 :             flags |= gfx::ShapedTextFlags::TEXT_IS_RTL;
      64             :         }
      65          62 :         if (aMetrics->GetVertical()) {
      66           0 :             switch (aMetrics->GetTextOrientation()) {
      67             :             case NS_STYLE_TEXT_ORIENTATION_MIXED:
      68           0 :                 flags |= gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED;
      69           0 :                 break;
      70             :             case NS_STYLE_TEXT_ORIENTATION_UPRIGHT:
      71           0 :                 flags |= gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
      72           0 :                 break;
      73             :             case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS:
      74           0 :                 flags |= gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
      75           0 :                 break;
      76             :             }
      77             :         }
      78          62 :         return flags;
      79             :     }
      80             : 
      81             :     RefPtr<gfxTextRun> mTextRun;
      82             : };
      83             : 
      84             : class StubPropertyProvider final : public gfxTextRun::PropertyProvider {
      85             : public:
      86           0 :     void GetHyphenationBreaks(gfxTextRun::Range aRange,
      87             :                               gfxTextRun::HyphenType* aBreakBefore) const {
      88           0 :         NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
      89           0 :     }
      90           0 :     mozilla::StyleHyphens GetHyphensOption() const {
      91           0 :         NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
      92           0 :         return mozilla::StyleHyphens::None;
      93             :     }
      94           0 :     gfxFloat GetHyphenWidth() const {
      95           0 :         NS_ERROR("This shouldn't be called because we never enable hyphens");
      96           0 :         return 0;
      97             :     }
      98           0 :     already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget() const {
      99           0 :         NS_ERROR("This shouldn't be called because we never enable hyphens");
     100           0 :         return nullptr;
     101             :     }
     102           0 :     uint32_t GetAppUnitsPerDevUnit() const {
     103           0 :         NS_ERROR("This shouldn't be called because we never enable hyphens");
     104           0 :         return 60;
     105             :     }
     106           0 :     void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) const {
     107           0 :         NS_ERROR("This shouldn't be called because we never enable spacing");
     108           0 :     }
     109             : };
     110             : 
     111             : } // namespace
     112             : 
     113           6 : nsFontMetrics::nsFontMetrics(const nsFont& aFont, const Params& aParams,
     114           6 :                              nsDeviceContext *aContext)
     115             :     : mFont(aFont)
     116           6 :     , mLanguage(aParams.language)
     117             :     , mDeviceContext(aContext)
     118           6 :     , mP2A(aContext->AppUnitsPerDevPixel())
     119           6 :     , mOrientation(aParams.orientation)
     120             :     , mTextRunRTL(false)
     121             :     , mVertical(false)
     122          24 :     , mTextOrientation(0)
     123             : {
     124           6 :     gfxFontStyle style(aFont.style,
     125           6 :                        aFont.weight,
     126           6 :                        aFont.stretch,
     127           6 :                        gfxFloat(aFont.size) / mP2A,
     128           6 :                        aParams.language,
     129           6 :                        aParams.explicitLanguage,
     130           6 :                        aFont.sizeAdjust,
     131           6 :                        aFont.systemFont,
     132           6 :                        mDeviceContext->IsPrinterContext(),
     133           6 :                        aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
     134           6 :                        aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
     135          66 :                        aFont.languageOverride);
     136             : 
     137           6 :     aFont.AddFontFeaturesToStyle(&style);
     138           6 :     aFont.AddFontVariationsToStyle(&style);
     139             : 
     140           6 :     gfxFloat devToCssSize = gfxFloat(mP2A) /
     141           6 :         gfxFloat(mDeviceContext->AppUnitsPerCSSPixel());
     142           6 :     mFontGroup = gfxPlatform::GetPlatform()->
     143           6 :         CreateFontGroup(aFont.fontlist, &style, aParams.textPerf,
     144          12 :                         aParams.userFontSet, devToCssSize);
     145           6 : }
     146             : 
     147           2 : nsFontMetrics::~nsFontMetrics()
     148             : {
     149             :     // Should not be dropped by stylo
     150           1 :     MOZ_ASSERT(NS_IsMainThread());
     151           1 :     if (mDeviceContext) {
     152           0 :         mDeviceContext->FontMetricsDeleted(this);
     153             :     }
     154           1 : }
     155             : 
     156             : void
     157           1 : nsFontMetrics::Destroy()
     158             : {
     159           1 :     mDeviceContext = nullptr;
     160           1 : }
     161             : 
     162             : // XXXTODO get rid of this macro
     163             : #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
     164             : #define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
     165             : 
     166             : const gfxFont::Metrics&
     167         938 : nsFontMetrics::GetMetrics(gfxFont::Orientation aOrientation) const
     168             : {
     169         938 :     return mFontGroup->GetFirstValidFont()->GetMetrics(aOrientation);
     170             : }
     171             : 
     172             : nscoord
     173           0 : nsFontMetrics::XHeight()
     174             : {
     175           0 :     return ROUND_TO_TWIPS(GetMetrics().xHeight);
     176             : }
     177             : 
     178             : nscoord
     179           0 : nsFontMetrics::CapHeight()
     180             : {
     181           0 :     return ROUND_TO_TWIPS(GetMetrics().capHeight);
     182             : }
     183             : 
     184             : nscoord
     185           0 : nsFontMetrics::SuperscriptOffset()
     186             : {
     187           0 :     return ROUND_TO_TWIPS(GetMetrics().emHeight *
     188             :                           NS_FONT_SUPERSCRIPT_OFFSET_RATIO);
     189             : }
     190             : 
     191             : nscoord
     192           0 : nsFontMetrics::SubscriptOffset()
     193             : {
     194           0 :     return ROUND_TO_TWIPS(GetMetrics().emHeight *
     195             :                           NS_FONT_SUBSCRIPT_OFFSET_RATIO);
     196             : }
     197             : 
     198             : void
     199           0 : nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
     200             : {
     201           0 :     aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
     202           0 :     aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
     203           0 : }
     204             : 
     205             : void
     206           0 : nsFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
     207             : {
     208           0 :     aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
     209           0 :     aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
     210           0 : }
     211             : 
     212             : // GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
     213             : // text-decoration lines drawable area. See bug 421353.
     214             : // BE CAREFUL for rounding each values. The logic MUST be same as
     215             : // nsCSSRendering::GetTextDecorationRectInternal's.
     216             : 
     217         138 : static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
     218             :                                   gfxFontGroup* aFontGroup)
     219             : {
     220         138 :     gfxFloat offset = floor(-aFontGroup->GetUnderlineOffset() + 0.5);
     221         138 :     gfxFloat size = NS_round(aMetrics.underlineSize);
     222         138 :     gfxFloat minDescent = offset + size;
     223         138 :     return floor(std::max(minDescent, aMetrics.maxDescent) + 0.5);
     224             : }
     225             : 
     226         270 : static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
     227             : {
     228         270 :     return floor(aMetrics.maxAscent + 0.5);
     229             : }
     230             : 
     231             : nscoord
     232         147 : nsFontMetrics::InternalLeading()
     233             : {
     234         147 :     return ROUND_TO_TWIPS(GetMetrics().internalLeading);
     235             : }
     236             : 
     237             : nscoord
     238         147 : nsFontMetrics::ExternalLeading()
     239             : {
     240         147 :     return ROUND_TO_TWIPS(GetMetrics().externalLeading);
     241             : }
     242             : 
     243             : nscoord
     244         147 : nsFontMetrics::EmHeight()
     245             : {
     246         147 :     return ROUND_TO_TWIPS(GetMetrics().emHeight);
     247             : }
     248             : 
     249             : nscoord
     250           0 : nsFontMetrics::EmAscent()
     251             : {
     252           0 :     return ROUND_TO_TWIPS(GetMetrics().emAscent);
     253             : }
     254             : 
     255             : nscoord
     256           0 : nsFontMetrics::EmDescent()
     257             : {
     258           0 :     return ROUND_TO_TWIPS(GetMetrics().emDescent);
     259             : }
     260             : 
     261             : nscoord
     262         114 : nsFontMetrics::MaxHeight()
     263             : {
     264         114 :     return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
     265         114 :         CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
     266             : }
     267             : 
     268             : nscoord
     269         156 : nsFontMetrics::MaxAscent()
     270             : {
     271         156 :     return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
     272             : }
     273             : 
     274             : nscoord
     275          24 : nsFontMetrics::MaxDescent()
     276             : {
     277          24 :     return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
     278             : }
     279             : 
     280             : nscoord
     281          20 : nsFontMetrics::MaxAdvance()
     282             : {
     283          20 :     return CEIL_TO_TWIPS(GetMetrics().maxAdvance);
     284             : }
     285             : 
     286             : nscoord
     287          29 : nsFontMetrics::AveCharWidth()
     288             : {
     289             :     // Use CEIL instead of ROUND for consistency with GetMaxAdvance
     290          29 :     return CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
     291             : }
     292             : 
     293             : nscoord
     294           0 : nsFontMetrics::SpaceWidth()
     295             : {
     296             :     // For vertical text with mixed or sideways orientation, we want the
     297             :     // width of a horizontal space (even if we're using vertical line-spacing
     298             :     // metrics, as with "writing-mode:vertical-*;text-orientation:mixed").
     299           0 :     return CEIL_TO_TWIPS(
     300             :         GetMetrics(mVertical &&
     301             :                    mTextOrientation == NS_STYLE_TEXT_ORIENTATION_UPRIGHT
     302             :                        ? gfxFont::eVertical
     303             :                        : gfxFont::eHorizontal).spaceWidth);
     304             : }
     305             : 
     306             : int32_t
     307          40 : nsFontMetrics::GetMaxStringLength()
     308             : {
     309          40 :     const gfxFont::Metrics& m = GetMetrics();
     310          40 :     const double x = 32767.0 / m.maxAdvance;
     311          40 :     int32_t len = (int32_t)floor(x);
     312          40 :     return std::max(1, len);
     313             : }
     314             : 
     315             : nscoord
     316           0 : nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
     317             :                         DrawTarget* aDrawTarget)
     318             : {
     319           0 :     if (aLength == 0)
     320           0 :         return 0;
     321             : 
     322           0 :     if (aLength == 1 && aString[0] == ' ')
     323           0 :         return SpaceWidth();
     324             : 
     325           0 :     StubPropertyProvider provider;
     326           0 :     AutoTextRun textRun(this, aDrawTarget, aString, aLength);
     327           0 :     if (textRun.get()) {
     328           0 :       return NSToCoordRound(
     329           0 :           textRun->GetAdvanceWidth(Range(0, aLength), &provider));
     330             :     }
     331           0 :     return 0;
     332             : }
     333             : 
     334             : nscoord
     335          40 : nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
     336             :                         DrawTarget* aDrawTarget)
     337             : {
     338          40 :     if (aLength == 0)
     339           0 :         return 0;
     340             : 
     341          40 :     if (aLength == 1 && aString[0] == ' ')
     342           0 :         return SpaceWidth();
     343             : 
     344          40 :     StubPropertyProvider provider;
     345          80 :     AutoTextRun textRun(this, aDrawTarget, aString, aLength);
     346          40 :     if (textRun.get()) {
     347          80 :       return NSToCoordRound(
     348          40 :           textRun->GetAdvanceWidth(Range(0, aLength), &provider));
     349             :     }
     350           0 :     return 0;
     351             : }
     352             : 
     353             : // Draw a string using this font handle on the surface passed in.
     354             : void
     355           0 : nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
     356             :                           nscoord aX, nscoord aY,
     357             :                           gfxContext *aContext)
     358             : {
     359           0 :     if (aLength == 0)
     360           0 :         return;
     361             : 
     362           0 :     StubPropertyProvider provider;
     363           0 :     AutoTextRun textRun(this, aContext->GetDrawTarget(), aString, aLength);
     364           0 :     if (!textRun.get()) {
     365           0 :         return;
     366             :     }
     367           0 :     gfxPoint pt(aX, aY);
     368           0 :     Range range(0, aLength);
     369           0 :     if (mTextRunRTL) {
     370           0 :         if (mVertical) {
     371           0 :             pt.y += textRun->GetAdvanceWidth(range, &provider);
     372             :         } else {
     373           0 :             pt.x += textRun->GetAdvanceWidth(range, &provider);
     374             :         }
     375             :     }
     376           0 :     gfxTextRun::DrawParams params(aContext);
     377           0 :     params.provider = &provider;
     378           0 :     textRun->Draw(range, pt, params);
     379             : }
     380             : 
     381             : void
     382           3 : nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
     383             :                           nscoord aX, nscoord aY,
     384             :                           gfxContext *aContext,
     385             :                           DrawTarget* aTextRunConstructionDrawTarget)
     386             : {
     387           3 :     if (aLength == 0)
     388           0 :         return;
     389             : 
     390           3 :     StubPropertyProvider provider;
     391           6 :     AutoTextRun textRun(this, aTextRunConstructionDrawTarget, aString, aLength);
     392           3 :     if (!textRun.get()) {
     393           0 :         return;
     394             :     }
     395           3 :     gfxPoint pt(aX, aY);
     396           3 :     Range range(0, aLength);
     397           3 :     if (mTextRunRTL) {
     398           0 :         if (mVertical) {
     399           0 :             pt.y += textRun->GetAdvanceWidth(range, &provider);
     400             :         } else {
     401           0 :             pt.x += textRun->GetAdvanceWidth(range, &provider);
     402             :         }
     403             :     }
     404           3 :     gfxTextRun::DrawParams params(aContext);
     405           3 :     params.provider = &provider;
     406           3 :     textRun->Draw(range, pt, params);
     407             : }
     408             : 
     409             : static nsBoundingMetrics
     410          24 : GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t* aString,
     411             :                        uint32_t aLength, mozilla::gfx::DrawTarget* aDrawTarget,
     412             :                        gfxFont::BoundingBoxType aType)
     413             : {
     414          24 :     if (aLength == 0)
     415           5 :         return nsBoundingMetrics();
     416             : 
     417          19 :     StubPropertyProvider provider;
     418          38 :     AutoTextRun textRun(aMetrics, aDrawTarget, aString, aLength);
     419          19 :     nsBoundingMetrics m;
     420          19 :     if (textRun.get()) {
     421             :         gfxTextRun::Metrics theMetrics = textRun->MeasureText(
     422          19 :             gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider);
     423             : 
     424          19 :         m.leftBearing  = NSToCoordFloor( theMetrics.mBoundingBox.X());
     425          19 :         m.rightBearing = NSToCoordCeil(  theMetrics.mBoundingBox.XMost());
     426          19 :         m.ascent       = NSToCoordCeil( -theMetrics.mBoundingBox.Y());
     427          19 :         m.descent      = NSToCoordCeil(  theMetrics.mBoundingBox.YMost());
     428          19 :         m.width        = NSToCoordRound( theMetrics.mAdvanceWidth);
     429             :     }
     430          19 :     return m;
     431             : }
     432             : 
     433             : nsBoundingMetrics
     434           0 : nsFontMetrics::GetBoundingMetrics(const char16_t *aString, uint32_t aLength,
     435             :                                   DrawTarget* aDrawTarget)
     436             : {
     437             :   return GetTextBoundingMetrics(this, aString, aLength, aDrawTarget,
     438           0 :                                 gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS);
     439             : }
     440             : 
     441             : nsBoundingMetrics
     442          24 : nsFontMetrics::GetInkBoundsForVisualOverflow(const char16_t *aString, uint32_t aLength,
     443             :                                              DrawTarget* aDrawTarget)
     444             : {
     445             :   return GetTextBoundingMetrics(this, aString, aLength, aDrawTarget,
     446          24 :                                 gfxFont::LOOSE_INK_EXTENTS);
     447             : }
     448             : 

Generated by: LCOV version 1.13