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/. */
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2013-12-09 06:52:54 +04:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2014-06-30 22:05:29 +04:00
|
|
|
#include "mozilla/Base64.h"
|
2018-04-13 22:34:37 +03:00
|
|
|
#include "mozilla/FontPropertyTypes.h"
|
2013-06-23 16:03:39 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
|
|
|
#include "gfxAndroidPlatform.h"
|
2012-10-03 23:29:10 +04:00
|
|
|
#include "mozilla/Omnijar.h"
|
2015-10-20 20:13:35 +03:00
|
|
|
#include "mozilla/UniquePtr.h"
|
|
|
|
#include "mozilla/UniquePtrExtensions.h"
|
2012-10-03 23:29:10 +04:00
|
|
|
#include "nsIInputStream.h"
|
2018-02-17 02:30:47 +03:00
|
|
|
#include "nsReadableUtils.h"
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
#include "nsXULAppAPI.h"
|
2011-09-23 15:15:36 +04:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <android/log.h>
|
|
|
|
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko", ##args)
|
|
|
|
|
2011-09-23 13:34:42 +04:00
|
|
|
#include "ft2build.h"
|
|
|
|
#include FT_FREETYPE_H
|
2011-09-23 15:16:13 +04:00
|
|
|
#include FT_TRUETYPE_TAGS_H
|
|
|
|
#include FT_TRUETYPE_TABLES_H
|
2018-01-31 20:07:49 +03:00
|
|
|
#include FT_MULTIPLE_MASTERS_H
|
2011-09-23 15:16:13 +04:00
|
|
|
#include "cairo-ft.h"
|
|
|
|
|
|
|
|
#include "gfxFT2FontList.h"
|
2011-09-23 13:34:42 +04:00
|
|
|
#include "gfxFT2Fonts.h"
|
2018-01-31 20:07:49 +03:00
|
|
|
#include "gfxFT2Utils.h"
|
2011-09-23 15:16:13 +04:00
|
|
|
#include "gfxUserFontSet.h"
|
|
|
|
#include "gfxFontUtils.h"
|
2011-09-23 13:34:42 +04:00
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2016-09-28 22:42:41 +03:00
|
|
|
#include "nsIObserverService.h"
|
2009-10-07 18:13:40 +04:00
|
|
|
#include "nsTArray.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
2016-09-28 22:42:41 +03:00
|
|
|
#include "nsCRT.h"
|
2009-10-07 18:13:40 +04:00
|
|
|
|
|
|
|
#include "nsDirectoryServiceUtils.h"
|
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsISimpleEnumerator.h"
|
2013-08-13 01:44:56 +04:00
|
|
|
#include "nsIMemory.h"
|
2013-10-08 03:15:59 +04:00
|
|
|
#include "gfxFontConstants.h"
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2011-09-23 15:15:36 +04:00
|
|
|
#include "mozilla/scache/StartupCache.h"
|
2014-06-30 22:05:29 +04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/mman.h>
|
2011-09-23 15:15:36 +04:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2011-10-11 09:50:08 +04:00
|
|
|
using namespace mozilla;
|
2017-04-07 00:41:02 +03:00
|
|
|
using namespace mozilla::gfx;
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2015-10-30 01:34:06 +03:00
|
|
|
static LazyLogModule sFontInfoLog("fontInfoLog");
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
#undef LOG
|
2015-10-30 01:34:06 +03:00
|
|
|
#define LOG(args) MOZ_LOG(sFontInfoLog, mozilla::LogLevel::Debug, args)
|
|
|
|
#define LOG_ENABLED() MOZ_LOG_TEST(sFontInfoLog, mozilla::LogLevel::Debug)
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
static cairo_user_data_key_t sFTUserFontDataKey;
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
static __inline void BuildKeyNameFromFontName(nsACString& aName) {
|
2009-10-07 18:13:40 +04:00
|
|
|
ToLowerCase(aName);
|
|
|
|
}
|
|
|
|
|
2013-03-04 21:03:14 +04:00
|
|
|
// Helper to access the FT_Face for a given FT2FontEntry,
|
|
|
|
// creating a temporary face if the entry does not have one yet.
|
|
|
|
// This allows us to read font names, tables, etc if necessary
|
|
|
|
// without permanently instantiating a freetype face and consuming
|
|
|
|
// memory long-term.
|
2013-06-25 12:14:03 +04:00
|
|
|
// This may fail (resulting in a null FT_Face), e.g. if it fails to
|
|
|
|
// allocate memory to uncompress a font from omnijar.
|
2013-03-04 21:03:14 +04:00
|
|
|
class AutoFTFace {
|
|
|
|
public:
|
2018-03-27 17:51:32 +03:00
|
|
|
explicit AutoFTFace(FT2FontEntry* aFontEntry)
|
2018-06-15 02:42:56 +03:00
|
|
|
: mFace(nullptr),
|
|
|
|
mFontDataBuf(nullptr),
|
|
|
|
mDataLength(0),
|
|
|
|
mOwnsFace(false) {
|
2015-09-24 18:31:30 +03:00
|
|
|
if (aFontEntry->mFTFace) {
|
2017-05-18 04:56:24 +03:00
|
|
|
mFace = aFontEntry->mFTFace;
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
NS_ASSERTION(!aFontEntry->mFilename.IsEmpty(),
|
|
|
|
"can't use AutoFTFace for fonts without a filename");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// A relative path (no initial "/") means this is a resource in
|
|
|
|
// omnijar, not an installed font on the device.
|
|
|
|
// The NS_ASSERTIONs here should never fail, as the resource must have
|
|
|
|
// been read successfully during font-list initialization or we'd never
|
|
|
|
// have created the font entry. The only legitimate runtime failure
|
|
|
|
// here would be memory allocation, in which case mFace remains null.
|
|
|
|
if (aFontEntry->mFilename[0] != '/') {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE);
|
2013-06-25 12:14:03 +04:00
|
|
|
nsZipItem* item = reader->GetItem(aFontEntry->mFilename.get());
|
|
|
|
NS_ASSERTION(item, "failed to find zip entry");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
uint32_t bufSize = item->RealSize();
|
2015-02-19 07:51:06 +03:00
|
|
|
mFontDataBuf = static_cast<uint8_t*>(malloc(bufSize));
|
2013-06-25 12:14:03 +04:00
|
|
|
if (mFontDataBuf) {
|
|
|
|
nsZipCursor cursor(item, reader, mFontDataBuf, bufSize);
|
|
|
|
cursor.Copy(&bufSize);
|
|
|
|
NS_ASSERTION(bufSize == item->RealSize(), "error reading bundled font");
|
2018-01-31 20:07:49 +03:00
|
|
|
mDataLength = bufSize;
|
2018-06-15 02:42:56 +03:00
|
|
|
mFace = Factory::NewFTFaceFromData(nullptr, mFontDataBuf, bufSize,
|
2013-03-04 21:03:14 +04:00
|
|
|
aFontEntry->mFTFontIndex);
|
|
|
|
if (!mFace) {
|
|
|
|
NS_WARNING("failed to create freetype face");
|
2013-06-25 12:14:03 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2013-06-25 12:14:03 +04:00
|
|
|
} else {
|
|
|
|
mFace = Factory::NewFTFace(nullptr, aFontEntry->mFilename.get(),
|
|
|
|
aFontEntry->mFTFontIndex);
|
2017-05-18 04:56:24 +03:00
|
|
|
if (!mFace) {
|
2013-06-25 12:14:03 +04:00
|
|
|
NS_WARNING("failed to create freetype face");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2015-02-19 07:51:06 +03:00
|
|
|
if (FT_Err_Ok != FT_Select_Charmap(mFace, FT_ENCODING_UNICODE)) {
|
|
|
|
NS_WARNING("failed to select Unicode charmap");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-02-19 07:51:06 +03:00
|
|
|
mOwnsFace = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2013-03-04 21:03:14 +04:00
|
|
|
~AutoFTFace() {
|
|
|
|
if (mFace && mOwnsFace) {
|
2015-02-19 07:51:06 +03:00
|
|
|
Factory::ReleaseFTFace(mFace);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (mFontDataBuf) {
|
2017-05-18 04:56:24 +03:00
|
|
|
free(mFontDataBuf);
|
2013-03-04 21:03:14 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
operator FT_Face() { return mFace; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// If we 'forget' the FT_Face (used when ownership is handed over to Cairo),
|
|
|
|
// we do -not- free the mFontDataBuf (if used); that also becomes the
|
|
|
|
// responsibility of the new owner of the face.
|
2013-03-04 21:03:14 +04:00
|
|
|
FT_Face forget() {
|
|
|
|
NS_ASSERTION(mOwnsFace, "can't forget() when we didn't own the face");
|
|
|
|
mOwnsFace = false;
|
|
|
|
return mFace;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
const uint8_t* FontData() const { return mFontDataBuf; }
|
2018-01-31 20:07:49 +03:00
|
|
|
uint32_t DataLength() const { return mDataLength; }
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-03-04 21:03:14 +04:00
|
|
|
private:
|
2013-06-25 12:14:03 +04:00
|
|
|
FT_Face mFace;
|
|
|
|
uint8_t* mFontDataBuf; // Uncompressed data (for fonts stored in a JAR),
|
|
|
|
// or null for fonts instantiated from a file.
|
|
|
|
// If non-null, this must survive as long as the
|
|
|
|
// FT_Face.
|
2018-01-31 20:07:49 +03:00
|
|
|
uint32_t mDataLength; // Size of mFontDataBuf, if present.
|
2013-06-25 12:14:03 +04:00
|
|
|
bool mOwnsFace;
|
2013-03-04 21:03:14 +04:00
|
|
|
};
|
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
/*
|
|
|
|
* FT2FontEntry
|
|
|
|
* gfxFontEntry subclass corresponding to a specific face that can be
|
|
|
|
* rendered by freetype. This is associated with a face index in a
|
|
|
|
* file (normally a .ttf/.otf file holding a single face, but in principle
|
|
|
|
* there could be .ttc files with multiple faces).
|
|
|
|
* The FT2FontEntry can create the necessary FT_Face on demand, and can
|
|
|
|
* then create a Cairo font_face and scaled_font for drawing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
cairo_scaled_font_t* FT2FontEntry::CreateScaledFont(
|
|
|
|
const gfxFontStyle* aStyle) {
|
2018-01-31 20:07:49 +03:00
|
|
|
cairo_font_face_t* cairoFace = CairoFontFace(aStyle);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (!cairoFace) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_scaled_font_t* scaledFont = nullptr;
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
cairo_matrix_t sizeMatrix;
|
|
|
|
cairo_matrix_t identityMatrix;
|
|
|
|
|
|
|
|
// XXX deal with adjusted size
|
|
|
|
cairo_matrix_init_scale(&sizeMatrix, aStyle->size, aStyle->size);
|
|
|
|
cairo_matrix_init_identity(&identityMatrix);
|
|
|
|
|
|
|
|
cairo_font_options_t* fontOptions = cairo_font_options_create();
|
|
|
|
|
2013-01-15 19:19:28 +04:00
|
|
|
if (gfxPlatform::GetPlatform()->RequiresLinearZoom()) {
|
2012-02-09 02:52:57 +04:00
|
|
|
cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF);
|
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
scaledFont = cairo_scaled_font_create(cairoFace, &sizeMatrix, &identityMatrix,
|
2011-09-23 15:16:13 +04:00
|
|
|
fontOptions);
|
|
|
|
cairo_font_options_destroy(fontOptions);
|
|
|
|
|
|
|
|
NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
|
|
|
|
"Failed to make scaled font");
|
|
|
|
|
|
|
|
return scaledFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
FT2FontEntry::~FT2FontEntry() {
|
2018-08-02 00:39:05 +03:00
|
|
|
if (mMMVar) {
|
|
|
|
FT_Done_MM_Var(mFTFace->glyph->library, mMMVar);
|
|
|
|
}
|
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
// Do nothing for mFTFace here since FTFontDestroyFunc is called by cairo.
|
2012-07-30 18:20:58 +04:00
|
|
|
mFTFace = nullptr;
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
#ifndef ANDROID
|
|
|
|
if (mFontFace) {
|
|
|
|
cairo_font_face_destroy(mFontFace);
|
2012-07-30 18:20:58 +04:00
|
|
|
mFontFace = nullptr;
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-08-01 13:25:35 +03:00
|
|
|
gfxFontEntry* FT2FontEntry::Clone() const {
|
|
|
|
MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
|
|
|
|
FT2FontEntry* fe = new FT2FontEntry(Name());
|
|
|
|
fe->mFilename = mFilename;
|
|
|
|
fe->mFTFontIndex = mFTFontIndex;
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mWeightRange = mWeightRange;
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mStretchRange = mStretchRange;
|
|
|
|
fe->mStyleRange = mStyleRange;
|
2017-08-01 13:25:35 +03:00
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
2018-06-15 02:42:56 +03:00
|
|
|
static cairo_user_data_key_t sFTFaceKey;
|
|
|
|
|
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
|
|
|
gfxFont* FT2FontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) {
|
2011-09-23 15:16:13 +04:00
|
|
|
cairo_scaled_font_t* scaledFont = CreateScaledFont(aFontStyle);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (!scaledFont) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-10-18 21:22:09 +03:00
|
|
|
RefPtr<UnscaledFontFreeType> unscaledFont(mUnscaledFont);
|
2017-04-07 00:41:02 +03:00
|
|
|
if (!unscaledFont) {
|
|
|
|
unscaledFont =
|
2018-06-15 02:42:56 +03:00
|
|
|
!mFilename.IsEmpty() && mFilename[0] == '/'
|
2017-04-07 00:41:02 +03:00
|
|
|
? new UnscaledFontFreeType(mFilename.BeginReading(), mFTFontIndex)
|
2018-06-15 02:42:56 +03:00
|
|
|
: new UnscaledFontFreeType(mFTFace);
|
2017-04-07 00:41:02 +03:00
|
|
|
mUnscaledFont = unscaledFont;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-06-15 02:42:56 +03:00
|
|
|
cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaledFont);
|
|
|
|
FT_Face ftFace =
|
|
|
|
static_cast<FT_Face>(cairo_font_face_get_user_data(face, &sFTFaceKey));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-06-15 02:42:56 +03:00
|
|
|
gfxFont* font = new gfxFT2Font(unscaledFont, scaledFont,
|
|
|
|
ftFace ? ftFace : mFTFace, this, aFontStyle);
|
2011-09-23 15:16:13 +04:00
|
|
|
cairo_scaled_font_destroy(scaledFont);
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
2018-09-12 22:34:57 +03:00
|
|
|
FT2FontEntry* FT2FontEntry::CreateFontEntry(
|
|
|
|
const nsACString& aFontName, WeightRange aWeight, StretchRange aStretch,
|
2014-09-08 11:23:19 +04:00
|
|
|
SlantStyleRange aStyle, const uint8_t* aFontData, uint32_t aLength) {
|
2011-09-23 15:16:13 +04:00
|
|
|
// Ownership of aFontData is passed in here; the fontEntry must
|
|
|
|
// retain it as long as the FT_Face needs it, and ensure it is
|
|
|
|
// eventually deleted.
|
2017-05-18 04:56:24 +03:00
|
|
|
FT_Face face = Factory::NewFTFaceFromData(nullptr, aFontData, aLength, 0);
|
|
|
|
if (!face) {
|
2015-04-01 08:29:55 +03:00
|
|
|
free((void*)aFontData);
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
2012-05-22 01:09:54 +04:00
|
|
|
if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE)) {
|
2017-05-18 04:56:24 +03:00
|
|
|
Factory::ReleaseFTFace(face);
|
2015-04-01 08:29:55 +03:00
|
|
|
free((void*)aFontData);
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-05-22 01:09:54 +04:00
|
|
|
}
|
2014-09-08 11:23:20 +04:00
|
|
|
// Create our FT2FontEntry, which inherits the name of the userfont entry
|
2012-05-24 12:15:54 +04:00
|
|
|
// as it's not guaranteed that the face has valid names (bug 737315)
|
2014-09-08 11:23:19 +04:00
|
|
|
FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(face, nullptr, 0, aFontName,
|
2018-01-31 20:07:49 +03:00
|
|
|
aFontData, aLength);
|
2011-09-23 15:16:13 +04:00
|
|
|
if (fe) {
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mStyleRange = aStyle;
|
|
|
|
fe->mWeightRange = aWeight;
|
|
|
|
fe->mStretchRange = aStretch;
|
2014-09-08 11:23:20 +04:00
|
|
|
fe->mIsDataUserFont = true;
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
|
|
|
class FTUserFontData {
|
|
|
|
public:
|
2018-01-31 20:07:49 +03:00
|
|
|
FTUserFontData(FT_Face aFace, const uint8_t* aData, uint32_t aLength)
|
|
|
|
: mFace(aFace), mFontData(aData), mLength(aLength) {}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
~FTUserFontData() {
|
2017-05-18 04:56:24 +03:00
|
|
|
Factory::ReleaseFTFace(mFace);
|
2011-09-23 15:16:13 +04:00
|
|
|
if (mFontData) {
|
2015-04-01 08:29:55 +03:00
|
|
|
free((void*)mFontData);
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
const uint8_t* FontData() const { return mFontData; }
|
2018-01-31 20:07:49 +03:00
|
|
|
uint32_t Length() const { return mLength; }
|
2013-06-25 12:14:03 +04:00
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
private:
|
|
|
|
FT_Face mFace;
|
2012-08-22 19:56:38 +04:00
|
|
|
const uint8_t* mFontData;
|
2018-01-31 20:07:49 +03:00
|
|
|
uint32_t mLength;
|
2011-09-23 15:16:13 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static void FTFontDestroyFunc(void* data) {
|
|
|
|
FTUserFontData* userFontData = static_cast<FTUserFontData*>(data);
|
|
|
|
delete userFontData;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
FT2FontEntry* FT2FontEntry::CreateFontEntry(const FontListEntry& aFLE) {
|
|
|
|
FT2FontEntry* fe = new FT2FontEntry(aFLE.faceName());
|
|
|
|
fe->mFilename = aFLE.filepath();
|
|
|
|
fe->mFTFontIndex = aFLE.index();
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mWeightRange = WeightRange::FromScalar(aFLE.weightRange());
|
|
|
|
fe->mStretchRange = StretchRange::FromScalar(aFLE.stretchRange());
|
|
|
|
fe->mStyleRange = SlantStyleRange::FromScalar(aFLE.styleRange());
|
2011-09-23 15:16:13 +04:00
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
2013-03-04 21:03:11 +04:00
|
|
|
// Helpers to extract font entry properties from an FT_Face
|
|
|
|
static bool FTFaceIsItalic(FT_Face aFace) {
|
|
|
|
return !!(aFace->style_flags & FT_STYLE_FLAG_ITALIC);
|
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2013-03-04 21:03:11 +04:00
|
|
|
static FontWeight FTFaceGetWeight(FT_Face aFace) {
|
2011-09-23 15:16:13 +04:00
|
|
|
TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(aFace, ft_sfnt_os2));
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t os2weight = 0;
|
2011-09-23 15:16:13 +04:00
|
|
|
if (os2 && os2->version != 0xffff) {
|
|
|
|
// Technically, only 100 to 900 are valid, but some fonts
|
|
|
|
// have this set wrong -- e.g. "Microsoft Logo Bold Italic" has
|
|
|
|
// it set to 6 instead of 600. We try to be nice and handle that
|
|
|
|
// as well.
|
2013-03-04 21:03:11 +04:00
|
|
|
if (os2->usWeightClass >= 100 && os2->usWeightClass <= 900) {
|
2011-09-23 15:16:13 +04:00
|
|
|
os2weight = os2->usWeightClass;
|
2013-03-04 21:03:11 +04:00
|
|
|
} else if (os2->usWeightClass >= 1 && os2->usWeightClass <= 9) {
|
2011-09-23 15:16:13 +04:00
|
|
|
os2weight = os2->usWeightClass * 100;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2013-03-04 21:03:11 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-03-04 21:03:11 +04:00
|
|
|
uint16_t result;
|
|
|
|
if (os2weight != 0) {
|
|
|
|
result = os2weight;
|
|
|
|
} else if (aFace->style_flags & FT_STYLE_FLAG_BOLD) {
|
|
|
|
result = 700;
|
|
|
|
} else {
|
|
|
|
result = 400;
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-03-04 21:03:11 +04:00
|
|
|
NS_ASSERTION(result >= 100 && result <= 900, "Invalid weight in font!");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-16 22:26:08 +03:00
|
|
|
return FontWeight(int(result));
|
2013-03-04 21:03:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Used to create the font entry for installed faces on the device,
|
|
|
|
// when iterating over the fonts directories.
|
|
|
|
// We use the FT_Face to retrieve the details needed for the font entry,
|
|
|
|
// but unless we have been passed font data (i.e. for a user font),
|
|
|
|
// we do *not* save a reference to it, nor create a cairo face,
|
|
|
|
// as we don't want to keep a freetype face for every installed font
|
|
|
|
// permanently in memory.
|
|
|
|
/* static */
|
|
|
|
FT2FontEntry* FT2FontEntry::CreateFontEntry(
|
|
|
|
FT_Face aFace, const char* aFilename, uint8_t aIndex,
|
2018-01-31 20:07:49 +03:00
|
|
|
const nsACString& aName, const uint8_t* aFontData, uint32_t aLength) {
|
2013-03-04 21:03:11 +04:00
|
|
|
FT2FontEntry* fe = new FT2FontEntry(aName);
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mStyleRange =
|
|
|
|
SlantStyleRange(FTFaceIsItalic(aFace) ? FontSlantStyle::Italic()
|
|
|
|
: FontSlantStyle::Normal());
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mWeightRange = WeightRange(FTFaceGetWeight(aFace));
|
2013-03-04 21:03:11 +04:00
|
|
|
fe->mFilename = aFilename;
|
|
|
|
fe->mFTFontIndex = aIndex;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-03-04 21:03:11 +04:00
|
|
|
if (aFontData) {
|
|
|
|
fe->mFTFace = aFace;
|
|
|
|
int flags = gfxPlatform::GetPlatform()->FontHintingEnabled()
|
|
|
|
? FT_LOAD_DEFAULT
|
|
|
|
: (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
2017-12-07 16:22:49 +03:00
|
|
|
fe->mFontFace =
|
|
|
|
cairo_ft_font_face_create_for_ft_face(aFace, flags, nullptr, 0);
|
2018-01-31 20:07:49 +03:00
|
|
|
FTUserFontData* userFontData =
|
|
|
|
new FTUserFontData(aFace, aFontData, aLength);
|
2013-06-25 12:14:03 +04:00
|
|
|
cairo_font_face_set_user_data(fe->mFontFace, &sFTUserFontDataKey,
|
2013-03-04 21:03:11 +04:00
|
|
|
userFontData, FTFontDestroyFunc);
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
2012-05-24 12:15:54 +04:00
|
|
|
// construct font entry name for an installed font from names in the FT_Face,
|
|
|
|
// and then create our FT2FontEntry
|
2012-08-22 19:56:38 +04:00
|
|
|
static FT2FontEntry* CreateNamedFontEntry(FT_Face aFace, const char* aFilename,
|
|
|
|
uint8_t aIndex) {
|
2012-05-24 12:15:54 +04:00
|
|
|
if (!aFace->family_name) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-05-24 12:15:54 +04:00
|
|
|
}
|
2018-09-12 22:34:57 +03:00
|
|
|
nsAutoCString fontName(aFace->family_name);
|
2012-05-24 12:15:54 +04:00
|
|
|
if (aFace->style_name && strcmp("Regular", aFace->style_name)) {
|
2014-05-22 07:48:51 +04:00
|
|
|
fontName.Append(' ');
|
2018-09-12 22:34:57 +03:00
|
|
|
fontName.Append(aFace->style_name);
|
2012-05-24 12:15:54 +04:00
|
|
|
}
|
|
|
|
return FT2FontEntry::CreateFontEntry(aFace, aFilename, aIndex, fontName);
|
|
|
|
}
|
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
FT2FontEntry* gfxFT2Font::GetFontEntry() {
|
|
|
|
return static_cast<FT2FontEntry*>(mFontEntry.get());
|
|
|
|
}
|
|
|
|
|
2018-01-31 20:07:49 +03:00
|
|
|
cairo_font_face_t* FT2FontEntry::CairoFontFace(const gfxFontStyle* aStyle) {
|
|
|
|
// Create our basic (no-variations) mFontFace if not already present;
|
|
|
|
// this also ensures we have mFTFace available.
|
2011-09-23 15:16:13 +04:00
|
|
|
if (!mFontFace) {
|
2013-03-04 21:03:14 +04:00
|
|
|
AutoFTFace face(this);
|
|
|
|
if (!face) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-05-22 01:09:54 +04:00
|
|
|
}
|
2012-02-09 02:52:57 +04:00
|
|
|
int flags = gfxPlatform::GetPlatform()->FontHintingEnabled()
|
|
|
|
? FT_LOAD_DEFAULT
|
|
|
|
: (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
2018-01-31 20:07:49 +03:00
|
|
|
mFontFace = cairo_ft_font_face_create_for_ft_face(face, flags, nullptr, 0);
|
|
|
|
auto userFontData =
|
|
|
|
new FTUserFontData(face, face.FontData(), face.DataLength());
|
2013-06-25 12:14:03 +04:00
|
|
|
cairo_font_face_set_user_data(mFontFace, &sFTUserFontDataKey, userFontData,
|
2011-09-23 15:16:13 +04:00
|
|
|
FTFontDestroyFunc);
|
2018-01-31 20:07:49 +03:00
|
|
|
mFTFace = face.forget();
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-02-14 14:02:05 +03:00
|
|
|
// If variations are present, we will not use our cached mFontFace
|
|
|
|
// but always create a new cairo_font_face_t because its FT_Face will
|
|
|
|
// have custom variation coordinates applied.
|
|
|
|
if ((!mVariationSettings.IsEmpty() ||
|
2018-04-25 09:18:23 +03:00
|
|
|
(aStyle && !aStyle->variationSettings.IsEmpty())) &&
|
2018-02-14 14:02:05 +03:00
|
|
|
(mFTFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
|
2018-01-31 20:07:49 +03:00
|
|
|
int flags = gfxPlatform::GetPlatform()->FontHintingEnabled()
|
|
|
|
? FT_LOAD_DEFAULT
|
|
|
|
: (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
2018-02-14 14:02:05 +03:00
|
|
|
// Resolve variations from entry (descriptor) and style (property)
|
2018-04-25 09:18:23 +03:00
|
|
|
AutoTArray<gfxFontVariation, 8> settings;
|
|
|
|
GetVariationsForStyle(settings, aStyle ? *aStyle : gfxFontStyle());
|
2018-01-31 20:07:49 +03:00
|
|
|
AutoTArray<FT_Fixed, 8> coords;
|
2018-08-02 00:39:05 +03:00
|
|
|
gfxFT2FontBase::SetupVarCoords(GetMMVar(), settings, &coords);
|
2018-01-31 20:07:49 +03:00
|
|
|
// Create a separate FT_Face because we need to apply custom
|
|
|
|
// variation settings to it.
|
|
|
|
FT_Face ftFace;
|
2018-06-15 02:42:56 +03:00
|
|
|
if (!mFilename.IsEmpty() && mFilename[0] == '/') {
|
2018-01-31 20:07:49 +03:00
|
|
|
ftFace = Factory::NewFTFace(nullptr, mFilename.get(), mFTFontIndex);
|
|
|
|
} else {
|
|
|
|
auto ufd = reinterpret_cast<FTUserFontData*>(
|
|
|
|
cairo_font_face_get_user_data(mFontFace, &sFTUserFontDataKey));
|
|
|
|
ftFace = Factory::NewFTFaceFromData(nullptr, ufd->FontData(),
|
|
|
|
ufd->Length(), mFTFontIndex);
|
|
|
|
}
|
2018-02-14 14:02:05 +03:00
|
|
|
// The variation coordinates will actually be applied to ftFace by
|
|
|
|
// gfxFT2FontBase::InitMetrics, so we don't need to do it here.
|
2018-01-31 20:07:49 +03:00
|
|
|
cairo_font_face_t* cairoFace = cairo_ft_font_face_create_for_ft_face(
|
|
|
|
ftFace, flags, coords.Elements(), coords.Length());
|
|
|
|
// Set up user data to properly release the FT_Face when the cairo face
|
|
|
|
// is deleted.
|
2018-06-15 02:42:56 +03:00
|
|
|
if (cairo_font_face_set_user_data(
|
|
|
|
cairoFace, &sFTFaceKey, ftFace,
|
2018-01-31 20:07:49 +03:00
|
|
|
(cairo_destroy_func_t)&Factory::ReleaseFTFace)) {
|
|
|
|
// set_user_data failed! discard, and fall back to default face
|
|
|
|
cairo_font_face_destroy(cairoFace);
|
|
|
|
FT_Done_Face(ftFace);
|
|
|
|
} else {
|
|
|
|
return cairoFace;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-01-31 20:07:49 +03:00
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
return mFontFace;
|
|
|
|
}
|
|
|
|
|
2014-05-05 22:59:55 +04:00
|
|
|
// Copied/modified from similar code in gfxMacPlatformFontList.mm:
|
|
|
|
// Complex scripts will not render correctly unless Graphite or OT
|
|
|
|
// layout tables are present.
|
|
|
|
// For OpenType, we also check that the GSUB table supports the relevant
|
|
|
|
// script tag, to avoid using things like Arial Unicode MS for Lao (it has
|
|
|
|
// the characters, but lacks OpenType support).
|
|
|
|
|
|
|
|
// TODO: consider whether we should move this to gfxFontEntry and do similar
|
|
|
|
// cmap-masking on all platforms to avoid using fonts that won't shape
|
|
|
|
// properly.
|
|
|
|
|
2014-01-29 11:39:01 +04:00
|
|
|
nsresult FT2FontEntry::ReadCMAP(FontInfoData* aFontInfoData) {
|
2012-04-19 03:59:43 +04:00
|
|
|
if (mCharacterMap) {
|
2011-09-23 15:16:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<uint8_t, 16384> buffer;
|
2013-05-16 20:29:20 +04:00
|
|
|
nsresult rv = CopyFontTable(TTAG_cmap, buffer);
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2018-03-26 15:25:11 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2014-05-05 22:59:55 +04:00
|
|
|
rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(), *charmap,
|
|
|
|
mUVSOffset);
|
|
|
|
}
|
|
|
|
|
2014-06-02 15:46:49 +04:00
|
|
|
if (NS_SUCCEEDED(rv) && !mIsDataUserFont && !HasGraphiteTables()) {
|
|
|
|
// For downloadable fonts, trust the author and don't
|
|
|
|
// try to munge the cmap based on script shaping support.
|
|
|
|
|
2012-04-19 03:59:43 +04:00
|
|
|
// We also assume a Graphite font knows what it's doing,
|
|
|
|
// and provides whatever shaping is needed for the
|
|
|
|
// characters it supports, so only check/clear the
|
|
|
|
// complex-script ranges for non-Graphite fonts
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
// for layout support, check for the presence of opentype layout tables
|
|
|
|
bool hasGSUB = HasFontTable(TRUETYPE_TAG('G', 'S', 'U', 'B'));
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2013-03-04 21:03:14 +04:00
|
|
|
for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges;
|
|
|
|
sr->rangeStart; sr++) {
|
2012-05-24 12:16:01 +04:00
|
|
|
// check to see if the cmap includes complex script codepoints
|
|
|
|
if (charmap->TestRange(sr->rangeStart, sr->rangeEnd)) {
|
|
|
|
// We check for GSUB here, as GPOS alone would not be ok.
|
2018-12-08 16:44:55 +03:00
|
|
|
if (hasGSUB && SupportsScriptInGSUB(sr->tags, sr->numTags)) {
|
2012-05-24 12:16:01 +04:00
|
|
|
continue;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2012-05-24 12:16:01 +04:00
|
|
|
charmap->ClearRange(sr->rangeStart, sr->rangeEnd);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2012-05-24 12:16:01 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
2013-03-04 21:03:14 +04:00
|
|
|
// Hack for the SamsungDevanagari font, bug 1012365:
|
2012-05-24 12:16:01 +04:00
|
|
|
// pretend the font supports U+0972.
|
2014-06-02 15:46:49 +04:00
|
|
|
if (!charmap->test(0x0972) && charmap->test(0x0905) &&
|
2012-05-24 12:16:01 +04:00
|
|
|
charmap->test(0x0945)) {
|
|
|
|
charmap->set(0x0972);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
#endif
|
2011-09-23 15:16:13 +04:00
|
|
|
|
|
|
|
mHasCmapTable = NS_SUCCEEDED(rv);
|
2012-04-19 03:59:43 +04:00
|
|
|
if (mHasCmapTable) {
|
|
|
|
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
|
|
|
|
mCharacterMap = pfl->FindCharMap(charmap);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2012-04-19 03:59:43 +04:00
|
|
|
// if error occurred, initialize to null cmap
|
|
|
|
mCharacterMap = new gfxCharacterMap();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
nsresult FT2FontEntry::CopyFontTable(uint32_t aTableTag,
|
|
|
|
nsTArray<uint8_t>& aBuffer) {
|
|
|
|
AutoFTFace face(this);
|
|
|
|
if (!face) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
FT_Error status;
|
|
|
|
FT_ULong len = 0;
|
|
|
|
status = FT_Load_Sfnt_Table(face, aTableTag, 0, nullptr, &len);
|
|
|
|
if (status != FT_Err_Ok || len == 0) {
|
2016-08-19 15:57:05 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2016-08-19 15:57:05 +03:00
|
|
|
if (!aBuffer.SetLength(len, fallible)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-08-19 15:57:05 +03:00
|
|
|
uint8_t* buf = aBuffer.Elements();
|
|
|
|
status = FT_Load_Sfnt_Table(face, aTableTag, 0, buf, &len);
|
2012-05-24 12:16:01 +04:00
|
|
|
NS_ENSURE_TRUE(status == FT_Err_Ok, NS_ERROR_FAILURE);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
return NS_OK;
|
2013-06-25 12:14:03 +04:00
|
|
|
}
|
|
|
|
|
2017-07-06 17:06:45 +03:00
|
|
|
hb_blob_t* FT2FontEntry::GetFontTable(uint32_t aTableTag) {
|
2015-09-24 18:31:30 +03:00
|
|
|
if (mFontFace) {
|
2013-06-25 12:14:03 +04:00
|
|
|
// if there's a cairo font face, we may be able to return a blob
|
|
|
|
// that just wraps a range of the attached user font data
|
|
|
|
FTUserFontData* userFontData = static_cast<FTUserFontData*>(
|
|
|
|
cairo_font_face_get_user_data(mFontFace, &sFTUserFontDataKey));
|
|
|
|
if (userFontData && userFontData->FontData()) {
|
2016-08-19 15:57:05 +03:00
|
|
|
return gfxFontUtils::GetTableFromFontData(userFontData->FontData(),
|
2013-03-04 21:03:14 +04:00
|
|
|
aTableTag);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// otherwise, use the default method (which in turn will call our
|
|
|
|
// implementation of CopyFontTable)
|
|
|
|
return gfxFontEntry::GetFontTable(aTableTag);
|
|
|
|
}
|
|
|
|
|
2018-04-26 19:08:18 +03:00
|
|
|
bool FT2FontEntry::HasVariations() {
|
|
|
|
if (mHasVariationsInitialized) {
|
|
|
|
return mHasVariations;
|
|
|
|
}
|
|
|
|
mHasVariationsInitialized = true;
|
|
|
|
|
|
|
|
AutoFTFace face(this);
|
|
|
|
if (face) {
|
|
|
|
mHasVariations = FT_Face(face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mHasVariations;
|
|
|
|
}
|
|
|
|
|
2018-04-26 19:08:18 +03:00
|
|
|
void FT2FontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes) {
|
|
|
|
if (!HasVariations()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-08-02 00:39:05 +03:00
|
|
|
FT_MM_Var* mmVar = GetMMVar();
|
|
|
|
if (!mmVar) {
|
2018-04-26 19:08:18 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
gfxFT2Utils::GetVariationAxes(mmVar, aAxes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FT2FontEntry::GetVariationInstances(
|
|
|
|
nsTArray<gfxFontVariationInstance>& aInstances) {
|
|
|
|
if (!HasVariations()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-08-02 00:39:05 +03:00
|
|
|
FT_MM_Var* mmVar = GetMMVar();
|
|
|
|
if (!mmVar) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gfxFT2Utils::GetVariationInstances(this, mmVar, aInstances);
|
|
|
|
}
|
|
|
|
|
|
|
|
FT_MM_Var* FT2FontEntry::GetMMVar() {
|
|
|
|
if (mMMVarInitialized) {
|
|
|
|
return mMMVar;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-08-02 00:39:05 +03:00
|
|
|
mMMVarInitialized = true;
|
2013-03-04 21:03:14 +04:00
|
|
|
AutoFTFace face(this);
|
|
|
|
if (!face) {
|
2018-08-02 00:39:05 +03:00
|
|
|
return nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-08-02 00:39:05 +03:00
|
|
|
if (FT_Err_Ok != FT_Get_MM_Var(face, &mMMVar)) {
|
|
|
|
mMMVar = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-08-02 00:39:05 +03:00
|
|
|
return mMMVar;
|
2018-04-26 19:08:18 +03:00
|
|
|
}
|
|
|
|
|
2013-10-15 06:19:47 +04:00
|
|
|
void FT2FontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const {
|
|
|
|
gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
aSizes->mFontListSize +=
|
|
|
|
mFilename.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:19:47 +04:00
|
|
|
void FT2FontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const {
|
2012-03-28 01:38:39 +04:00
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
2013-10-15 06:19:47 +04:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
}
|
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
/*
|
|
|
|
* FT2FontFamily
|
|
|
|
* A standard gfxFontFamily; just adds a method used to support sending
|
|
|
|
* the font list from chrome to content via IPC.
|
|
|
|
*/
|
|
|
|
|
2017-07-06 17:06:45 +03:00
|
|
|
void FT2FontFamily::AddFacesToFontList(
|
|
|
|
InfallibleTArray<FontListEntry>* aFontList) {
|
2011-09-23 15:16:13 +04:00
|
|
|
for (int i = 0, n = mAvailableFonts.Length(); i < n; ++i) {
|
|
|
|
const FT2FontEntry* fe =
|
|
|
|
static_cast<const FT2FontEntry*>(mAvailableFonts[i].get());
|
|
|
|
if (!fe) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-04-23 17:52:20 +03:00
|
|
|
aFontList->AppendElement(
|
|
|
|
FontListEntry(Name(), fe->Name(), fe->mFilename,
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->Weight().AsScalar(), fe->Stretch().AsScalar(),
|
|
|
|
fe->SlantStyle().AsScalar(), fe->mFTFontIndex));
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Startup cache support for the font list:
|
|
|
|
* We store the list of families and faces, with their style attributes and the
|
|
|
|
* corresponding font files, in the startup cache.
|
|
|
|
* This allows us to recreate the gfxFT2FontList collection of families and
|
|
|
|
* faces without instantiating Freetype faces for each font file (in order to
|
|
|
|
* find their attributes), leading to significantly quicker startup.
|
|
|
|
*/
|
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
#define CACHE_KEY "font.cached-list"
|
|
|
|
|
|
|
|
class FontNameCache {
|
|
|
|
public:
|
2016-09-28 22:42:41 +03:00
|
|
|
// Creates the object but does NOT load the cached data from the startup
|
|
|
|
// cache; call Init() after creation to do that.
|
2015-06-01 08:14:44 +03:00
|
|
|
FontNameCache() : mMap(&mOps, sizeof(FNCMapEntry), 0), mWriteNeeded(false) {
|
|
|
|
// HACK ALERT: it's weird to assign |mOps| after we passed a pointer to
|
|
|
|
// it to |mMap|'s constructor. A more normal approach here would be to
|
|
|
|
// have a static |sOps| member. Unfortunately, this mysteriously but
|
|
|
|
// consistently makes Fennec start-up slower, so we take this
|
|
|
|
// unorthodox approach instead. It's safe because PLDHashTable's
|
|
|
|
// constructor doesn't dereference the pointer; it just makes a copy of
|
|
|
|
// it.
|
2015-05-15 07:48:43 +03:00
|
|
|
mOps = (PLDHashTableOps){StringHash, HashMatchEntry, MoveEntry,
|
2015-09-15 00:23:47 +03:00
|
|
|
PLDHashTable::ClearEntryStub, nullptr};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-07-04 04:29:00 +03:00
|
|
|
MOZ_ASSERT(XRE_IsParentProcess(),
|
2016-09-28 22:42:41 +03:00
|
|
|
"FontNameCache should only be used in chrome process");
|
2011-09-23 15:15:36 +04:00
|
|
|
mCache = mozilla::scache::StartupCache::GetSingleton();
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
~FontNameCache() {
|
|
|
|
if (!mWriteNeeded || !mCache) {
|
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString buf;
|
2015-06-10 23:07:41 +03:00
|
|
|
for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
auto entry = static_cast<FNCMapEntry*>(iter.Get());
|
|
|
|
if (!entry->mFileExists) {
|
|
|
|
// skip writing entries for files that are no longer present
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
buf.Append(entry->mFilename);
|
|
|
|
buf.Append(';');
|
|
|
|
buf.Append(entry->mFaces);
|
|
|
|
buf.Append(';');
|
|
|
|
buf.AppendInt(entry->mTimestamp);
|
|
|
|
buf.Append(';');
|
|
|
|
buf.AppendInt(entry->mFilesize);
|
|
|
|
buf.Append(';');
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-02-17 02:30:47 +03:00
|
|
|
mCache->PutBuffer(CACHE_KEY, UniquePtr<char[]>(ToNewCString(buf)),
|
|
|
|
buf.Length() + 1);
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
// This may be called more than once (if we re-load the font list).
|
2011-09-23 15:15:36 +04:00
|
|
|
void Init() {
|
2015-05-21 07:23:55 +03:00
|
|
|
if (!mCache) {
|
2011-09-23 15:15:36 +04:00
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t size;
|
2016-02-18 20:26:28 +03:00
|
|
|
UniquePtr<char[]> buf;
|
2011-09-23 15:15:36 +04:00
|
|
|
if (NS_FAILED(mCache->GetBuffer(CACHE_KEY, &buf, &size))) {
|
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-02-24 23:48:35 +03:00
|
|
|
LOG(("got: %s from the cache", nsDependentCString(buf.get(), size).get()));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
mMap.Clear();
|
|
|
|
mWriteNeeded = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-02-24 23:48:35 +03:00
|
|
|
const char* beginning = buf.get();
|
2011-09-23 15:15:36 +04:00
|
|
|
const char* end = strchr(beginning, ';');
|
|
|
|
while (end) {
|
|
|
|
nsCString filename(beginning, end - beginning);
|
|
|
|
beginning = end + 1;
|
|
|
|
if (!(end = strchr(beginning, ';'))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nsCString faceList(beginning, end - beginning);
|
|
|
|
beginning = end + 1;
|
|
|
|
if (!(end = strchr(beginning, ';'))) {
|
|
|
|
break;
|
|
|
|
}
|
2013-07-31 19:44:31 +04:00
|
|
|
uint32_t timestamp = strtoul(beginning, nullptr, 10);
|
2011-09-23 15:15:36 +04:00
|
|
|
beginning = end + 1;
|
|
|
|
if (!(end = strchr(beginning, ';'))) {
|
|
|
|
break;
|
|
|
|
}
|
2013-07-31 19:44:31 +04:00
|
|
|
uint32_t filesize = strtoul(beginning, nullptr, 10);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-09-15 00:23:12 +03:00
|
|
|
auto mapEntry =
|
|
|
|
static_cast<FNCMapEntry*>(mMap.Add(filename.get(), fallible));
|
2011-09-23 15:15:36 +04:00
|
|
|
if (mapEntry) {
|
|
|
|
mapEntry->mFilename.Assign(filename);
|
|
|
|
mapEntry->mTimestamp = timestamp;
|
|
|
|
mapEntry->mFilesize = filesize;
|
|
|
|
mapEntry->mFaces.Assign(faceList);
|
|
|
|
// entries from the startupcache are marked "non-existing"
|
|
|
|
// until we have confirmed that the file still exists
|
2011-10-17 18:59:28 +04:00
|
|
|
mapEntry->mFileExists = false;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
beginning = end + 1;
|
|
|
|
end = strchr(beginning, ';');
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
void GetInfoForFile(const nsCString& aFileName, nsCString& aFaceList,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t* aTimestamp, uint32_t* aFilesize) {
|
2015-05-21 10:34:25 +03:00
|
|
|
auto entry = static_cast<FNCMapEntry*>(mMap.Search(aFileName.get()));
|
2015-01-27 01:25:13 +03:00
|
|
|
if (entry) {
|
2011-09-23 15:15:36 +04:00
|
|
|
*aTimestamp = entry->mTimestamp;
|
|
|
|
*aFilesize = entry->mFilesize;
|
|
|
|
aFaceList.Assign(entry->mFaces);
|
|
|
|
// this entry does correspond to an existing file
|
|
|
|
// (although it might not be up-to-date, in which case
|
|
|
|
// it will get overwritten via CacheFileInfo)
|
2011-10-17 18:59:28 +04:00
|
|
|
entry->mFileExists = true;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
void CacheFileInfo(const nsCString& aFileName, const nsCString& aFaceList,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aTimestamp, uint32_t aFilesize) {
|
2015-09-15 00:23:12 +03:00
|
|
|
auto entry = static_cast<FNCMapEntry*>(mMap.Add(aFileName.get(), fallible));
|
2011-09-23 15:15:36 +04:00
|
|
|
if (entry) {
|
|
|
|
entry->mFilename.Assign(aFileName);
|
|
|
|
entry->mTimestamp = aTimestamp;
|
|
|
|
entry->mFilesize = aFilesize;
|
|
|
|
entry->mFaces.Assign(aFaceList);
|
2011-10-17 18:59:28 +04:00
|
|
|
entry->mFileExists = true;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mWriteNeeded = true;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
private:
|
|
|
|
mozilla::scache::StartupCache* mCache;
|
2015-05-20 02:46:17 +03:00
|
|
|
PLDHashTable mMap;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mWriteNeeded;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-05-15 07:48:43 +03:00
|
|
|
PLDHashTableOps mOps;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
typedef struct : public PLDHashEntryHdr {
|
|
|
|
public:
|
|
|
|
nsCString mFilename;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t mTimestamp;
|
|
|
|
uint32_t mFilesize;
|
2011-09-23 15:15:36 +04:00
|
|
|
nsCString mFaces;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mFileExists;
|
2011-09-23 15:15:36 +04:00
|
|
|
} FNCMapEntry;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:33:44 +03:00
|
|
|
static PLDHashNumber StringHash(const void* key) {
|
2011-09-23 15:15:36 +04:00
|
|
|
return HashString(reinterpret_cast<const char*>(key));
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-03-16 07:33:44 +03:00
|
|
|
static bool HashMatchEntry(const PLDHashEntryHdr* aHdr, const void* key) {
|
2011-09-23 15:15:36 +04:00
|
|
|
const FNCMapEntry* entry = static_cast<const FNCMapEntry*>(aHdr);
|
|
|
|
return entry->mFilename.Equals(reinterpret_cast<const char*>(key));
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
static void MoveEntry(PLDHashTable* table, const PLDHashEntryHdr* aFrom,
|
|
|
|
PLDHashEntryHdr* aTo) {
|
|
|
|
FNCMapEntry* to = static_cast<FNCMapEntry*>(aTo);
|
|
|
|
const FNCMapEntry* from = static_cast<const FNCMapEntry*>(aFrom);
|
|
|
|
to->mFilename.Assign(from->mFilename);
|
|
|
|
to->mTimestamp = from->mTimestamp;
|
|
|
|
to->mFilesize = from->mFilesize;
|
|
|
|
to->mFaces.Assign(from->mFaces);
|
|
|
|
to->mFileExists = from->mFileExists;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
/***************************************************************
|
|
|
|
*
|
|
|
|
* gfxFT2FontList
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
// For Mobile, we use gfxFT2Fonts, and we build the font list by directly
|
|
|
|
// scanning the system's Fonts directory for OpenType and TrueType files.
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
#define JAR_LAST_MODIFED_TIME "jar-last-modified-time"
|
|
|
|
|
|
|
|
class WillShutdownObserver : public nsIObserver {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIOBSERVER
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
explicit WillShutdownObserver(gfxFT2FontList* aFontList)
|
|
|
|
: mFontList(aFontList) {}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-11-20 02:16:24 +03:00
|
|
|
void Remove() {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
|
|
|
|
}
|
|
|
|
mFontList = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-11-20 02:16:24 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
protected:
|
|
|
|
virtual ~WillShutdownObserver() {}
|
|
|
|
|
|
|
|
gfxFT2FontList* mFontList;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(WillShutdownObserver, nsIObserver)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
WillShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData) {
|
|
|
|
if (!nsCRT::strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)) {
|
|
|
|
mFontList->WillShutdown();
|
|
|
|
} else {
|
2018-06-18 08:43:11 +03:00
|
|
|
MOZ_ASSERT_UNREACHABLE("unexpected notification topic");
|
2016-09-28 22:42:41 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
gfxFT2FontList::gfxFT2FontList() : mJarModifiedTime(0) {
|
2016-09-28 22:42:41 +03:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
mObserver = new WillShutdownObserver(this);
|
|
|
|
obs->AddObserver(mObserver, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFT2FontList::~gfxFT2FontList() {
|
|
|
|
if (mObserver) {
|
2018-11-20 02:16:24 +03:00
|
|
|
mObserver->Remove();
|
2016-09-28 22:42:41 +03:00
|
|
|
}
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
|
|
|
|
2014-06-30 22:05:29 +04:00
|
|
|
void gfxFT2FontList::AppendFacesFromCachedFaceList(const nsCString& aFileName,
|
|
|
|
const nsCString& aFaceList,
|
2011-09-23 15:15:36 +04:00
|
|
|
StandardFile aStdFile) {
|
2018-09-12 22:34:57 +03:00
|
|
|
const char* beginning = aFaceList.get();
|
2011-09-23 15:15:36 +04:00
|
|
|
const char* end = strchr(beginning, ',');
|
2018-04-25 09:18:23 +03:00
|
|
|
while (end) {
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString familyName(beginning, end - beginning);
|
|
|
|
ToLowerCase(familyName);
|
2011-09-23 15:15:36 +04:00
|
|
|
|
|
|
|
beginning = end + 1;
|
|
|
|
if (!(end = strchr(beginning, ','))) {
|
|
|
|
break;
|
|
|
|
}
|
2018-09-12 22:34:57 +03:00
|
|
|
nsAutoCString faceName(beginning, end - beginning);
|
2011-09-23 15:15:36 +04:00
|
|
|
|
|
|
|
beginning = end + 1;
|
2018-05-17 16:44:37 +03:00
|
|
|
if (!(end = strchr(beginning, ','))) {
|
2018-04-25 09:18:23 +03:00
|
|
|
break;
|
2012-05-25 18:03:42 +04:00
|
|
|
}
|
2013-07-31 19:44:31 +04:00
|
|
|
uint32_t index = strtoul(beginning, nullptr, 10);
|
2012-05-25 18:03:42 +04:00
|
|
|
|
|
|
|
beginning = end + 1;
|
2012-12-19 13:42:25 +04:00
|
|
|
if (!(end = strchr(beginning, ','))) {
|
2012-05-25 18:03:42 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
nsAutoCString minStyle(beginning, end - beginning);
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString maxStyle(minStyle);
|
2012-05-25 18:03:42 +04:00
|
|
|
int32_t colon = minStyle.FindChar(':');
|
2013-03-04 21:03:14 +04:00
|
|
|
if (colon > 0) {
|
|
|
|
maxStyle.Assign(minStyle.BeginReading() + colon + 1);
|
|
|
|
minStyle.Truncate(colon);
|
2012-05-25 18:03:42 +04:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
beginning = end + 1;
|
2011-09-23 15:15:36 +04:00
|
|
|
if (!(end = strchr(beginning, ','))) {
|
2015-09-12 06:30:14 +03:00
|
|
|
break;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
|
|
|
char* limit;
|
|
|
|
float minWeight = strtof(beginning, &limit);
|
2015-09-12 06:30:14 +03:00
|
|
|
float maxWeight;
|
|
|
|
if (*limit == ':' && limit + 1 < end) {
|
2018-01-30 22:08:22 +03:00
|
|
|
maxWeight = strtof(limit + 1, nullptr);
|
2011-09-23 15:15:36 +04:00
|
|
|
} else {
|
|
|
|
maxWeight = minWeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
beginning = end + 1;
|
2015-09-12 06:30:14 +03:00
|
|
|
if (!(end = strchr(beginning, ','))) {
|
|
|
|
break;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
float minStretch = strtof(beginning, &limit);
|
2018-04-25 09:18:23 +03:00
|
|
|
float maxStretch;
|
|
|
|
if (*limit == ':' && limit + 1 < end) {
|
|
|
|
maxStretch = strtof(limit + 1, nullptr);
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2018-04-25 09:18:23 +03:00
|
|
|
maxStretch = minStretch;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 09:18:23 +03:00
|
|
|
FontListEntry fle(
|
|
|
|
familyName, faceName, aFileName,
|
|
|
|
WeightRange(FontWeight(minWeight), FontWeight(maxWeight)).AsScalar(),
|
|
|
|
StretchRange(FontStretch(minStretch), FontStretch(maxStretch))
|
|
|
|
.AsScalar(),
|
|
|
|
SlantStyleRange(FontSlantStyle::FromString(minStyle.get()),
|
|
|
|
FontSlantStyle::FromString(maxStyle.get()))
|
|
|
|
.AsScalar(),
|
2018-11-30 13:46:48 +03:00
|
|
|
index);
|
2011-09-23 15:15:36 +04:00
|
|
|
AppendFaceFromFontListEntry(fle, aStdFile);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
beginning = end + 1;
|
|
|
|
end = strchr(beginning, ',');
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
static void AppendToFaceList(nsCString& aFaceList, nsACString& aFamilyName,
|
|
|
|
FT2FontEntry* aFontEntry) {
|
|
|
|
aFaceList.Append(aFamilyName);
|
2011-09-23 15:15:36 +04:00
|
|
|
aFaceList.Append(',');
|
2013-06-25 12:14:03 +04:00
|
|
|
aFaceList.Append(aFontEntry->Name());
|
2011-09-23 15:15:36 +04:00
|
|
|
aFaceList.Append(',');
|
2013-06-25 12:14:03 +04:00
|
|
|
aFaceList.AppendInt(aFontEntry->mFTFontIndex);
|
|
|
|
aFaceList.Append(',');
|
|
|
|
// Note that ToString() appends to the destination string without
|
|
|
|
// replacing existing contents (see FontPropertyTypes.h)
|
|
|
|
aFontEntry->SlantStyle().Min().ToString(aFaceList);
|
|
|
|
aFaceList.Append(':');
|
|
|
|
aFontEntry->SlantStyle().Max().ToString(aFaceList);
|
2011-09-23 15:15:36 +04:00
|
|
|
aFaceList.Append(',');
|
2018-04-25 09:18:23 +03:00
|
|
|
aFaceList.AppendFloat(aFontEntry->Weight().Min().ToFloat());
|
2018-05-17 16:44:37 +03:00
|
|
|
aFaceList.Append(':');
|
2013-06-25 12:14:03 +04:00
|
|
|
aFaceList.AppendFloat(aFontEntry->Weight().Max().ToFloat());
|
|
|
|
aFaceList.Append(',');
|
|
|
|
aFaceList.AppendFloat(aFontEntry->Stretch().Min().Percentage());
|
2018-05-17 16:44:37 +03:00
|
|
|
aFaceList.Append(':');
|
2013-06-25 12:14:03 +04:00
|
|
|
aFaceList.AppendFloat(aFontEntry->Stretch().Max().Percentage());
|
|
|
|
aFaceList.Append(',');
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
void FT2FontEntry::CheckForBrokenFont(gfxFontFamily* aFamily) {
|
|
|
|
// note if the family is in the "bad underline" blacklist
|
|
|
|
if (aFamily->IsBadUnderlineFamily()) {
|
|
|
|
mIsBadUnderlineFont = true;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// bug 721719 - set the IgnoreGSUB flag on entries for Roboto
|
|
|
|
// because of unwanted on-by-default "ae" ligature.
|
|
|
|
// (See also AppendFaceFromFontListEntry.)
|
2014-03-20 10:43:31 +04:00
|
|
|
if (aFamily->Name().EqualsLiteral("roboto")) {
|
|
|
|
mIgnoreGSUB = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2014-03-20 10:43:31 +04:00
|
|
|
// bug 706888 - set the IgnoreGSUB flag on the broken version of
|
2018-11-15 19:11:45 +03:00
|
|
|
// Droid Sans Arabic from certain phones, as identified by the
|
|
|
|
// font checksum in the 'head' table
|
|
|
|
else if (aFamily->Name().EqualsLiteral("droid sans arabic")) {
|
2013-06-25 12:14:03 +04:00
|
|
|
AutoFTFace face(this);
|
|
|
|
if (face) {
|
2018-04-25 09:18:23 +03:00
|
|
|
const TT_Header* head =
|
2013-06-25 12:14:03 +04:00
|
|
|
static_cast<const TT_Header*>(FT_Get_Sfnt_Table(face, ft_sfnt_head));
|
|
|
|
if (head && head->CheckSum_Adjust == 0xe445242) {
|
2018-04-25 09:18:23 +03:00
|
|
|
mIgnoreGSUB = true;
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
void gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
|
|
|
|
FontNameCache* aCache,
|
|
|
|
StandardFile aStdFile) {
|
|
|
|
nsCString cachedFaceList;
|
|
|
|
uint32_t filesize = 0, timestamp = 0;
|
|
|
|
if (aCache) {
|
|
|
|
aCache->GetInfoForFile(aFileName, cachedFaceList, ×tamp, &filesize);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
struct stat s;
|
2013-06-25 12:14:03 +04:00
|
|
|
int statRetval = stat(aFileName.get(), &s);
|
|
|
|
if (!cachedFaceList.IsEmpty() && 0 == statRetval &&
|
|
|
|
uint32_t(s.st_mtime) == timestamp && s.st_size == filesize) {
|
|
|
|
LOG(("using cached font info for %s", aFileName.get()));
|
2014-06-30 22:05:29 +04:00
|
|
|
AppendFacesFromCachedFaceList(aFileName, cachedFaceList, aStdFile);
|
2012-10-03 23:29:10 +04:00
|
|
|
return;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
FT_Face dummy = Factory::NewFTFace(nullptr, aFileName.get(), -1);
|
|
|
|
if (dummy) {
|
2011-09-23 15:15:36 +04:00
|
|
|
LOG(("reading font info via FreeType for %s", aFileName.get()));
|
2015-09-12 06:30:14 +03:00
|
|
|
nsCString newFaceList;
|
2011-09-23 15:15:36 +04:00
|
|
|
timestamp = s.st_mtime;
|
|
|
|
filesize = s.st_size;
|
2009-10-07 18:13:40 +04:00
|
|
|
for (FT_Long i = 0; i < dummy->num_faces; i++) {
|
2017-05-18 04:56:24 +03:00
|
|
|
FT_Face face = Factory::NewFTFace(nullptr, aFileName.get(), i);
|
|
|
|
if (!face) {
|
2009-10-07 18:13:40 +04:00
|
|
|
continue;
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
2017-07-06 17:06:45 +03:00
|
|
|
AddFaceToList(aFileName, i, aStdFile, face, newFaceList);
|
2017-05-18 04:56:24 +03:00
|
|
|
Factory::ReleaseFTFace(face);
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
2013-06-25 12:14:03 +04:00
|
|
|
Factory::ReleaseFTFace(dummy);
|
|
|
|
if (aCache && 0 == statRetval && !newFaceList.IsEmpty()) {
|
|
|
|
aCache->CacheFileInfo(aFileName, newFaceList, timestamp, filesize);
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2012-10-03 23:29:10 +04:00
|
|
|
|
2015-10-20 20:13:35 +03:00
|
|
|
void gfxFT2FontList::FindFontsInOmnijar(FontNameCache* aCache) {
|
|
|
|
bool jarChanged = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-10-20 20:13:35 +03:00
|
|
|
mozilla::scache::StartupCache* cache =
|
2013-06-25 12:14:03 +04:00
|
|
|
mozilla::scache::StartupCache::GetSingleton();
|
2016-02-18 20:26:28 +03:00
|
|
|
UniquePtr<char[]> cachedModifiedTimeBuf;
|
2013-06-25 12:14:03 +04:00
|
|
|
uint32_t longSize;
|
|
|
|
if (cache &&
|
2015-10-20 20:13:35 +03:00
|
|
|
NS_SUCCEEDED(cache->GetBuffer(JAR_LAST_MODIFED_TIME,
|
|
|
|
&cachedModifiedTimeBuf, &longSize)) &&
|
2013-06-25 12:14:03 +04:00
|
|
|
longSize == sizeof(int64_t)) {
|
|
|
|
nsCOMPtr<nsIFile> jarFile = Omnijar::GetPath(Omnijar::Type::GRE);
|
2016-09-28 22:42:41 +03:00
|
|
|
jarFile->GetLastModifiedTime(&mJarModifiedTime);
|
2015-10-20 20:13:35 +03:00
|
|
|
if (mJarModifiedTime > *(int64_t*)cachedModifiedTimeBuf.get()) {
|
2013-06-25 12:14:03 +04:00
|
|
|
jarChanged = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-20 20:13:35 +03:00
|
|
|
static const char* sJarSearchPaths[] = {
|
|
|
|
"res/fonts/*.ttf$",
|
2018-11-30 13:46:48 +03:00
|
|
|
};
|
2015-10-20 20:13:35 +03:00
|
|
|
RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE);
|
2013-06-25 12:14:03 +04:00
|
|
|
for (unsigned i = 0; i < ArrayLength(sJarSearchPaths); i++) {
|
|
|
|
nsZipFind* find;
|
|
|
|
if (NS_SUCCEEDED(reader->FindInit(sJarSearchPaths[i], &find))) {
|
|
|
|
const char* path;
|
|
|
|
uint16_t len;
|
|
|
|
while (NS_SUCCEEDED(find->FindNext(&path, &len))) {
|
2018-09-12 22:34:57 +03:00
|
|
|
nsCString entryName(path, len);
|
2013-06-25 12:14:03 +04:00
|
|
|
AppendFacesFromOmnijarEntry(reader, entryName, aCache, jarChanged);
|
|
|
|
}
|
|
|
|
delete find;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-03 23:29:10 +04:00
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
// Given the freetype face corresponding to an entryName and face index,
|
2013-06-25 12:14:03 +04:00
|
|
|
// add the face to the available font list and to the faceList string
|
2017-05-18 04:56:24 +03:00
|
|
|
void gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
|
|
|
|
StandardFile aStdFile, FT_Face aFace,
|
2013-06-25 12:14:03 +04:00
|
|
|
nsCString& aFaceList) {
|
2017-05-18 04:56:24 +03:00
|
|
|
if (FT_Err_Ok != FT_Select_Charmap(aFace, FT_ENCODING_UNICODE)) {
|
|
|
|
// ignore faces that don't support a Unicode charmap
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
// build the font entry name and create an FT2FontEntry,
|
2013-06-25 12:14:03 +04:00
|
|
|
// but do -not- keep a reference to the FT_Face
|
2016-08-23 03:06:07 +03:00
|
|
|
RefPtr<FT2FontEntry> fe =
|
2017-05-18 04:56:24 +03:00
|
|
|
CreateNamedFontEntry(aFace, aEntryName.get(), aIndex);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
if (fe) {
|
2018-09-12 22:34:57 +03:00
|
|
|
nsAutoCString name(aFace->family_name);
|
2017-05-18 04:56:24 +03:00
|
|
|
BuildKeyNameFromFontName(name);
|
|
|
|
RefPtr<gfxFontFamily> family = mFontFamilies.GetWeak(name);
|
|
|
|
if (!family) {
|
2013-06-25 12:14:03 +04:00
|
|
|
family = new FT2FontFamily(name);
|
2017-07-06 17:06:45 +03:00
|
|
|
mFontFamilies.Put(name, family);
|
2018-09-12 22:34:57 +03:00
|
|
|
if (mSkipSpaceLookupCheckFamilies.Contains(name)) {
|
2013-06-25 12:14:03 +04:00
|
|
|
family->SetSkipSpaceFeatureCheck(true);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-11-15 19:11:45 +03:00
|
|
|
if (mBadUnderlineFamilyNames.ContainsSorted(name)) {
|
2013-06-25 12:14:03 +04:00
|
|
|
family->SetBadUnderlineFamily();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2014-06-30 22:05:29 +04:00
|
|
|
fe->mStandardFace = (aStdFile == kStandard);
|
2013-06-25 12:14:03 +04:00
|
|
|
family->AddFontEntry(fe);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
fe->CheckForBrokenFont(family);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-07-06 17:06:45 +03:00
|
|
|
AppendToFaceList(aFaceList, name, fe);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (LOG_ENABLED()) {
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString weightString;
|
|
|
|
fe->Weight().ToString(weightString);
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString stretchString;
|
|
|
|
fe->Stretch().ToString(stretchString);
|
2018-11-30 13:46:48 +03:00
|
|
|
LOG(
|
2013-06-25 12:14:03 +04:00
|
|
|
("(fontinit) added (%s) to family (%s)"
|
2018-04-25 09:18:23 +03:00
|
|
|
" with style: %s weight: %s stretch: %s",
|
2018-09-12 22:34:57 +03:00
|
|
|
fe->Name().get(), family->Name().get(),
|
2013-06-25 12:14:03 +04:00
|
|
|
fe->IsItalic() ? "italic" : "normal", weightString.get(),
|
2018-04-25 09:18:23 +03:00
|
|
|
stretchString.get()));
|
2013-06-25 12:14:03 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2012-10-03 23:29:10 +04:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
|
2013-06-25 12:14:03 +04:00
|
|
|
const nsCString& aEntryName,
|
2014-06-30 22:05:29 +04:00
|
|
|
FontNameCache* aCache,
|
2013-06-25 12:14:03 +04:00
|
|
|
bool aJarChanged) {
|
2015-09-12 06:30:14 +03:00
|
|
|
nsCString faceList;
|
2013-06-25 12:14:03 +04:00
|
|
|
if (aCache && !aJarChanged) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t filesize, timestamp;
|
2015-09-12 06:30:14 +03:00
|
|
|
aCache->GetInfoForFile(aEntryName, faceList, ×tamp, &filesize);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (faceList.Length() > 0) {
|
2017-07-06 17:06:45 +03:00
|
|
|
AppendFacesFromCachedFaceList(aEntryName, faceList);
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
nsZipItem* item = aArchive->GetItem(aEntryName.get());
|
|
|
|
NS_ASSERTION(item, "failed to find zip entry");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
uint32_t bufSize = item->RealSize();
|
|
|
|
// We use fallible allocation here; if there's not enough RAM, we'll simply
|
|
|
|
// ignore the bundled fonts and fall back to the device's installed fonts.
|
2015-10-20 20:13:35 +03:00
|
|
|
auto buf = MakeUniqueFallible<uint8_t[]>(bufSize);
|
2013-06-25 12:14:03 +04:00
|
|
|
if (!buf) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
nsZipCursor cursor(item, aArchive, buf.get(), bufSize);
|
|
|
|
uint8_t* data = cursor.Copy(&bufSize);
|
|
|
|
NS_ASSERTION(data && bufSize == item->RealSize(),
|
|
|
|
"error reading bundled font");
|
|
|
|
if (!data) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
FT_Face dummy = Factory::NewFTFaceFromData(nullptr, buf.get(), bufSize, 0);
|
|
|
|
if (!dummy) {
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
for (FT_Long i = 0; i < dummy->num_faces; i++) {
|
2017-05-18 04:56:24 +03:00
|
|
|
FT_Face face = Factory::NewFTFaceFromData(nullptr, buf.get(), bufSize, i);
|
|
|
|
if (!face) {
|
2013-06-25 12:14:03 +04:00
|
|
|
continue;
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
2017-07-06 17:06:45 +03:00
|
|
|
AddFaceToList(aEntryName, i, kStandard, face, faceList);
|
2017-05-18 04:56:24 +03:00
|
|
|
Factory::ReleaseFTFace(face);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2013-06-25 12:14:03 +04:00
|
|
|
|
2017-05-18 04:56:24 +03:00
|
|
|
Factory::ReleaseFTFace(dummy);
|
2013-06-25 12:14:03 +04:00
|
|
|
|
|
|
|
if (aCache && !faceList.IsEmpty()) {
|
|
|
|
aCache->CacheFileInfo(aEntryName, faceList, 0, bufSize);
|
2012-10-03 23:29:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// Called on each family after all fonts are added to the list;
|
|
|
|
// this will sort faces to give priority to "standard" font files
|
|
|
|
// if aUserArg is non-null (i.e. we're using it as a boolean flag)
|
2018-09-12 22:34:57 +03:00
|
|
|
static void FinalizeFamilyMemberList(nsCStringHashKey::KeyType aKey,
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily>& aFamily,
|
2015-09-24 18:31:30 +03:00
|
|
|
bool aSortFaces) {
|
2013-06-25 12:14:03 +04:00
|
|
|
gfxFontFamily* family = aFamily.get();
|
|
|
|
|
|
|
|
family->SetHasStyles(true);
|
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
if (aSortFaces) {
|
2013-06-25 12:14:03 +04:00
|
|
|
family->SortAvailableFonts();
|
|
|
|
}
|
|
|
|
family->CheckForSimpleFamily();
|
|
|
|
}
|
2012-10-03 23:29:10 +04:00
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
void gfxFT2FontList::FindFonts() {
|
2010-07-16 10:03:45 +04:00
|
|
|
gfxFontCache* fc = gfxFontCache::GetCache();
|
|
|
|
if (fc) fc->AgeAllGenerations();
|
2011-09-23 15:15:36 +04:00
|
|
|
ClearLangGroupPrefFonts();
|
|
|
|
mCodepointsWithNoFonts.reset();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-07-06 17:06:45 +03:00
|
|
|
mCodepointsWithNoFonts.SetRange(0, 0x1f); // C0 controls
|
2011-09-23 15:15:36 +04:00
|
|
|
mCodepointsWithNoFonts.SetRange(0x7f, 0x9f); // C1 controls
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-10-03 23:27:25 +04:00
|
|
|
if (!XRE_IsParentProcess()) {
|
2013-06-25 12:14:03 +04:00
|
|
|
// Content process: ask the Chrome process to give us the list
|
|
|
|
InfallibleTArray<FontListEntry> fonts;
|
2016-09-28 22:42:41 +03:00
|
|
|
mozilla::dom::ContentChild::GetSingleton()->SendReadFontList(&fonts);
|
2015-09-22 16:55:56 +03:00
|
|
|
for (uint32_t i = 0, n = fonts.Length(); i < n; ++i) {
|
|
|
|
// We don't need to identify "standard" font files here,
|
|
|
|
// as the faces are already sorted.
|
|
|
|
AppendFaceFromFontListEntry(fonts[i], kUnknown);
|
|
|
|
}
|
2012-10-03 23:27:25 +04:00
|
|
|
// Passing null for userdata tells Finalize that it does not need
|
|
|
|
// to sort faces (because they were already sorted by chrome,
|
|
|
|
// so we just maintain the existing order)
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
2018-09-12 22:34:57 +03:00
|
|
|
nsCStringHashKey::KeyType key = iter.Key();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily>& family = iter.Data();
|
2015-09-24 18:31:30 +03:00
|
|
|
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2017-05-01 21:46:01 +03:00
|
|
|
LOG(("got font list from chrome process: %" PRIdPTR " faces in %" PRIu32
|
2017-07-06 17:06:45 +03:00
|
|
|
" families",
|
|
|
|
fonts.Length(), mFontFamilies.Count()));
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
// Chrome process: get the cached list (if any)
|
2016-09-28 22:42:41 +03:00
|
|
|
if (!mFontNameCache) {
|
|
|
|
mFontNameCache = MakeUnique<FontNameCache>();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2016-09-28 22:42:41 +03:00
|
|
|
mFontNameCache->Init();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
// ANDROID_ROOT is the root of the android system, typically /system;
|
|
|
|
// font files are in /$ANDROID_ROOT/fonts/
|
|
|
|
nsCString root;
|
|
|
|
char* androidRoot = PR_GetEnv("ANDROID_ROOT");
|
|
|
|
if (androidRoot) {
|
|
|
|
root = androidRoot;
|
2018-11-30 13:46:48 +03:00
|
|
|
} else {
|
2011-09-23 15:15:36 +04:00
|
|
|
root = NS_LITERAL_CSTRING("/system");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2014-05-22 07:48:51 +04:00
|
|
|
root.AppendLiteral("/fonts");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-07-06 17:06:45 +03:00
|
|
|
FindFontsInDir(root, mFontNameCache.get());
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-10-03 23:27:25 +04:00
|
|
|
if (mFontFamilies.Count() == 0) {
|
|
|
|
// if we can't find/read the font directory, we are doomed!
|
2016-12-03 00:46:53 +03:00
|
|
|
MOZ_CRASH("Could not read the system fonts directory");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 12:14:03 +04:00
|
|
|
// Look for fonts stored in omnijar, unless we're on a low-memory
|
|
|
|
// device where we don't want to spend the RAM to decompress them.
|
|
|
|
// (Prefs may disable this, or force-enable it even with low memory.)
|
|
|
|
bool lowmem;
|
|
|
|
nsCOMPtr<nsIMemory> mem = nsMemory::GetGlobalMemoryService();
|
|
|
|
if ((NS_SUCCEEDED(mem->IsLowMemoryPlatform(&lowmem)) && !lowmem &&
|
|
|
|
Preferences::GetBool("gfx.bundled_fonts.enabled")) ||
|
|
|
|
Preferences::GetBool("gfx.bundled_fonts.force-enabled")) {
|
2017-07-06 17:06:45 +03:00
|
|
|
FindFontsInOmnijar(mFontNameCache.get());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
2012-12-18 15:18:56 +04:00
|
|
|
// Look for downloaded fonts in a profile-agnostic "fonts" directory.
|
2015-09-22 16:55:56 +03:00
|
|
|
nsCOMPtr<nsIProperties> dirSvc =
|
|
|
|
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
|
|
|
|
if (dirSvc) {
|
|
|
|
nsCOMPtr<nsIFile> appDir;
|
|
|
|
nsresult rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
|
|
|
|
getter_AddRefs(appDir));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2013-06-25 12:14:03 +04:00
|
|
|
appDir->AppendNative(NS_LITERAL_CSTRING("fonts"));
|
2015-09-22 16:55:56 +03:00
|
|
|
nsCString localPath;
|
|
|
|
if (NS_SUCCEEDED(appDir->GetNativePath(localPath))) {
|
2017-07-06 17:06:45 +03:00
|
|
|
FindFontsInDir(localPath, mFontNameCache.get());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-18 15:18:56 +04:00
|
|
|
// look for locally-added fonts in a "fonts" subdir of the profile
|
2013-06-25 12:14:03 +04:00
|
|
|
nsCOMPtr<nsIFile> localDir;
|
|
|
|
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
|
|
|
|
getter_AddRefs(localDir));
|
|
|
|
if (NS_SUCCEEDED(rv) &&
|
|
|
|
NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
|
2015-09-22 16:55:56 +03:00
|
|
|
nsCString localPath;
|
2012-10-03 23:28:43 +04:00
|
|
|
rv = localDir->GetNativePath(localPath);
|
2015-09-22 16:55:56 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2017-07-06 17:06:45 +03:00
|
|
|
FindFontsInDir(localPath, mFontNameCache.get());
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-23 15:16:13 +04:00
|
|
|
// Finalize the families by sorting faces into standard order
|
2012-10-03 23:27:25 +04:00
|
|
|
// and marking "simple" families.
|
2011-09-23 15:15:36 +04:00
|
|
|
// Passing non-null userData here says that we want faces to be sorted.
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
2018-09-12 22:34:57 +03:00
|
|
|
nsCStringHashKey::KeyType key = iter.Key();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily>& family = iter.Data();
|
2015-09-24 18:31:30 +03:00
|
|
|
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
|
|
|
|
}
|
2012-10-03 23:27:25 +04:00
|
|
|
}
|
|
|
|
|
2014-06-30 22:05:29 +04:00
|
|
|
void gfxFT2FontList::FindFontsInDir(const nsCString& aDir,
|
2017-07-06 17:06:45 +03:00
|
|
|
FontNameCache* aFNC) {
|
2011-09-23 15:15:36 +04:00
|
|
|
static const char* sStandardFonts[] = {"DroidSans.ttf",
|
|
|
|
"DroidSans-Bold.ttf",
|
|
|
|
"DroidSerif-Regular.ttf",
|
|
|
|
"DroidSerif-Bold.ttf",
|
|
|
|
"DroidSerif-Italic.ttf",
|
|
|
|
"DroidSerif-BoldItalic.ttf",
|
|
|
|
"DroidSansMono.ttf",
|
|
|
|
"DroidSansArabic.ttf",
|
|
|
|
"DroidSansHebrew.ttf",
|
|
|
|
"DroidSansThai.ttf",
|
|
|
|
"MTLmr3m.ttf",
|
|
|
|
"MTLc3m.ttf",
|
2013-05-11 12:00:42 +04:00
|
|
|
"NanumGothic.ttf",
|
2011-09-23 15:15:36 +04:00
|
|
|
"DroidSansJapanese.ttf",
|
|
|
|
"DroidSansFallback.ttf"};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-10-03 23:27:25 +04:00
|
|
|
DIR* d = opendir(aDir.get());
|
2011-09-23 15:15:36 +04:00
|
|
|
if (!d) {
|
2012-10-03 23:27:25 +04:00
|
|
|
return;
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-07-31 19:44:31 +04:00
|
|
|
struct dirent* ent = nullptr;
|
|
|
|
while ((ent = readdir(d)) != nullptr) {
|
2014-03-25 14:07:31 +04:00
|
|
|
const char* ext = strrchr(ent->d_name, '.');
|
|
|
|
if (!ext) {
|
2011-09-23 15:15:36 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (strcasecmp(ext, ".ttf") == 0 || strcasecmp(ext, ".otf") == 0 ||
|
2014-03-25 14:07:31 +04:00
|
|
|
strcasecmp(ext, ".woff") == 0 || strcasecmp(ext, ".ttc") == 0) {
|
2011-09-23 15:15:36 +04:00
|
|
|
bool isStdFont = false;
|
2012-10-03 23:27:25 +04:00
|
|
|
for (unsigned int i = 0; i < ArrayLength(sStandardFonts) && !isStdFont;
|
|
|
|
i++) {
|
2011-09-23 15:15:36 +04:00
|
|
|
isStdFont = strcmp(sStandardFonts[i], ent->d_name) == 0;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-10-03 23:27:25 +04:00
|
|
|
nsCString s(aDir);
|
2011-09-23 15:15:36 +04:00
|
|
|
s.Append('/');
|
2014-03-25 14:07:31 +04:00
|
|
|
s.Append(ent->d_name);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
// Add the face(s) from this file to our font list;
|
|
|
|
// note that if we have cached info for this file in fnc,
|
|
|
|
// and the file is unchanged, we won't actually need to read it.
|
|
|
|
// If the file is new/changed, this will update the FontNameCache.
|
2017-07-06 17:06:45 +03:00
|
|
|
AppendFacesFromFontFile(s, aFNC, isStdFont ? kStandard : kUnknown);
|
2010-07-16 10:03:45 +04:00
|
|
|
}
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-10-03 23:27:25 +04:00
|
|
|
closedir(d);
|
2011-09-23 12:53:13 +04:00
|
|
|
}
|
|
|
|
|
2011-09-23 15:15:36 +04:00
|
|
|
void gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
|
2014-06-30 22:05:29 +04:00
|
|
|
StandardFile aStdFile) {
|
2011-09-23 15:16:13 +04:00
|
|
|
FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(aFLE);
|
2011-09-23 15:15:36 +04:00
|
|
|
if (fe) {
|
2014-06-30 22:05:29 +04:00
|
|
|
fe->mStandardFace = (aStdFile == kStandard);
|
2018-09-12 22:34:57 +03:00
|
|
|
RefPtr<gfxFontFamily> family = mFontFamilies.GetWeak(aFLE.familyName());
|
2011-09-23 15:15:36 +04:00
|
|
|
if (!family) {
|
2018-09-12 22:34:57 +03:00
|
|
|
family = new FT2FontFamily(aFLE.familyName());
|
|
|
|
mFontFamilies.Put(aFLE.familyName(), family);
|
|
|
|
if (mSkipSpaceLookupCheckFamilies.Contains(aFLE.familyName())) {
|
2014-03-20 10:43:31 +04:00
|
|
|
family->SetSkipSpaceFeatureCheck(true);
|
|
|
|
}
|
2018-11-15 19:11:45 +03:00
|
|
|
if (mBadUnderlineFamilyNames.ContainsSorted(aFLE.familyName())) {
|
2011-09-23 15:15:36 +04:00
|
|
|
family->SetBadUnderlineFamily();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
family->AddFontEntry(fe);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-12-19 13:42:25 +04:00
|
|
|
fe->CheckForBrokenFont(family);
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-13 08:11:25 +03:00
|
|
|
void gfxFT2FontList::GetSystemFontList(
|
|
|
|
InfallibleTArray<FontListEntry>* retValue) {
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
auto family = static_cast<FT2FontFamily*>(iter.Data().get());
|
2017-07-06 17:06:45 +03:00
|
|
|
family->AddFacesToFontList(retValue);
|
2015-09-24 18:31:30 +03:00
|
|
|
}
|
2011-09-23 15:15:36 +04:00
|
|
|
}
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
static void LoadSkipSpaceLookupCheck(
|
|
|
|
nsTHashtable<nsCStringHashKey>& aSkipSpaceLookupCheck) {
|
2018-09-18 11:34:24 +03:00
|
|
|
AutoTArray<nsCString, 5> skiplist;
|
2014-03-26 12:03:56 +04:00
|
|
|
gfxFontUtils::GetPrefsFontList(
|
|
|
|
"font.whitelist.skip_default_features_space_check", skiplist);
|
2014-03-20 10:43:31 +04:00
|
|
|
uint32_t numFonts = skiplist.Length();
|
|
|
|
for (uint32_t i = 0; i < numFonts; i++) {
|
|
|
|
ToLowerCase(skiplist[i]);
|
2018-09-18 11:34:24 +03:00
|
|
|
aSkipSpaceLookupCheck.PutEntry(skiplist[i]);
|
2014-03-20 10:43:31 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-23 03:06:07 +03:00
|
|
|
nsresult gfxFT2FontList::InitFontListForPlatform() {
|
2014-03-20 10:43:31 +04:00
|
|
|
LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies);
|
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
FindFonts();
|
2010-11-08 14:02:27 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
// called for each family name, based on the assumption that the
|
2009-10-07 18:13:40 +04:00
|
|
|
// first part of the full name is the family name
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
gfxFontEntry* gfxFT2FontList::LookupLocalFont(const nsACString& aFontName,
|
2018-04-25 09:18:23 +03:00
|
|
|
WeightRange aWeightForEntry,
|
|
|
|
StretchRange aStretchForEntry,
|
|
|
|
SlantStyleRange aStyleForEntry) {
|
2009-10-07 18:13:40 +04:00
|
|
|
// walk over list of names
|
2015-09-24 18:31:30 +03:00
|
|
|
FT2FontEntry* fontEntry = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
// Check family name, based on the assumption that the
|
|
|
|
// first part of the full name is the family name
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily>& fontFamily = iter.Data();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
// does the family name match up to the length of the family name?
|
2018-09-12 22:34:57 +03:00
|
|
|
const nsCString& family = fontFamily->Name();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
const nsAutoCString fullNameFamily(
|
|
|
|
Substring(aFontName, 0, family.Length()));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
// if so, iterate over faces in this family to see if there is a match
|
2018-09-12 22:34:57 +03:00
|
|
|
if (family.Equals(fullNameFamily, nsCaseInsensitiveCStringComparator())) {
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<gfxFontEntry> >& fontList = fontFamily->GetFontList();
|
2015-09-24 18:31:30 +03:00
|
|
|
int index, len = fontList.Length();
|
|
|
|
for (index = 0; index < len; index++) {
|
|
|
|
gfxFontEntry* fe = fontList[index];
|
|
|
|
if (!fe) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-09-12 22:34:57 +03:00
|
|
|
if (fe->Name().Equals(aFontName,
|
|
|
|
nsCaseInsensitiveCStringComparator())) {
|
2015-09-24 18:31:30 +03:00
|
|
|
fontEntry = static_cast<FT2FontEntry*>(fe);
|
|
|
|
goto searchDone;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
}
|
2015-09-24 18:31:30 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2009-10-07 18:13:40 +04:00
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
searchDone:
|
|
|
|
if (!fontEntry) {
|
2014-04-08 12:10:41 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-04-08 12:10:41 +04:00
|
|
|
// Clone the font entry so that we can then set its style descriptors
|
2014-09-08 11:23:20 +04:00
|
|
|
// from the userfont entry rather than the actual font.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-04-08 12:10:41 +04:00
|
|
|
// Ensure existence of mFTFace in the original entry
|
2015-09-24 18:31:30 +03:00
|
|
|
fontEntry->CairoFontFace();
|
|
|
|
if (!fontEntry->mFTFace) {
|
2014-04-08 12:10:41 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-09-24 18:31:30 +03:00
|
|
|
FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(
|
|
|
|
fontEntry->mFTFace, fontEntry->mFilename.get(), fontEntry->mFTFontIndex,
|
|
|
|
fontEntry->Name(), nullptr);
|
2014-04-08 12:10:41 +04:00
|
|
|
if (fe) {
|
2018-04-25 09:18:23 +03:00
|
|
|
fe->mStyleRange = aStyleForEntry;
|
|
|
|
fe->mWeightRange = aWeightForEntry;
|
|
|
|
fe->mStretchRange = aStretchForEntry;
|
2014-09-08 11:23:20 +04:00
|
|
|
fe->mIsLocalUserFont = true;
|
2014-04-08 12:10:41 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-04-08 12:10:41 +04:00
|
|
|
return fe;
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
|
|
|
|
2016-08-23 03:06:07 +03:00
|
|
|
gfxFontFamily* gfxFT2FontList::GetDefaultFontForPlatform(
|
|
|
|
const gfxFontStyle* aStyle) {
|
2014-06-06 10:09:23 +04:00
|
|
|
gfxFontFamily* ff = nullptr;
|
2016-10-27 03:17:10 +03:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
2018-09-12 22:34:57 +03:00
|
|
|
ff = FindFamily(NS_LITERAL_CSTRING("Roboto"));
|
2014-06-06 10:09:23 +04:00
|
|
|
if (!ff) {
|
2018-09-12 22:34:57 +03:00
|
|
|
ff = FindFamily(NS_LITERAL_CSTRING("Droid Sans"));
|
2012-06-21 10:45:55 +04:00
|
|
|
}
|
2009-10-07 18:13:40 +04:00
|
|
|
#endif
|
|
|
|
/* TODO: what about Qt or other platforms that may use this? */
|
2014-06-06 10:09:23 +04:00
|
|
|
return ff;
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
gfxFontEntry* gfxFT2FontList::MakePlatformFont(const nsACString& aFontName,
|
2018-04-25 09:18:23 +03:00
|
|
|
WeightRange aWeightForEntry,
|
|
|
|
StretchRange aStretchForEntry,
|
|
|
|
SlantStyleRange aStyleForEntry,
|
2014-09-08 11:23:19 +04:00
|
|
|
const uint8_t* aFontData,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aLength) {
|
2009-10-07 18:13:40 +04:00
|
|
|
// The FT2 font needs the font data to persist, so we do NOT free it here
|
|
|
|
// but instead pass ownership to the font entry.
|
|
|
|
// Deallocation will happen later, when the font face is destroyed.
|
2018-04-25 09:18:23 +03:00
|
|
|
return FT2FontEntry::CreateFontEntry(aFontName, aWeightForEntry,
|
|
|
|
aStretchForEntry, aStyleForEntry,
|
|
|
|
aFontData, aLength);
|
2009-10-07 18:13:40 +04:00
|
|
|
}
|
2011-09-23 15:16:13 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
void gfxFT2FontList::GetFontFamilyList(
|
|
|
|
nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray) {
|
2015-09-24 18:31:30 +03:00
|
|
|
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily>& family = iter.Data();
|
2015-09-24 18:31:30 +03:00
|
|
|
aFamilyArray.AppendElement(family);
|
|
|
|
}
|
2014-06-30 22:05:29 +04:00
|
|
|
}
|
2016-09-28 22:42:41 +03:00
|
|
|
|
2018-09-12 22:34:57 +03:00
|
|
|
gfxFontFamily* gfxFT2FontList::CreateFontFamily(const nsACString& aName) const {
|
2017-08-01 13:25:35 +03:00
|
|
|
return new FT2FontFamily(aName);
|
|
|
|
}
|
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
void gfxFT2FontList::WillShutdown() {
|
|
|
|
mozilla::scache::StartupCache* cache =
|
|
|
|
mozilla::scache::StartupCache::GetSingleton();
|
|
|
|
if (cache && mJarModifiedTime > 0) {
|
2018-02-17 02:30:47 +03:00
|
|
|
const size_t bufSize = sizeof(mJarModifiedTime);
|
|
|
|
auto buf = MakeUnique<char[]>(bufSize);
|
|
|
|
memcpy(buf.get(), &mJarModifiedTime, bufSize);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-28 22:42:41 +03:00
|
|
|
cache->PutBuffer(JAR_LAST_MODIFED_TIME, std::move(buf), bufSize);
|
|
|
|
}
|
|
|
|
mFontNameCache = nullptr;
|
|
|
|
}
|