gfx/src/nsFontMetrics.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/src/nsFontMetrics.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,396 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsFontMetrics.h"
    1.10 +#include <math.h>                       // for floor, ceil
    1.11 +#include <algorithm>                    // for max
    1.12 +#include "gfxPlatform.h"                // for gfxPlatform
    1.13 +#include "gfxPoint.h"                   // for gfxPoint
    1.14 +#include "gfxRect.h"                    // for gfxRect
    1.15 +#include "gfxTypes.h"                   // for gfxFloat
    1.16 +#include "nsBoundingMetrics.h"          // for nsBoundingMetrics
    1.17 +#include "nsDebug.h"                    // for NS_ERROR, NS_ABORT_IF_FALSE
    1.18 +#include "nsDeviceContext.h"            // for nsDeviceContext
    1.19 +#include "nsIAtom.h"                    // for nsIAtom
    1.20 +#include "nsMathUtils.h"                // for NS_round
    1.21 +#include "nsRenderingContext.h"         // for nsRenderingContext
    1.22 +#include "nsString.h"               // for nsString
    1.23 +#include "nsStyleConsts.h"              // for NS_STYLE_HYPHENS_NONE
    1.24 +
    1.25 +class gfxUserFontSet;
    1.26 +
    1.27 +namespace {
    1.28 +
    1.29 +class AutoTextRun {
    1.30 +public:
    1.31 +    AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
    1.32 +                const char* aString, int32_t aLength)
    1.33 +    {
    1.34 +        mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
    1.35 +            reinterpret_cast<const uint8_t*>(aString), aLength,
    1.36 +            aRC->ThebesContext(),
    1.37 +            aMetrics->AppUnitsPerDevPixel(),
    1.38 +            ComputeFlags(aMetrics));
    1.39 +    }
    1.40 +
    1.41 +    AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
    1.42 +                const char16_t* aString, int32_t aLength)
    1.43 +    {
    1.44 +        mTextRun = aMetrics->GetThebesFontGroup()->MakeTextRun(
    1.45 +            aString, aLength,
    1.46 +            aRC->ThebesContext(),
    1.47 +            aMetrics->AppUnitsPerDevPixel(),
    1.48 +            ComputeFlags(aMetrics));
    1.49 +    }
    1.50 +
    1.51 +    gfxTextRun *get() { return mTextRun; }
    1.52 +    gfxTextRun *operator->() { return mTextRun; }
    1.53 +
    1.54 +private:
    1.55 +    static uint32_t ComputeFlags(nsFontMetrics* aMetrics) {
    1.56 +        uint32_t flags = 0;
    1.57 +        if (aMetrics->GetTextRunRTL()) {
    1.58 +            flags |= gfxTextRunFactory::TEXT_IS_RTL;
    1.59 +        }
    1.60 +        return flags;
    1.61 +    }
    1.62 +
    1.63 +    nsAutoPtr<gfxTextRun> mTextRun;
    1.64 +};
    1.65 +
    1.66 +class StubPropertyProvider : public gfxTextRun::PropertyProvider {
    1.67 +public:
    1.68 +    virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
    1.69 +                                      bool* aBreakBefore) {
    1.70 +        NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
    1.71 +    }
    1.72 +    virtual int8_t GetHyphensOption() {
    1.73 +        NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
    1.74 +        return NS_STYLE_HYPHENS_NONE;
    1.75 +    }
    1.76 +    virtual gfxFloat GetHyphenWidth() {
    1.77 +        NS_ERROR("This shouldn't be called because we never enable hyphens");
    1.78 +        return 0;
    1.79 +    }
    1.80 +    virtual already_AddRefed<gfxContext> GetContext() {
    1.81 +        NS_ERROR("This shouldn't be called because we never enable hyphens");
    1.82 +        return nullptr;
    1.83 +    }
    1.84 +    virtual uint32_t GetAppUnitsPerDevUnit() {
    1.85 +        NS_ERROR("This shouldn't be called because we never enable hyphens");
    1.86 +        return 60;
    1.87 +    }
    1.88 +    virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
    1.89 +                            Spacing* aSpacing) {
    1.90 +        NS_ERROR("This shouldn't be called because we never enable spacing");
    1.91 +    }
    1.92 +};
    1.93 +
    1.94 +} // anon namespace
    1.95 +
    1.96 +nsFontMetrics::nsFontMetrics()
    1.97 +    : mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
    1.98 +{
    1.99 +}
   1.100 +
   1.101 +nsFontMetrics::~nsFontMetrics()
   1.102 +{
   1.103 +    if (mDeviceContext)
   1.104 +        mDeviceContext->FontMetricsDeleted(this);
   1.105 +}
   1.106 +
   1.107 +nsresult
   1.108 +nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
   1.109 +                    nsDeviceContext *aContext,
   1.110 +                    gfxUserFontSet *aUserFontSet,
   1.111 +                    gfxTextPerfMetrics *aTextPerf)
   1.112 +{
   1.113 +    NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
   1.114 +
   1.115 +    mFont = aFont;
   1.116 +    mLanguage = aLanguage;
   1.117 +    mDeviceContext = aContext;
   1.118 +    mP2A = mDeviceContext->AppUnitsPerDevPixel();
   1.119 +
   1.120 +    gfxFontStyle style(aFont.style,
   1.121 +                       aFont.weight,
   1.122 +                       aFont.stretch,
   1.123 +                       gfxFloat(aFont.size) / mP2A,
   1.124 +                       aLanguage,
   1.125 +                       aFont.sizeAdjust,
   1.126 +                       aFont.systemFont,
   1.127 +                       mDeviceContext->IsPrinterSurface(),
   1.128 +                       aFont.languageOverride);
   1.129 +
   1.130 +    aFont.AddFontFeaturesToStyle(&style);
   1.131 +
   1.132 +    mFontGroup = gfxPlatform::GetPlatform()->
   1.133 +        CreateFontGroup(aFont.name, &style, aUserFontSet);
   1.134 +    mFontGroup->SetTextPerfMetrics(aTextPerf);
   1.135 +    if (mFontGroup->FontListLength() < 1)
   1.136 +        return NS_ERROR_UNEXPECTED;
   1.137 +
   1.138 +    return NS_OK;
   1.139 +}
   1.140 +
   1.141 +void
   1.142 +nsFontMetrics::Destroy()
   1.143 +{
   1.144 +    mDeviceContext = nullptr;
   1.145 +}
   1.146 +
   1.147 +// XXXTODO get rid of this macro
   1.148 +#define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
   1.149 +#define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
   1.150 +
   1.151 +const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
   1.152 +{
   1.153 +    return mFontGroup->GetFontAt(0)->GetMetrics();
   1.154 +}
   1.155 +
   1.156 +nscoord
   1.157 +nsFontMetrics::XHeight()
   1.158 +{
   1.159 +    return ROUND_TO_TWIPS(GetMetrics().xHeight);
   1.160 +}
   1.161 +
   1.162 +nscoord
   1.163 +nsFontMetrics::SuperscriptOffset()
   1.164 +{
   1.165 +    return ROUND_TO_TWIPS(GetMetrics().superscriptOffset);
   1.166 +}
   1.167 +
   1.168 +nscoord
   1.169 +nsFontMetrics::SubscriptOffset()
   1.170 +{
   1.171 +    return ROUND_TO_TWIPS(GetMetrics().subscriptOffset);
   1.172 +}
   1.173 +
   1.174 +void
   1.175 +nsFontMetrics::GetStrikeout(nscoord& aOffset, nscoord& aSize)
   1.176 +{
   1.177 +    aOffset = ROUND_TO_TWIPS(GetMetrics().strikeoutOffset);
   1.178 +    aSize = ROUND_TO_TWIPS(GetMetrics().strikeoutSize);
   1.179 +}
   1.180 +
   1.181 +void
   1.182 +nsFontMetrics::GetUnderline(nscoord& aOffset, nscoord& aSize)
   1.183 +{
   1.184 +    aOffset = ROUND_TO_TWIPS(mFontGroup->GetUnderlineOffset());
   1.185 +    aSize = ROUND_TO_TWIPS(GetMetrics().underlineSize);
   1.186 +}
   1.187 +
   1.188 +// GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
   1.189 +// text-decoration lines drawable area. See bug 421353.
   1.190 +// BE CAREFUL for rounding each values. The logic MUST be same as
   1.191 +// nsCSSRendering::GetTextDecorationRectInternal's.
   1.192 +
   1.193 +static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
   1.194 +                                  gfxFontGroup* aFontGroup)
   1.195 +{
   1.196 +    gfxFloat offset = floor(-aFontGroup->GetUnderlineOffset() + 0.5);
   1.197 +    gfxFloat size = NS_round(aMetrics.underlineSize);
   1.198 +    gfxFloat minDescent = floor(offset + size + 0.5);
   1.199 +    return std::max(minDescent, aMetrics.maxDescent);
   1.200 +}
   1.201 +
   1.202 +static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
   1.203 +{
   1.204 +    return floor(aMetrics.maxAscent + 0.5);
   1.205 +}
   1.206 +
   1.207 +nscoord
   1.208 +nsFontMetrics::InternalLeading()
   1.209 +{
   1.210 +    return ROUND_TO_TWIPS(GetMetrics().internalLeading);
   1.211 +}
   1.212 +
   1.213 +nscoord
   1.214 +nsFontMetrics::ExternalLeading()
   1.215 +{
   1.216 +    return ROUND_TO_TWIPS(GetMetrics().externalLeading);
   1.217 +}
   1.218 +
   1.219 +nscoord
   1.220 +nsFontMetrics::EmHeight()
   1.221 +{
   1.222 +    return ROUND_TO_TWIPS(GetMetrics().emHeight);
   1.223 +}
   1.224 +
   1.225 +nscoord
   1.226 +nsFontMetrics::EmAscent()
   1.227 +{
   1.228 +    return ROUND_TO_TWIPS(GetMetrics().emAscent);
   1.229 +}
   1.230 +
   1.231 +nscoord
   1.232 +nsFontMetrics::EmDescent()
   1.233 +{
   1.234 +    return ROUND_TO_TWIPS(GetMetrics().emDescent);
   1.235 +}
   1.236 +
   1.237 +nscoord
   1.238 +nsFontMetrics::MaxHeight()
   1.239 +{
   1.240 +    return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics())) +
   1.241 +        CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
   1.242 +}
   1.243 +
   1.244 +nscoord
   1.245 +nsFontMetrics::MaxAscent()
   1.246 +{
   1.247 +    return CEIL_TO_TWIPS(ComputeMaxAscent(GetMetrics()));
   1.248 +}
   1.249 +
   1.250 +nscoord
   1.251 +nsFontMetrics::MaxDescent()
   1.252 +{
   1.253 +    return CEIL_TO_TWIPS(ComputeMaxDescent(GetMetrics(), mFontGroup));
   1.254 +}
   1.255 +
   1.256 +nscoord
   1.257 +nsFontMetrics::MaxAdvance()
   1.258 +{
   1.259 +    return CEIL_TO_TWIPS(GetMetrics().maxAdvance);
   1.260 +}
   1.261 +
   1.262 +nscoord
   1.263 +nsFontMetrics::AveCharWidth()
   1.264 +{
   1.265 +    // Use CEIL instead of ROUND for consistency with GetMaxAdvance
   1.266 +    return CEIL_TO_TWIPS(GetMetrics().aveCharWidth);
   1.267 +}
   1.268 +
   1.269 +nscoord
   1.270 +nsFontMetrics::SpaceWidth()
   1.271 +{
   1.272 +    return CEIL_TO_TWIPS(GetMetrics().spaceWidth);
   1.273 +}
   1.274 +
   1.275 +int32_t
   1.276 +nsFontMetrics::GetMaxStringLength()
   1.277 +{
   1.278 +    const gfxFont::Metrics& m = GetMetrics();
   1.279 +    const double x = 32767.0 / m.maxAdvance;
   1.280 +    int32_t len = (int32_t)floor(x);
   1.281 +    return std::max(1, len);
   1.282 +}
   1.283 +
   1.284 +nscoord
   1.285 +nsFontMetrics::GetWidth(const char* aString, uint32_t aLength,
   1.286 +                        nsRenderingContext *aContext)
   1.287 +{
   1.288 +    if (aLength == 0)
   1.289 +        return 0;
   1.290 +
   1.291 +    if (aLength == 1 && aString[0] == ' ')
   1.292 +        return SpaceWidth();
   1.293 +
   1.294 +    StubPropertyProvider provider;
   1.295 +    AutoTextRun textRun(this, aContext, aString, aLength);
   1.296 +    return textRun.get() ?
   1.297 +        NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
   1.298 +}
   1.299 +
   1.300 +nscoord
   1.301 +nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
   1.302 +                        nsRenderingContext *aContext)
   1.303 +{
   1.304 +    if (aLength == 0)
   1.305 +        return 0;
   1.306 +
   1.307 +    if (aLength == 1 && aString[0] == ' ')
   1.308 +        return SpaceWidth();
   1.309 +
   1.310 +    StubPropertyProvider provider;
   1.311 +    AutoTextRun textRun(this, aContext, aString, aLength);
   1.312 +    return textRun.get() ?
   1.313 +        NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
   1.314 +}
   1.315 +
   1.316 +// Draw a string using this font handle on the surface passed in.
   1.317 +void
   1.318 +nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
   1.319 +                          nscoord aX, nscoord aY,
   1.320 +                          nsRenderingContext *aContext)
   1.321 +{
   1.322 +    if (aLength == 0)
   1.323 +        return;
   1.324 +
   1.325 +    StubPropertyProvider provider;
   1.326 +    AutoTextRun textRun(this, aContext, aString, aLength);
   1.327 +    if (!textRun.get()) {
   1.328 +        return;
   1.329 +    }
   1.330 +    gfxPoint pt(aX, aY);
   1.331 +    if (mTextRunRTL) {
   1.332 +        pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
   1.333 +    }
   1.334 +    textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
   1.335 +                  &provider, nullptr, nullptr);
   1.336 +}
   1.337 +
   1.338 +void
   1.339 +nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
   1.340 +                          nscoord aX, nscoord aY,
   1.341 +                          nsRenderingContext *aContext,
   1.342 +                          nsRenderingContext *aTextRunConstructionContext)
   1.343 +{
   1.344 +    if (aLength == 0)
   1.345 +        return;
   1.346 +
   1.347 +    StubPropertyProvider provider;
   1.348 +    AutoTextRun textRun(this, aTextRunConstructionContext, aString, aLength);
   1.349 +    if (!textRun.get()) {
   1.350 +        return;
   1.351 +    }
   1.352 +    gfxPoint pt(aX, aY);
   1.353 +    if (mTextRunRTL) {
   1.354 +        pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
   1.355 +    }
   1.356 +    textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
   1.357 +                  &provider, nullptr, nullptr);
   1.358 +}
   1.359 +
   1.360 +static nsBoundingMetrics
   1.361 +GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t *aString, uint32_t aLength,
   1.362 +                       nsRenderingContext *aContext, gfxFont::BoundingBoxType aType)
   1.363 +{
   1.364 +    if (aLength == 0)
   1.365 +        return nsBoundingMetrics();
   1.366 +
   1.367 +    StubPropertyProvider provider;
   1.368 +    AutoTextRun textRun(aMetrics, aContext, aString, aLength);
   1.369 +    nsBoundingMetrics m;
   1.370 +    if (textRun.get()) {
   1.371 +        gfxTextRun::Metrics theMetrics =
   1.372 +            textRun->MeasureText(0, aLength,
   1.373 +                                 aType,
   1.374 +                                 aContext->ThebesContext(), &provider);
   1.375 +
   1.376 +        m.leftBearing  = NSToCoordFloor( theMetrics.mBoundingBox.X());
   1.377 +        m.rightBearing = NSToCoordCeil(  theMetrics.mBoundingBox.XMost());
   1.378 +        m.ascent       = NSToCoordCeil( -theMetrics.mBoundingBox.Y());
   1.379 +        m.descent      = NSToCoordCeil(  theMetrics.mBoundingBox.YMost());
   1.380 +        m.width        = NSToCoordRound( theMetrics.mAdvanceWidth);
   1.381 +    }
   1.382 +    return m;
   1.383 +}
   1.384 +
   1.385 +nsBoundingMetrics
   1.386 +nsFontMetrics::GetBoundingMetrics(const char16_t *aString, uint32_t aLength,
   1.387 +                                  nsRenderingContext *aContext)
   1.388 +{
   1.389 +  return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS);
   1.390 +  
   1.391 +}
   1.392 +
   1.393 +nsBoundingMetrics
   1.394 +nsFontMetrics::GetInkBoundsForVisualOverflow(const char16_t *aString, uint32_t aLength,
   1.395 +                                             nsRenderingContext *aContext)
   1.396 +{
   1.397 +  return GetTextBoundingMetrics(this, aString, aLength, aContext, gfxFont::LOOSE_INK_EXTENTS);
   1.398 +}
   1.399 +

mercurial