2018-11-30 22:52:05 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-03-15 12:34:25 +03:00
|
|
|
|
|
|
|
#include "gfxGDIFont.h"
|
2013-06-30 20:26:39 +04:00
|
|
|
|
|
|
|
#include "mozilla/MemoryReporting.h"
|
2016-08-17 01:41:12 +03:00
|
|
|
#include "mozilla/Sprintf.h"
|
2013-11-22 07:35:40 +04:00
|
|
|
#include "mozilla/WindowsVersion.h"
|
2013-06-30 20:26:39 +04:00
|
|
|
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2010-03-15 12:34:25 +03:00
|
|
|
#include "gfxWindowsPlatform.h"
|
|
|
|
#include "gfxContext.h"
|
2013-08-06 00:06:09 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "nsUnicodeProperties.h"
|
2013-10-08 03:15:59 +04:00
|
|
|
#include "gfxFontConstants.h"
|
2014-09-16 13:58:12 +04:00
|
|
|
#include "gfxTextRun.h"
|
2010-03-15 12:34:25 +03:00
|
|
|
|
|
|
|
#include "cairo-win32.h"
|
|
|
|
|
|
|
|
#define ROUND(x) floor((x) + 0.5)
|
|
|
|
|
2013-08-06 00:06:09 +04:00
|
|
|
using namespace mozilla;
|
2017-08-07 23:20:44 +03:00
|
|
|
using namespace mozilla::gfx;
|
2013-08-06 00:06:09 +04:00
|
|
|
using namespace mozilla::unicode;
|
|
|
|
|
2010-03-15 12:34:25 +03:00
|
|
|
gfxGDIFont::gfxGDIFont(GDIFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
|
|
|
|
AntialiasOption anAAOption)
|
2017-04-07 00:41:02 +03:00
|
|
|
: gfxFont(nullptr, aFontEntry, aFontStyle, anAAOption),
|
2013-07-31 19:44:31 +04:00
|
|
|
mFont(nullptr),
|
2012-07-30 18:20:58 +04:00
|
|
|
mMetrics(nullptr),
|
2019-09-20 19:30:21 +03:00
|
|
|
mIsBitmap(false),
|
2014-06-09 19:43:16 +04:00
|
|
|
mScriptCache(nullptr) {
|
2018-04-26 14:46:18 +03:00
|
|
|
mNeedsSyntheticBold = aFontStyle->NeedsSyntheticBold(aFontEntry);
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
|
2016-08-22 23:39:19 +03:00
|
|
|
Initialize();
|
2017-04-07 00:41:02 +03:00
|
|
|
|
|
|
|
if (mFont) {
|
|
|
|
mUnscaledFont = aFontEntry->LookupUnscaledFont(mFont);
|
|
|
|
}
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxGDIFont::~gfxGDIFont() {
|
2013-01-01 16:34:34 +04:00
|
|
|
if (mFont) {
|
|
|
|
::DeleteObject(mFont);
|
|
|
|
}
|
2014-06-09 19:43:16 +04:00
|
|
|
if (mScriptCache) {
|
|
|
|
ScriptFreeCache(&mScriptCache);
|
|
|
|
}
|
2010-05-05 14:10:36 +04:00
|
|
|
delete mMetrics;
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
UniquePtr<gfxFont> gfxGDIFont::CopyWithAntialiasOption(
|
|
|
|
AntialiasOption anAAOption) {
|
2017-01-09 20:41:35 +03:00
|
|
|
auto entry = static_cast<GDIFontEntry*>(mFontEntry.get());
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
return MakeUnique<gfxGDIFont>(entry, &mStyle, anAAOption);
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
2015-12-16 00:56:41 +03:00
|
|
|
bool gfxGDIFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
|
2014-05-31 11:12:40 +04:00
|
|
|
uint32_t aOffset, uint32_t aLength, Script aScript,
|
2017-04-03 19:49:17 +03:00
|
|
|
bool aVertical, RoundingFlags aRounding,
|
2014-05-31 11:12:40 +04:00
|
|
|
gfxShapedText* aShapedText) {
|
2010-05-05 14:10:36 +04:00
|
|
|
if (!mIsValid) {
|
|
|
|
NS_WARNING("invalid font! expect incorrect text rendering");
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-05-05 14:10:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-12-16 00:56:41 +03:00
|
|
|
return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
|
2017-04-03 19:49:17 +03:00
|
|
|
aVertical, aRounding, aShapedText);
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
2014-09-30 10:37:40 +04:00
|
|
|
const gfxFont::Metrics& gfxGDIFont::GetHorizontalMetrics() { return *mMetrics; }
|
2010-03-15 12:34:25 +03:00
|
|
|
|
2017-08-07 23:20:44 +03:00
|
|
|
already_AddRefed<ScaledFont> gfxGDIFont::GetScaledFont(DrawTarget* aTarget) {
|
|
|
|
if (!mAzureScaledFont) {
|
|
|
|
LOGFONT lf;
|
|
|
|
GetObject(GetHFONT(), sizeof(LOGFONT), &lf);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-10-02 00:56:30 +03:00
|
|
|
mAzureScaledFont = Factory::CreateScaledFontForGDIFont(
|
|
|
|
&lf, GetUnscaledFont(), GetAdjustedSize());
|
2018-07-04 17:56:40 +03:00
|
|
|
InitializeScaledFont();
|
2017-08-07 23:20:44 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-08-07 23:20:44 +03:00
|
|
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
|
|
|
return scaledFont.forget();
|
|
|
|
}
|
|
|
|
|
2016-06-27 19:41:55 +03:00
|
|
|
gfxFont::RunMetrics gfxGDIFont::Measure(const gfxTextRun* aTextRun,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aStart, uint32_t aEnd,
|
2011-06-22 12:49:53 +04:00
|
|
|
BoundingBoxType aBoundingBoxType,
|
2015-12-16 00:56:41 +03:00
|
|
|
DrawTarget* aRefDrawTarget,
|
2014-10-16 12:40:19 +04:00
|
|
|
Spacing* aSpacing,
|
2017-05-05 00:27:05 +03:00
|
|
|
gfx::ShapedTextFlags aOrientation) {
|
2011-06-22 12:49:53 +04:00
|
|
|
gfxFont::RunMetrics metrics =
|
2015-12-16 00:56:41 +03:00
|
|
|
gfxFont::Measure(aTextRun, aStart, aEnd, aBoundingBoxType, aRefDrawTarget,
|
|
|
|
aSpacing, aOrientation);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-06-22 12:49:53 +04:00
|
|
|
// if aBoundingBoxType is LOOSE_INK_EXTENTS
|
|
|
|
// and the underlying cairo font may be antialiased,
|
|
|
|
// we can't trust Windows to have considered all the pixels
|
|
|
|
// so we need to add "padding" to the bounds.
|
|
|
|
// (see bugs 475968, 439831, compare also bug 445087)
|
|
|
|
if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
|
|
|
|
mAntialiasOption != kAntialiasNone && metrics.mBoundingBox.Width() > 0) {
|
2017-12-19 23:48:39 +03:00
|
|
|
metrics.mBoundingBox.MoveByX(-aTextRun->GetAppUnitsPerDevUnit());
|
|
|
|
metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() +
|
|
|
|
aTextRun->GetAppUnitsPerDevUnit() * 3);
|
2011-06-22 12:49:53 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-06-22 12:49:53 +04:00
|
|
|
return metrics;
|
|
|
|
}
|
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
void gfxGDIFont::Initialize() {
|
|
|
|
NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
LOGFONTW logFont;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-03-15 12:34:25 +03:00
|
|
|
if (mAdjustedSize == 0.0) {
|
|
|
|
mAdjustedSize = mStyle.size;
|
2015-04-21 09:10:40 +03:00
|
|
|
if (mStyle.sizeAdjust > 0.0 && mAdjustedSize > 0.0) {
|
2010-03-15 12:34:25 +03:00
|
|
|
// to implement font-size-adjust, we first create the "unadjusted" font
|
2017-11-23 22:38:17 +03:00
|
|
|
FillLogFont(logFont, mAdjustedSize);
|
2010-05-05 14:10:36 +04:00
|
|
|
mFont = ::CreateFontIndirectW(&logFont);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
// initialize its metrics so we can calculate size adjustment
|
|
|
|
Initialize();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-11-14 16:42:06 +03:00
|
|
|
// Unless the font was so small that GDI metrics rounded to zero,
|
2010-03-15 12:34:25 +03:00
|
|
|
// calculate the properly adjusted size, and then proceed
|
2010-05-05 14:10:36 +04:00
|
|
|
// to recreate mFont and recalculate metrics
|
2016-11-14 16:42:06 +03:00
|
|
|
if (mMetrics->xHeight > 0.0 && mMetrics->emHeight > 0.0) {
|
|
|
|
gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight;
|
|
|
|
mAdjustedSize = mStyle.GetAdjustedSize(aspect);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
// delete the temporary font and metrics
|
|
|
|
::DeleteObject(mFont);
|
2012-07-30 18:20:58 +04:00
|
|
|
mFont = nullptr;
|
2010-05-05 14:10:36 +04:00
|
|
|
delete mMetrics;
|
2012-07-30 18:20:58 +04:00
|
|
|
mMetrics = nullptr;
|
2015-04-21 09:10:40 +03:00
|
|
|
} else if (mStyle.sizeAdjust == 0.0) {
|
|
|
|
mAdjustedSize = 0.0;
|
2012-02-14 12:24:26 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2012-02-14 12:24:26 +04:00
|
|
|
// (bug 724231) for local user fonts, we don't use GDI's synthetic bold,
|
|
|
|
// as it could lead to a different, incompatible face being used
|
|
|
|
// but instead do our own multi-striking
|
2018-04-26 14:46:18 +03:00
|
|
|
if (mNeedsSyntheticBold && GetFontEntry()->IsLocalUserFont()) {
|
2012-02-14 12:24:26 +04:00
|
|
|
mApplySyntheticBold = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
// this may end up being zero
|
2011-07-15 18:16:15 +04:00
|
|
|
mAdjustedSize = ROUND(mAdjustedSize);
|
2017-11-23 22:38:17 +03:00
|
|
|
FillLogFont(logFont, mAdjustedSize);
|
2010-05-05 14:10:36 +04:00
|
|
|
mFont = ::CreateFontIndirectW(&logFont);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
mMetrics = new gfxFont::Metrics;
|
|
|
|
::memset(mMetrics, 0, sizeof(*mMetrics));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-04-07 00:41:02 +03:00
|
|
|
if (!mFont) {
|
|
|
|
NS_WARNING("Failed creating GDI font");
|
|
|
|
mIsValid = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-15 12:34:25 +03:00
|
|
|
AutoDC dc;
|
|
|
|
SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
|
|
|
|
AutoSelectFont selectFont(dc.GetDC(), mFont);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
// Get font metrics if size > 0
|
|
|
|
if (mAdjustedSize > 0.0) {
|
|
|
|
OUTLINETEXTMETRIC oMetrics;
|
|
|
|
TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
|
|
|
|
mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
|
|
|
|
mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
|
|
|
|
mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
|
|
|
|
mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
const MAT2 kIdentityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
|
|
|
|
GLYPHMETRICS gm;
|
2014-01-04 19:02:17 +04:00
|
|
|
DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm,
|
|
|
|
0, nullptr, &kIdentityMatrix);
|
2011-12-07 07:02:53 +04:00
|
|
|
if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
|
|
|
|
// 56% of ascent, best guess for true type
|
|
|
|
mMetrics->xHeight =
|
|
|
|
ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->xHeight = gm.gmptGlyphOrigin.y;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-08-18 12:43:54 +03:00
|
|
|
len = GetGlyphOutlineW(dc.GetDC(), char16_t('H'), GGO_METRICS, &gm, 0,
|
2014-01-04 19:02:17 +04:00
|
|
|
nullptr, &kIdentityMatrix);
|
2011-12-07 07:02:53 +04:00
|
|
|
if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
|
2016-08-18 12:43:54 +03:00
|
|
|
mMetrics->capHeight = metrics.tmAscent - metrics.tmInternalLeading;
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2016-08-18 12:43:54 +03:00
|
|
|
mMetrics->capHeight = gm.gmptGlyphOrigin.y;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
|
|
|
|
gfxFloat typEmHeight =
|
|
|
|
(double)oMetrics.otmAscent - (double)oMetrics.otmDescent;
|
|
|
|
mMetrics->emAscent =
|
|
|
|
ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight);
|
|
|
|
mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
|
|
|
|
if (oMetrics.otmEMSquare > 0) {
|
|
|
|
mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
} else {
|
2011-12-07 07:02:53 +04:00
|
|
|
// Make a best-effort guess at extended metrics
|
|
|
|
// this is based on general typographic guidelines
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
// GetTextMetrics can fail if the font file has been removed
|
|
|
|
// or corrupted recently.
|
|
|
|
BOOL result = GetTextMetrics(dc.GetDC(), &metrics);
|
|
|
|
if (!result) {
|
|
|
|
NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
|
2017-04-07 00:41:02 +03:00
|
|
|
mIsValid = false;
|
2011-12-07 07:02:53 +04:00
|
|
|
memset(mMetrics, 0, sizeof(*mMetrics));
|
2017-04-07 00:41:02 +03:00
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->xHeight =
|
|
|
|
ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
|
|
|
|
mMetrics->strikeoutSize = 1;
|
|
|
|
mMetrics->strikeoutOffset =
|
|
|
|
ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
|
|
|
|
mMetrics->underlineSize = 1;
|
|
|
|
mMetrics->underlineOffset =
|
|
|
|
-ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent
|
|
|
|
mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
|
|
|
|
mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading;
|
|
|
|
mMetrics->emDescent = metrics.tmDescent;
|
2016-08-18 12:43:54 +03:00
|
|
|
mMetrics->capHeight = mMetrics->emAscent;
|
2017-04-07 00:41:02 +03:00
|
|
|
}
|
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->internalLeading = metrics.tmInternalLeading;
|
|
|
|
mMetrics->externalLeading = metrics.tmExternalLeading;
|
|
|
|
mMetrics->maxHeight = metrics.tmHeight;
|
2016-08-18 12:43:54 +03:00
|
|
|
mMetrics->maxAscent = metrics.tmAscent;
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->maxDescent = metrics.tmDescent;
|
|
|
|
mMetrics->maxAdvance = metrics.tmMaxCharWidth;
|
|
|
|
mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth);
|
|
|
|
// The font is monospace when TMPF_FIXED_PITCH is *not* set!
|
|
|
|
// See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx
|
|
|
|
if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
|
|
|
|
mMetrics->maxAdvance = mMetrics->aveCharWidth;
|
|
|
|
}
|
2010-03-15 12:34:25 +03:00
|
|
|
|
2019-09-20 19:30:21 +03:00
|
|
|
mIsBitmap = !(metrics.tmPitchAndFamily & TMPF_VECTOR);
|
|
|
|
|
2015-05-15 23:30:29 +03:00
|
|
|
// For fonts with USE_TYPO_METRICS set in the fsSelection field,
|
|
|
|
// let the OS/2 sTypo* metrics override the previous values.
|
|
|
|
// (see http://www.microsoft.com/typography/otspec/os2.htm#fss)
|
|
|
|
// Using the equivalent values from oMetrics provides inconsistent
|
|
|
|
// results with CFF fonts, so we instead rely on OS2Table.
|
|
|
|
gfxFontEntry::AutoTable os2Table(mFontEntry,
|
|
|
|
TRUETYPE_TAG('O', 'S', '/', '2'));
|
|
|
|
if (os2Table) {
|
|
|
|
uint32_t len;
|
|
|
|
const OS2Table* os2 =
|
|
|
|
reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
|
|
|
|
if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
|
|
|
|
const uint16_t kUseTypoMetricsMask = 1 << 7;
|
|
|
|
if ((uint16_t(os2->fsSelection) & kUseTypoMetricsMask)) {
|
|
|
|
double ascent = int16_t(os2->sTypoAscender);
|
|
|
|
double descent = int16_t(os2->sTypoDescender);
|
2016-08-18 12:43:54 +03:00
|
|
|
double lineGap = int16_t(os2->sTypoLineGap);
|
|
|
|
mMetrics->maxAscent = ROUND(ascent * mFUnitsConvFactor);
|
|
|
|
mMetrics->maxDescent = -ROUND(descent * mFUnitsConvFactor);
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
|
|
|
|
mMetrics->internalLeading = mMetrics->maxHeight - mMetrics->emHeight;
|
2015-05-15 23:30:29 +03:00
|
|
|
gfxFloat lineHeight =
|
2016-08-18 12:43:54 +03:00
|
|
|
ROUND((ascent - descent + lineGap) * mFUnitsConvFactor);
|
|
|
|
lineHeight = std::max(lineHeight, mMetrics->maxHeight);
|
2011-12-07 07:02:53 +04:00
|
|
|
mMetrics->externalLeading = lineHeight - mMetrics->maxHeight;
|
2015-05-15 23:30:29 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-06-01 11:13:29 +03:00
|
|
|
// although sxHeight and sCapHeight are signed fields, we consider
|
2016-08-18 12:43:54 +03:00
|
|
|
// negative values to be erroneous and just ignore them
|
2015-06-01 11:13:29 +03:00
|
|
|
if (uint16_t(os2->version) >= 2) {
|
|
|
|
// version 2 and later includes the x-height and cap-height fields
|
|
|
|
if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
|
|
|
|
int16_t(os2->sxHeight) > 0) {
|
|
|
|
mMetrics->xHeight = ROUND(int16_t(os2->sxHeight) * mFUnitsConvFactor);
|
|
|
|
}
|
|
|
|
if (len >= offsetof(OS2Table, sCapHeight) + sizeof(int16_t) &&
|
|
|
|
int16_t(os2->sCapHeight) > 0) {
|
|
|
|
mMetrics->capHeight =
|
|
|
|
ROUND(int16_t(os2->sCapHeight) * mFUnitsConvFactor);
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
2015-11-02 11:36:50 +03:00
|
|
|
}
|
2011-12-07 07:02:53 +04:00
|
|
|
}
|
2010-05-05 14:10:36 +04:00
|
|
|
|
2013-01-04 22:35:37 +04:00
|
|
|
WORD glyph;
|
2015-06-01 11:13:29 +03:00
|
|
|
SIZE size;
|
2012-02-14 12:24:26 +04:00
|
|
|
DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
|
|
|
|
GGI_MARK_NONEXISTING_GLYPHS);
|
|
|
|
if (ret != GDI_ERROR && glyph != 0xFFFF) {
|
2013-01-04 22:35:37 +04:00
|
|
|
mSpaceGlyph = glyph;
|
2012-02-14 12:24:26 +04:00
|
|
|
// Cache the width of a single space.
|
|
|
|
GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size);
|
2015-06-01 11:13:29 +03:00
|
|
|
mMetrics->spaceWidth = ROUND(size.cx);
|
2012-02-14 12:24:26 +04:00
|
|
|
} else {
|
|
|
|
mMetrics->spaceWidth = mMetrics->aveCharWidth;
|
|
|
|
}
|
|
|
|
|
2010-05-05 14:10:36 +04:00
|
|
|
// Cache the width of digit zero, if available.
|
|
|
|
ret = GetGlyphIndicesW(dc.GetDC(), L"0", 1, &glyph,
|
|
|
|
GGI_MARK_NONEXISTING_GLYPHS);
|
|
|
|
if (ret != GDI_ERROR && glyph != 0xFFFF) {
|
|
|
|
GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size);
|
2019-03-21 07:50:41 +03:00
|
|
|
mMetrics->zeroWidth = ROUND(size.cx);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2019-03-21 07:50:41 +03:00
|
|
|
mMetrics->zeroWidth = -1.0; // indicates not found
|
2010-05-05 14:10:36 +04:00
|
|
|
}
|
|
|
|
|
2011-12-07 07:02:53 +04:00
|
|
|
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2015-11-02 11:36:50 +03:00
|
|
|
mFUnitsConvFactor = 0.0; // zero-sized font: all values scale to zero
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-26 14:46:18 +03:00
|
|
|
if (IsSyntheticBold()) {
|
2012-02-14 12:24:26 +04:00
|
|
|
mMetrics->aveCharWidth += GetSyntheticBoldOffset();
|
|
|
|
mMetrics->maxAdvance += GetSyntheticBoldOffset();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2010-03-31 16:46:18 +04:00
|
|
|
#if 0
|
2011-12-07 07:02:53 +04:00
|
|
|
printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this,
|
2018-09-12 22:34:57 +03:00
|
|
|
GetName().get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no"));
|
2011-12-07 07:02:53 +04:00
|
|
|
printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
|
|
|
|
printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
|
|
|
|
printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
|
2016-08-18 12:43:54 +03:00
|
|
|
printf(" spaceWidth: %f aveCharWidth: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth);
|
|
|
|
printf(" xHeight: %f capHeight: %f\n", mMetrics->xHeight, mMetrics->capHeight);
|
2014-06-28 10:40:36 +04:00
|
|
|
printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
|
|
|
|
mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
|
2010-03-31 16:46:18 +04:00
|
|
|
#endif
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
2017-11-23 22:38:17 +03:00
|
|
|
void gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize) {
|
2010-03-15 12:34:25 +03:00
|
|
|
GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry());
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-16 22:26:08 +03:00
|
|
|
// Figure out the lfWeight value to use for GDI font selection,
|
|
|
|
// or zero to use the entry's current LOGFONT value.
|
|
|
|
LONG weight;
|
2012-02-14 12:24:26 +04:00
|
|
|
if (fe->IsUserFont()) {
|
|
|
|
if (fe->IsLocalUserFont()) {
|
|
|
|
// for local user fonts, don't change the original weight
|
|
|
|
// in the entry's logfont, because that could alter the
|
|
|
|
// choice of actual face used (bug 724231)
|
2018-04-16 22:26:08 +03:00
|
|
|
weight = 0;
|
2012-02-14 12:24:26 +04:00
|
|
|
} else {
|
2018-04-25 09:18:23 +03:00
|
|
|
// avoid GDI synthetic bold which occurs when weight
|
2018-04-26 14:46:18 +03:00
|
|
|
// specified is >= font data weight + 200
|
|
|
|
weight = mNeedsSyntheticBold ? 700 : 200;
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2018-04-25 09:18:23 +03:00
|
|
|
// GDI doesn't support variation fonts, so for system fonts we know
|
|
|
|
// that the entry has only a single weight, not a range.
|
|
|
|
MOZ_ASSERT(fe->Weight().IsSingle());
|
2018-04-26 14:46:18 +03:00
|
|
|
weight = mNeedsSyntheticBold ? 700 : fe->Weight().Min().ToIntRounded();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2017-01-29 05:46:24 +03:00
|
|
|
fe->FillLogFont(&aLogFont, weight, aSize);
|
2010-03-15 12:34:25 +03:00
|
|
|
}
|
|
|
|
|
2014-06-09 18:47:31 +04:00
|
|
|
uint32_t gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector) {
|
|
|
|
// Callback used only for fonts that lack a 'cmap' table.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-06-09 18:47:31 +04:00
|
|
|
// We don't support variation selector sequences or non-BMP characters
|
|
|
|
// in the legacy bitmap, vector or postscript fonts that might use
|
|
|
|
// this code path.
|
|
|
|
if (aUnicode > 0xffff || aVarSelector) {
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-06-09 18:47:31 +04:00
|
|
|
if (!mGlyphIDs) {
|
2016-04-15 22:45:37 +03:00
|
|
|
mGlyphIDs = MakeUnique<nsDataHashtable<nsUint32HashKey, uint32_t>>(64);
|
2014-06-09 18:47:31 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-06-09 18:47:31 +04:00
|
|
|
uint32_t gid;
|
|
|
|
if (mGlyphIDs->Get(aUnicode, &gid)) {
|
|
|
|
return gid;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-06-09 18:47:31 +04:00
|
|
|
wchar_t ch = aUnicode;
|
|
|
|
WORD glyph;
|
2014-06-09 19:43:16 +04:00
|
|
|
DWORD ret = ScriptGetCMap(nullptr, &mScriptCache, &ch, 1, 0, &glyph);
|
2015-08-10 11:39:49 +03:00
|
|
|
if (ret != S_OK) {
|
2014-06-09 19:43:16 +04:00
|
|
|
AutoDC dc;
|
|
|
|
AutoSelectFont fs(dc.GetDC(), GetHFONT());
|
2015-08-10 11:39:49 +03:00
|
|
|
if (ret == E_PENDING) {
|
|
|
|
// Try ScriptGetCMap again now that we've set up the font.
|
|
|
|
ret = ScriptGetCMap(dc.GetDC(), &mScriptCache, &ch, 1, 0, &glyph);
|
2014-06-09 18:47:31 +04:00
|
|
|
}
|
2015-08-10 11:39:49 +03:00
|
|
|
if (ret != S_OK) {
|
|
|
|
// If ScriptGetCMap still failed, fall back to GetGlyphIndicesW
|
|
|
|
// (see bug 1105807).
|
|
|
|
ret = GetGlyphIndicesW(dc.GetDC(), &ch, 1, &glyph,
|
|
|
|
GGI_MARK_NONEXISTING_GLYPHS);
|
|
|
|
if (ret == GDI_ERROR || glyph == 0xFFFF) {
|
|
|
|
glyph = 0;
|
|
|
|
}
|
2014-06-09 18:47:31 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-06-09 18:47:31 +04:00
|
|
|
|
|
|
|
mGlyphIDs->Put(aUnicode, glyph);
|
|
|
|
return glyph;
|
|
|
|
}
|
|
|
|
|
2018-12-31 14:43:27 +03:00
|
|
|
int32_t gfxGDIFont::GetGlyphWidth(uint16_t aGID) {
|
2013-09-02 12:41:57 +04:00
|
|
|
if (!mGlyphWidths) {
|
2016-04-15 22:45:37 +03:00
|
|
|
mGlyphWidths = MakeUnique<nsDataHashtable<nsUint32HashKey, int32_t>>(128);
|
2009-10-07 21:16:52 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t width;
|
2013-09-02 12:41:57 +04:00
|
|
|
if (mGlyphWidths->Get(aGID, &width)) {
|
2009-10-07 21:16:52 +04:00
|
|
|
return width;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-11-26 19:01:19 +03:00
|
|
|
DCForMetrics dc;
|
2011-03-24 23:11:37 +03:00
|
|
|
AutoSelectFont fs(dc, GetHFONT());
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2009-10-07 21:16:52 +04:00
|
|
|
int devWidth;
|
2013-07-31 19:44:31 +04:00
|
|
|
if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
|
2014-06-18 20:46:04 +04:00
|
|
|
// clamp value to range [0..0x7fff], and convert to 16.16 fixed-point
|
|
|
|
devWidth = std::min(std::max(0, devWidth), 0x7fff);
|
|
|
|
width = devWidth << 16;
|
2013-09-02 12:41:57 +04:00
|
|
|
mGlyphWidths->Put(aGID, width);
|
2009-10-07 21:16:52 +04:00
|
|
|
return width;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2009-10-07 21:16:52 +04:00
|
|
|
return -1;
|
|
|
|
}
|
2012-03-23 16:14:16 +04:00
|
|
|
|
2019-09-20 19:30:21 +03:00
|
|
|
bool gfxGDIFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
|
|
|
|
DCForMetrics dc;
|
|
|
|
AutoSelectFont fs(dc, GetHFONT());
|
|
|
|
|
|
|
|
if (mIsBitmap) {
|
|
|
|
int devWidth;
|
|
|
|
if (!GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
devWidth = std::min(std::max(0, devWidth), 0x7fff);
|
|
|
|
|
|
|
|
*aBounds = gfxRect(0, -mMetrics->maxAscent, devWidth,
|
|
|
|
mMetrics->maxAscent + mMetrics->maxDescent);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MAT2 kIdentityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
|
|
|
|
GLYPHMETRICS gm;
|
|
|
|
if (GetGlyphOutlineW(dc, aGID, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr,
|
|
|
|
&kIdentityMatrix) == GDI_ERROR) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gm.gmBlackBoxX == 1 && gm.gmBlackBoxY == 1 &&
|
|
|
|
!GetGlyphOutlineW(dc, aGID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr,
|
|
|
|
&kIdentityMatrix)) {
|
|
|
|
// Workaround for GetGlyphOutline returning 1x1 bounding box
|
|
|
|
// for <space> glyph that is in fact empty.
|
|
|
|
gm.gmBlackBoxX = 0;
|
|
|
|
gm.gmBlackBoxY = 0;
|
|
|
|
} else if (gm.gmBlackBoxX > 0 && !aTight) {
|
|
|
|
// The bounding box reported by Windows supposedly contains the glyph's
|
|
|
|
// "black" area; however, antialiasing (especially with ClearType) means
|
|
|
|
// that the actual image that needs to be rendered may "bleed" into the
|
|
|
|
// adjacent pixels, mainly on the right side.
|
|
|
|
gm.gmptGlyphOrigin.x -= 1;
|
|
|
|
gm.gmBlackBoxX += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aBounds = gfxRect(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
|
|
|
|
gm.gmBlackBoxX, gm.gmBlackBoxY);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:19:47 +04:00
|
|
|
void gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
|
|
|
FontCacheSizes* aSizes) const {
|
|
|
|
gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2013-09-02 12:41:57 +04:00
|
|
|
aSizes->mFontInstances += aMallocSizeOf(mMetrics);
|
|
|
|
if (mGlyphWidths) {
|
|
|
|
aSizes->mFontInstances +=
|
2015-07-31 07:19:57 +03:00
|
|
|
mGlyphWidths->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
2013-09-02 12:41:57 +04:00
|
|
|
}
|
2012-03-23 16:14:16 +04:00
|
|
|
}
|
|
|
|
|
2013-10-15 06:19:47 +04:00
|
|
|
void gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
|
|
|
FontCacheSizes* aSizes) const {
|
2012-03-23 16:14:16 +04:00
|
|
|
aSizes->mFontInstances += aMallocSizeOf(this);
|
2013-10-15 06:19:47 +04:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-23 16:14:16 +04:00
|
|
|
}
|