merge mozilla-inbound to mozilla-central. r=merge a=merge

MozReview-Commit-ID: IgyDMUVYYBm
This commit is contained in:
Sebastian Hengst 2017-09-11 23:58:31 +02:00
Родитель e376f14721 f2b7e3f5a3
Коммит dbddac850d
30 изменённых файлов: 508 добавлений и 342 удалений

Просмотреть файл

@ -1481,6 +1481,8 @@ pref("toolkit.telemetry.archive.enabled", true);
pref("toolkit.telemetry.shutdownPingSender.enabled", true);
// Enables sending the shutdown ping using the pingsender from the first session.
pref("toolkit.telemetry.shutdownPingSender.enabledFirstSession", false);
// Enables sending a duplicate of the first shutdown ping from the first session.
pref("toolkit.telemetry.firstShutdownPing.enabled", true);
// Enables sending the 'new-profile' ping on new profiles.
pref("toolkit.telemetry.newProfilePing.enabled", true);
// Enables sending 'update' pings on Firefox updates.

Просмотреть файл

@ -3242,9 +3242,10 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
bool isCutCopy = (commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy"));
bool isPaste = commandID.LowerCaseEqualsLiteral("paste");
// if editing is not on, bail
if (!isCutCopy && !IsEditingOnAfterFlush()) {
if (!isCutCopy && !isPaste && !IsEditingOnAfterFlush()) {
return false;
}
@ -3285,9 +3286,8 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
return false;
}
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
if (restricted && !nsContentUtils::PrincipalHasPermission(&aSubjectPrincipal,
nsGkAtoms::clipboardRead)) {
if (isPaste && !nsContentUtils::PrincipalHasPermission(&aSubjectPrincipal,
nsGkAtoms::clipboardRead)) {
return false;
}

Просмотреть файл

@ -278,3 +278,4 @@ skip-if = toolkit == 'android' # chrome urls not available due to packaging
[test_selection_move_commands.html]
[test_pasteImgTextarea.html]
skip-if = toolkit == 'android' # bug 1299578
[test_execCommandPaste_noTarget.html]

Просмотреть файл

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script>
add_task(async function() {
let seenPaste = false;
let seenCopy = false;
document.addEventListener("copy", function oncpy(e) {
document.removeEventListener("copy", oncpy);
e.clipboardData.setData("text/plain", "my text");
e.preventDefault();
seenCopy = true;
});
document.addEventListener("paste", function onpst(e) {
document.removeEventListener("paste", onpst);
is(e.clipboardData.getData("text/plain"), "my text",
"The correct text was read from the clipboard");
e.preventDefault();
seenPaste = true;
});
ok(SpecialPowers.wrap(document).execCommand("copy"),
"Call should succeed");
ok(seenCopy, "Successfully copied the text to the clipboard");
ok(SpecialPowers.wrap(document).execCommand("paste"),
"Call should succeed");
ok(seenPaste, "Successfully read text from the clipboard");
// Check that reading text from the clipboard in non-privileged contexts
// still doesn't work.
function onpstfail(e) {
ok(false, "Should not see paste event triggered by non-privileged call");
}
document.addEventListener("paste", onpstfail);
ok(!document.execCommand("paste"), "Call should fail");
document.removeEventListener("paste", onpstfail);
});
</script>
</body>
</html>

Просмотреть файл

@ -340,6 +340,19 @@ gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
aLocalizedName = nsDependentString(famName.Elements());
}
bool
gfxDWriteFontFamily::IsSymbolFontFamily() const
{
// Just check the first font in the family
if (mDWFamily->GetFontCount() > 0) {
RefPtr<IDWriteFont> font;
if (SUCCEEDED(mDWFamily->GetFont(0, getter_AddRefs(font)))) {
return font->IsSymbolFont();
}
}
return false;
}
void
gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const
@ -371,16 +384,6 @@ gfxDWriteFontEntry::~gfxDWriteFontEntry()
{
}
bool
gfxDWriteFontEntry::IsSymbolFont()
{
if (mFont) {
return mFont->IsSymbolFont();
} else {
return false;
}
}
static bool
UsingArabicOrHebrewScriptSystemLocale()
{
@ -532,11 +535,9 @@ gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
RefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont;
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
mUVSOffset))) {
rv = NS_OK;
} else {
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
@ -544,14 +545,12 @@ gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
*charmap, mUVSOffset);
} else {
rv = NS_ERROR_NOT_AVAILABLE;
}
@ -1673,7 +1672,6 @@ DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
if (SUCCEEDED(hr)) {
bool cmapLoaded = false;
bool unicodeFont = false, symbolFont = false;
RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t offset;
@ -1681,10 +1679,9 @@ DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
cmapSize > 0 &&
NS_SUCCEEDED(
gfxFontUtils::ReadCMAP(cmapData, cmapSize, *charmap,
offset, unicodeFont, symbolFont))) {
offset))) {
fontData.mCharacterMap = charmap;
fontData.mUVSOffset = offset;
fontData.mSymbolFont = symbolFont;
cmapLoaded = true;
mLoadStats.cmaps++;
}

Просмотреть файл

@ -60,7 +60,15 @@ public:
void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const final;
bool FilterForFontList(nsIAtom* aLangGroup,
const nsACString& aGeneric) const final {
return !IsSymbolFontFamily();
}
protected:
// helper for FilterForFontList
bool IsSymbolFontFamily() const;
/** This font family's directwrite fontfamily object */
RefPtr<IDWriteFontFamily> mDWFamily;
bool mForceGDIClassic;
@ -154,8 +162,6 @@ public:
virtual ~gfxDWriteFontEntry();
virtual bool IsSymbolFont();
virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override;
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);

Просмотреть файл

@ -484,11 +484,8 @@ FT2FontEntry::ReadCMAP(FontInfoData *aFontInfoData)
nsresult rv = CopyFontTable(TTAG_cmap, buffer);
if (NS_SUCCEEDED(rv)) {
bool unicodeFont;
bool symbolFont;
rv = gfxFontUtils::ReadCMAP(buffer.Elements(), buffer.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
*charmap, mUVSOffset);
}
if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {

Просмотреть файл

@ -325,39 +325,6 @@ gfxFontconfigFontEntry::~gfxFontconfigFontEntry()
{
}
static bool
PatternHasLang(const FcPattern *aPattern, const FcChar8 *aLang)
{
FcLangSet *langset;
if (FcPatternGetLangSet(aPattern, FC_LANG, 0, &langset) != FcResultMatch) {
return false;
}
if (FcLangSetHasLang(langset, aLang) != FcLangDifferentLang) {
return true;
}
return false;
}
bool
gfxFontconfigFontEntry::SupportsLangGroup(nsIAtom *aLangGroup) const
{
if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
return true;
}
nsAutoCString fcLang;
gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
pfl->GetSampleLangForGroup(aLangGroup, fcLang);
if (fcLang.IsEmpty()) {
return true;
}
// is lang included in the underlying pattern?
return PatternHasLang(mFontPattern, ToFcChar8Ptr(fcLang.get()));
}
nsresult
gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
@ -368,11 +335,9 @@ gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
RefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont = false; // currently ignored
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
mUVSOffset))) {
rv = NS_OK;
} else {
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
@ -380,14 +345,12 @@ gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
*charmap, mUVSOffset);
} else {
rv = NS_ERROR_NOT_AVAILABLE;
}
@ -1189,6 +1152,54 @@ gfxFontconfigFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
}
}
static bool
PatternHasLang(const FcPattern *aPattern, const FcChar8 *aLang)
{
FcLangSet *langset;
if (FcPatternGetLangSet(aPattern, FC_LANG, 0, &langset) != FcResultMatch) {
return false;
}
if (FcLangSetHasLang(langset, aLang) != FcLangDifferentLang) {
return true;
}
return false;
}
bool
gfxFontconfigFontFamily::SupportsLangGroup(nsIAtom *aLangGroup) const
{
if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
return true;
}
nsAutoCString fcLang;
gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
pfl->GetSampleLangForGroup(aLangGroup, fcLang);
if (fcLang.IsEmpty()) {
return true;
}
// Before FindStyleVariations has been called, mFontPatterns will contain
// the font patterns. Afterward, it'll be empty, but mAvailableFonts
// will contain the font entries, each of which holds a reference to its
// pattern. We only check the first pattern in each list, because support
// for langs is considered to be consistent across all faces in a family.
FcPattern* fontPattern;
if (mFontPatterns.Length()) {
fontPattern = mFontPatterns[0];
} else if (mAvailableFonts.Length()) {
fontPattern = static_cast<gfxFontconfigFontEntry*>
(mAvailableFonts[0].get())->GetPattern();
} else {
return true;
}
// is lang included in the underlying pattern?
return PatternHasLang(fontPattern, ToFcChar8Ptr(fcLang.get()));
}
/* virtual */
gfxFontconfigFontFamily::~gfxFontconfigFontFamily()
{

Просмотреть файл

@ -99,8 +99,6 @@ public:
FcPattern* GetPattern() { return mFontPattern; }
bool SupportsLangGroup(nsIAtom *aLangGroup) const override;
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
bool TestCharacterMap(uint32_t aCh) override;
@ -201,9 +199,17 @@ public:
bool& aNeedsSyntheticBold,
bool aIgnoreSizeTolerance) override;
bool FilterForFontList(nsIAtom* aLangGroup,
const nsACString& aGeneric) const final {
return SupportsLangGroup(aLangGroup);
}
protected:
virtual ~gfxFontconfigFontFamily();
// helper for FilterForFontList
bool SupportsLangGroup(nsIAtom *aLangGroup) const;
nsTArray<nsCountedRef<FcPattern> > mFontPatterns;
bool mContainsAppFonts;

Просмотреть файл

@ -65,7 +65,6 @@ gfxFontEntry::gfxFontEntry() :
mIsDataUserFont(false),
mIsLocalUserFont(false),
mStandardFace(false),
mSymbolFont(false),
mIgnoreGDEF(false),
mIgnoreGSUB(false),
mSVGInitialized(false),
@ -104,7 +103,6 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
mIsUserFontContainer(false),
mIsDataUserFont(false),
mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
mSymbolFont(false),
mIgnoreGDEF(false),
mIgnoreGSUB(false),
mSVGInitialized(false),
@ -168,11 +166,6 @@ gfxFontEntry::~gfxFontEntry()
MOZ_ASSERT(!mGrFaceInitialized);
}
bool gfxFontEntry::IsSymbolFont()
{
return mSymbolFont;
}
bool gfxFontEntry::TestCharacterMap(uint32_t aCh)
{
if (!mCharacterMap) {
@ -602,14 +595,13 @@ gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
already_AddRefed<gfxCharacterMap>
gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
uint32_t& aUVSOffset,
bool& aSymbolFont)
uint32_t& aUVSOffset)
{
if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
return nullptr;
}
return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
return aFontInfoData->GetCMAP(mName, aUVSOffset);
}
hb_blob_t *

Просмотреть файл

@ -152,8 +152,6 @@ public:
const hb_set_t*
InputsForOpenTypeFeature(Script aScript, uint32_t aFeatureTag);
virtual bool IsSymbolFont();
virtual bool HasFontTable(uint32_t aTableTag);
inline bool HasGraphiteTables() {
@ -207,13 +205,6 @@ public:
nsTArray<uint16_t>& layerGlyphs,
nsTArray<mozilla::gfx::Color>& layerColors);
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
return true;
}
virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
return true;
}
// Access to raw font table data (needed for Harfbuzz):
// returns a pointer to data owned by the fontEntry or the OS,
// which will remain valid until the blob is destroyed.
@ -351,7 +342,6 @@ public:
bool mIsDataUserFont : 1; // platform font entry (data)
bool mIsLocalUserFont : 1; // platform font entry (local)
bool mStandardFace : 1;
bool mSymbolFont : 1;
bool mIgnoreGDEF : 1;
bool mIgnoreGSUB : 1;
bool mSVGInitialized : 1;
@ -423,8 +413,7 @@ protected:
// lookup the cmap in cached font data
virtual already_AddRefed<gfxCharacterMap>
GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
uint32_t& aUVSOffset,
bool& aSymbolFont);
uint32_t& aUVSOffset);
// helper for HasCharacter(), which is what client code should call
virtual bool TestCharacterMap(uint32_t aCh);
@ -764,6 +753,17 @@ public:
mSkipDefaultFeatureSpaceCheck = aSkipCheck;
}
// Check whether this family is appropriate to include in the Preferences
// font list for the given langGroup and CSS generic, if the platform lets
// us determine this.
// Return true if the family should be included in the list, false to omit.
// Default implementation returns true for everything, so no filtering
// will occur; individual platforms may override.
virtual bool FilterForFontList(nsIAtom* aLangGroup,
const nsACString& aGeneric) const {
return true;
}
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~gfxFontFamily();

Просмотреть файл

@ -21,21 +21,19 @@
// data retrieved for a given face
struct FontFaceData {
FontFaceData() : mUVSOffset(0), mSymbolFont(false) {}
FontFaceData() : mUVSOffset(0) {}
FontFaceData(const FontFaceData& aFontFaceData) {
mFullName = aFontFaceData.mFullName;
mPostscriptName = aFontFaceData.mPostscriptName;
mCharacterMap = aFontFaceData.mCharacterMap;
mUVSOffset = aFontFaceData.mUVSOffset;
mSymbolFont = aFontFaceData.mSymbolFont;
}
nsString mFullName;
nsString mPostscriptName;
RefPtr<gfxCharacterMap> mCharacterMap;
uint32_t mUVSOffset;
bool mSymbolFont;
};
// base class used to contain cached system-wide font info.
@ -78,8 +76,7 @@ public:
// fetches cmap data for a particular font from cached font data
virtual already_AddRefed<gfxCharacterMap>
GetCMAP(const nsAString& aFontName,
uint32_t& aUVSOffset,
bool& aSymbolFont)
uint32_t& aUVSOffset)
{
FontFaceData faceData;
if (!mFontFaceData.Get(aFontName, &faceData) ||
@ -88,7 +85,6 @@ public:
}
aUVSOffset = faceData.mUVSOffset;
aSymbolFont = faceData.mSymbolFont;
RefPtr<gfxCharacterMap> cmap = faceData.mCharacterMap;
return cmap.forget();
}

Просмотреть файл

@ -413,8 +413,7 @@ gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
uint32_t
gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
uint32_t *aTableOffset,
uint32_t *aUVSTableOffset,
bool *aSymbolEncoding)
uint32_t *aUVSTableOffset)
{
enum {
OffsetVersion = 0,
@ -474,17 +473,14 @@ gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
if (isSymbol(platformID, encodingID)) {
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = true;
break;
} else if (format == 4 && acceptableFormat4(platformID, encodingID, keepFormat)) {
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = false;
} else if ((format == 10 || format == 12 || format == 13) &&
acceptableUCS4Encoding(platformID, encodingID, keepFormat)) {
keepFormat = format;
*aTableOffset = offset;
*aSymbolEncoding = false;
if (platformID > PLATFORM_ID_UNICODE || !aUVSTableOffset || *aUVSTableOffset) {
break; // we don't want to try anything else when this format is available.
}
@ -502,36 +498,23 @@ gfxFontUtils::FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
nsresult
gfxFontUtils::ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
gfxSparseBitSet& aCharacterMap,
uint32_t& aUVSOffset,
bool& aUnicodeFont, bool& aSymbolFont)
uint32_t& aUVSOffset)
{
uint32_t offset;
bool symbol;
uint32_t format = FindPreferredSubtable(aBuf, aBufLength,
&offset, &aUVSOffset, &symbol);
&offset, &aUVSOffset);
switch (format) {
case 4:
if (symbol) {
aUnicodeFont = false;
aSymbolFont = true;
} else {
aUnicodeFont = true;
aSymbolFont = false;
}
return ReadCMAPTableFormat4(aBuf + offset, aBufLength - offset,
aCharacterMap);
case 10:
aUnicodeFont = true;
aSymbolFont = false;
return ReadCMAPTableFormat10(aBuf + offset, aBufLength - offset,
aCharacterMap);
case 12:
case 13:
aUnicodeFont = true;
aSymbolFont = false;
return ReadCMAPTableFormat12or13(aBuf + offset, aBufLength - offset,
aCharacterMap);
@ -769,9 +752,8 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
uint32_t aUnicode, uint32_t aVarSelector)
{
uint32_t offset, uvsOffset;
bool symbol;
uint32_t format = FindPreferredSubtable(aCmapBuf, aBufLength, &offset,
&uvsOffset, &symbol);
&uvsOffset);
uint32_t gid;
switch (format) {

Просмотреть файл

@ -794,14 +794,12 @@ public:
static uint32_t
FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
uint32_t *aTableOffset, uint32_t *aUVSTableOffset,
bool *aSymbolEncoding);
uint32_t *aTableOffset, uint32_t *aUVSTableOffset);
static nsresult
ReadCMAP(const uint8_t *aBuf, uint32_t aBufLength,
gfxSparseBitSet& aCharacterMap,
uint32_t& aUVSOffset,
bool& aUnicodeFont, bool& aSymbolFont);
uint32_t& aUVSOffset);
static uint32_t
MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh);

Просмотреть файл

@ -120,11 +120,10 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
gfxUserFontData *aUserFontData,
bool aFamilyHasItalicFace)
: gfxFontEntry(aFaceName),
mWindowsFamily(0), mWindowsPitch(0),
mFontType(aFontType),
mForceGDI(false),
mFamilyHasItalicFace(aFamilyHasItalicFace),
mCharset(), mUnicodeRanges()
mUnicodeRanges()
{
mUserFontData.reset(aUserFontData);
mStyle = aStyle;
@ -167,12 +166,9 @@ GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
RefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool unicodeFont = false, symbolFont = false;
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
mSymbolFont = symbolFont;
mUVSOffset))) {
rv = NS_OK;
} else {
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
@ -182,10 +178,8 @@ GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
if (NS_SUCCEEDED(rv)) {
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
*charmap, mUVSOffset);
}
mSymbolFont = symbolFont;
}
mHasCmapTable = NS_SUCCEEDED(rv);
@ -214,14 +208,6 @@ GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
return rv;
}
bool
GDIFontEntry::IsSymbolFont()
{
// initialize cmap first
HasCmapTable();
return mSymbolFont;
}
gfxFont *
GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
{
@ -486,7 +472,9 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
if (fe->mWeight == logFont.lfWeight &&
fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
// update the charset bit here since this could be different
fe->mCharset.set(metrics.tmCharSet);
// XXX Can we still do this now that we store mCharset
// on the font family rather than the font entry?
ff->mCharset.set(metrics.tmCharSet);
return 1;
}
}
@ -505,12 +493,6 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
ff->AddFontEntry(fe);
// mark the charset bit
fe->mCharset.set(metrics.tmCharSet);
fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
@ -713,6 +695,7 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
DWORD fontType,
LPARAM lParam)
{
const NEWTEXTMETRICW& metrics = lpntme->ntmTm;
const LOGFONTW& lf = lpelfe->elfLogFont;
if (lf.lfFaceName[0] == '@') {
@ -726,7 +709,7 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
if (!fontList->mFontFamilies.GetWeak(name)) {
nsDependentString faceName(lf.lfFaceName);
RefPtr<gfxFontFamily> family = new GDIFontFamily(faceName);
RefPtr<GDIFontFamily> family = new GDIFontFamily(faceName);
fontList->mFontFamilies.Put(name, family);
// if locale is such that CJK font names are the default coming from
@ -739,6 +722,12 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
if (fontList->mBadUnderlineFamilyNames.Contains(name))
family->SetBadUnderlineFamily();
family->mWindowsFamily = lf.lfPitchAndFamily & 0xF0;
family->mWindowsPitch = lf.lfPitchAndFamily & 0x0F;
// mark the charset bit
family->mCharset.set(metrics.tmCharSet);
}
return 1;
@ -1118,17 +1107,14 @@ int CALLBACK GDIFontInfo::EnumerateFontsForFamily(
cmapData.SetLength(cmapSize, fallible)) {
::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize);
bool cmapLoaded = false;
bool unicodeFont = false, symbolFont = false;
RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t offset;
if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(),
cmapSize, *charmap,
offset, unicodeFont,
symbolFont))) {
offset))) {
fontData.mCharacterMap = charmap;
fontData.mUVSOffset = offset;
fontData.mSymbolFont = symbolFont;
cmapLoaded = true;
famData->mFontInfo.mLoadStats.cmaps++;
}

Просмотреть файл

@ -109,9 +109,7 @@ class GDIFontEntry : public gfxFontEntry
public:
LPLOGFONTW GetLogFont() { return &mLogFont; }
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
virtual bool IsSymbolFont();
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
void FillLogFont(LOGFONTW *aLogFont, uint16_t aWeight, gfxFloat aSize);
@ -147,7 +145,97 @@ public:
mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
}
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
virtual bool SupportsRange(uint8_t range) {
return mUnicodeRanges.test(range);
}
virtual bool SkipDuringSystemFallback() {
return !HasCmapTable(); // explicitly skip non-SFNT fonts
}
virtual bool TestCharacterMap(uint32_t aCh);
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
gfxFontEntry* Clone() const override;
// create a font entry for a font with a given name
static GDIFontEntry* CreateFontEntry(const nsAString& aName,
gfxWindowsFontType aFontType,
uint8_t aStyle,
uint16_t aWeight, int16_t aStretch,
gfxUserFontData* aUserFontData,
bool aFamilyHasItalicFace);
// create a font entry for a font referenced by its fullname
static GDIFontEntry* LoadLocalFont(const nsAString& aFontName,
uint16_t aWeight,
int16_t aStretch,
uint8_t aStyle);
gfxWindowsFontType mFontType;
bool mForceGDI : 1;
// For src:local user-fonts, we keep track of whether the platform family
// contains an italic face, because in this case we can't safely ask GDI
// to create synthetic italics (oblique) via the LOGFONT.
// (For other types of font, this is just set to false.)
bool mFamilyHasItalicFace : 1;
gfxSparseBitSet mUnicodeRanges;
protected:
friend class gfxGDIFont;
GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
gfxUserFontData *aUserFontData, bool aFamilyHasItalicFace);
void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle,
bool aNeedsBold) override;
virtual nsresult CopyFontTable(uint32_t aTableTag,
nsTArray<uint8_t>& aBuffer) override;
already_AddRefed<mozilla::gfx::UnscaledFontGDI> LookupUnscaledFont(HFONT aFont);
LOGFONTW mLogFont;
mozilla::WeakPtr<mozilla::gfx::UnscaledFont> mUnscaledFont;
};
// a single font family, referencing one or more faces
class GDIFontFamily : public gfxFontFamily
{
public:
explicit GDIFontFamily(const nsAString& aName) :
gfxFontFamily(aName),
mWindowsFamily(0),
mWindowsPitch(0),
mCharset()
{}
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
bool FilterForFontList(nsIAtom* aLangGroup,
const nsACString& aGeneric) const final {
return !IsSymbolFontFamily() &&
SupportsLangGroup(aLangGroup) &&
MatchesGenericFamily(aGeneric);
}
protected:
friend class gfxGDIFontList;
// helpers for FilterForFontList
bool IsSymbolFontFamily() const {
return mCharset.test(SYMBOL_CHARSET);
}
bool MatchesGenericFamily(const nsACString& aGeneric) const {
if (aGeneric.IsEmpty()) {
return true;
}
@ -183,7 +271,7 @@ public:
return false;
}
virtual bool SupportsLangGroup(nsIAtom* aLangGroup) const override {
bool SupportsLangGroup(nsIAtom* aLangGroup) const {
if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
return true;
}
@ -220,79 +308,10 @@ public:
return false;
}
virtual bool SupportsRange(uint8_t range) {
return mUnicodeRanges.test(range);
}
virtual bool SkipDuringSystemFallback() {
return !HasCmapTable(); // explicitly skip non-SFNT fonts
}
virtual bool TestCharacterMap(uint32_t aCh);
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
gfxFontEntry* Clone() const override;
// create a font entry for a font with a given name
static GDIFontEntry* CreateFontEntry(const nsAString& aName,
gfxWindowsFontType aFontType,
uint8_t aStyle,
uint16_t aWeight, int16_t aStretch,
gfxUserFontData* aUserFontData,
bool aFamilyHasItalicFace);
// create a font entry for a font referenced by its fullname
static GDIFontEntry* LoadLocalFont(const nsAString& aFontName,
uint16_t aWeight,
int16_t aStretch,
uint8_t aStyle);
uint8_t mWindowsFamily;
uint8_t mWindowsPitch;
gfxWindowsFontType mFontType;
bool mForceGDI : 1;
// For src:local user-fonts, we keep track of whether the platform family
// contains an italic face, because in this case we can't safely ask GDI
// to create synthetic italics (oblique) via the LOGFONT.
// (For other types of font, this is just set to false.)
bool mFamilyHasItalicFace : 1;
gfxSparseBitSet mCharset;
gfxSparseBitSet mUnicodeRanges;
protected:
friend class gfxGDIFont;
GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
gfxUserFontData *aUserFontData, bool aFamilyHasItalicFace);
void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
virtual nsresult CopyFontTable(uint32_t aTableTag,
nsTArray<uint8_t>& aBuffer) override;
already_AddRefed<mozilla::gfx::UnscaledFontGDI> LookupUnscaledFont(HFONT aFont);
LOGFONTW mLogFont;
mozilla::WeakPtr<mozilla::gfx::UnscaledFont> mUnscaledFont;
};
// a single font family, referencing one or more faces
class GDIFontFamily : public gfxFontFamily
{
public:
explicit GDIFontFamily(const nsAString& aName) :
gfxFontFamily(aName) {}
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
private:
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,

Просмотреть файл

@ -1275,11 +1275,9 @@ gfxHarfBuzzShaper::Initialize()
}
uint32_t len;
const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, &len);
bool symbol;
mCmapFormat = gfxFontUtils::
FindPreferredSubtable(data, len,
&mSubtableOffset, &mUVSTableOffset,
&symbol);
&mSubtableOffset, &mUVSTableOffset);
if (mCmapFormat <= 0) {
return false;
}

Просмотреть файл

@ -152,11 +152,9 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
RefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont = false; // currently ignored
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
mUVSOffset))) {
rv = NS_OK;
} else {
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
@ -164,14 +162,12 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
*charmap, mUVSOffset);
} else {
rv = NS_ERROR_NOT_AVAILABLE;
}
@ -1479,16 +1475,12 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
uint32_t cmapLen = CFDataGetLength(cmapTable);
RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t offset;
bool unicodeFont = false; // ignored
bool symbolFont = false;
nsresult rv;
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset,
unicodeFont, symbolFont);
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset);
if (NS_SUCCEEDED(rv)) {
fontData.mCharacterMap = charmap;
fontData.mUVSOffset = offset;
fontData.mSymbolFont = symbolFont;
mLoadStats.cmaps++;
}
CFRelease(cmapTable);

Просмотреть файл

@ -483,25 +483,7 @@ gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
{
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
RefPtr<gfxFontFamily>& family = iter.Data();
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = aLangGroup;
bool needsBold;
RefPtr<gfxFontEntry> fontEntry = family->FindFontForStyle(style, needsBold);
NS_ASSERTION(fontEntry, "couldn't find any font entry in family");
if (!fontEntry) {
continue;
}
/* skip symbol fonts */
if (fontEntry->IsSymbolFont()) {
continue;
}
if (fontEntry->SupportsLangGroup(aLangGroup) &&
fontEntry->MatchesGenericFamily(aGenericFamily)) {
if (family->FilterForFontList(aLangGroup, aGenericFamily)) {
nsAutoString localizedFamilyName;
family->LocalizedName(localizedFamilyName);
aListOfFonts.AppendElement(localizedFamilyName);

Просмотреть файл

@ -4493,7 +4493,6 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
}
mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
nsCSSFrameConstructor::InsertionKind::Async,
nsCSSFrameConstructor::REMOVE_CONTENT);
if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {

Просмотреть файл

@ -7526,8 +7526,7 @@ nsCSSFrameConstructor::GetRangeInsertionPoint(nsIContent* aContainer,
bool
nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
nsIContent* aStartChild,
nsIContent* aEndChild,
InsertionKind aInsertionKind)
nsIContent* aEndChild)
{
if (aParentFrame->IsFrameSetFrame()) {
// Check whether we have any kids we care about.
@ -7536,7 +7535,8 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
cur = cur->GetNextSibling()) {
if (IsSpecialFramesetChild(cur)) {
// Just reframe the parent, since framesets are weird like that.
RecreateFramesForContent(aParentFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aParentFrame->GetContent(),
InsertionKind::Async);
return true;
}
}
@ -7592,7 +7592,8 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
{
MOZ_ASSERT(!aProvidedTreeMatchContext ||
aInsertionKind == InsertionKind::Sync);
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync || !RestyleManager()->IsInStyleRefresh());
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
!RestyleManager()->IsInStyleRefresh());
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
@ -7695,7 +7696,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
}
LAYOUT_PHASE_TEMP_EXIT();
if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr, aInsertionKind)) {
if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
LAYOUT_PHASE_TEMP_REENTER();
return;
}
@ -7829,7 +7830,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
// appending, so let WipeContainingBlock know that.
LAYOUT_PHASE_TEMP_EXIT();
if (WipeContainingBlock(state, containingBlock, parentFrame, items,
true, prevSibling, aInsertionKind)) {
true, prevSibling)) {
LAYOUT_PHASE_TEMP_REENTER();
return;
}
@ -8013,7 +8014,8 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
{
MOZ_ASSERT(!aProvidedTreeMatchContext ||
aInsertionKind == InsertionKind::Sync);
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync || !RestyleManager()->IsInStyleRefresh());
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
!RestyleManager()->IsInStyleRefresh());
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
@ -8212,7 +8214,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
LayoutFrameType frameType = insertion.mParentFrame->Type();
LAYOUT_PHASE_TEMP_EXIT();
if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild, aInsertionKind)) {
if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) {
LAYOUT_PHASE_TEMP_REENTER();
return;
}
@ -8410,7 +8412,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// appending, so let WipeContainingBlock know that.
LAYOUT_PHASE_TEMP_EXIT();
if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
isAppend, prevSibling, aInsertionKind)) {
isAppend, prevSibling)) {
LAYOUT_PHASE_TEMP_REENTER();
return;
}
@ -8603,18 +8605,12 @@ bool
nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aOldNextSibling,
InsertionKind aInsertionKind,
RemoveFlags aFlags)
{
MOZ_ASSERT(aChild);
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
"Should be in an update while destroying frames");
// We only want to recreate sync if we're already in frame construction, that
// is, recreate async for XBL DOM changes, and normal content removals.
MOZ_ASSERT(aFlags == REMOVE_FOR_RECONSTRUCTION ||
aInsertionKind == InsertionKind::Async);
nsPresContext* presContext = mPresShell->GetPresContext();
MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
@ -8664,7 +8660,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// XXXmats Can we recreate frames only for the ::after/::before content?
// XXX Perhaps even only those that belong to the aChild sub-tree?
LAYOUT_PHASE_TEMP_EXIT();
RecreateFramesForContent(ancestor, aInsertionKind);
RecreateFramesForContent(ancestor, InsertionKind::Async);
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -8674,8 +8670,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
LAYOUT_PHASE_TEMP_EXIT();
bool didReconstruct =
ContentRemoved(aChild, c, nullptr, aInsertionKind,
REMOVE_FOR_RECONSTRUCTION);
ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
if (didReconstruct) {
return true;
@ -8725,7 +8720,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// XXXsmaug This is super unefficient!
nsIContent* bindingParent = aContainer->GetBindingParent();
LAYOUT_PHASE_TEMP_EXIT();
RecreateFramesForContent(bindingParent, aInsertionKind);
RecreateFramesForContent(bindingParent, InsertionKind::Async);
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -8735,7 +8730,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// See whether we need to remove more than just childFrame
LAYOUT_PHASE_TEMP_EXIT();
if (MaybeRecreateContainerForFrameRemoval(childFrame, aInsertionKind)) {
if (MaybeRecreateContainerForFrameRemoval(childFrame)) {
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -8749,7 +8744,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
IsSpecialFramesetChild(aChild)) {
// Just reframe the parent, since framesets are weird like that.
LAYOUT_PHASE_TEMP_EXIT();
RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -8762,7 +8757,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
: parentFrame;
if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
LAYOUT_PHASE_TEMP_EXIT();
RecreateFramesForContent(parentFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(parentFrame->GetContent(), InsertionKind::Async);
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -8777,7 +8772,8 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
!AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
LAYOUT_PHASE_TEMP_EXIT();
RecreateFramesForContent(grandparentFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(grandparentFrame->GetContent(),
InsertionKind::Async);
LAYOUT_PHASE_TEMP_REENTER();
return true;
}
@ -9709,9 +9705,7 @@ FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
}
bool
nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
nsIFrame* aFrame,
InsertionKind aInsertionKind)
nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
@ -9730,14 +9724,15 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
}
#endif
ReframeContainingBlock(aFrame, aInsertionKind);
ReframeContainingBlock(aFrame);
return true;
}
nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
if (insertionFrame && insertionFrame->IsLegendFrame() &&
aFrame->GetParent()->IsFieldSetFrame()) {
RecreateFramesForContent(aFrame->GetParent()->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetParent()->GetContent(),
InsertionKind::Async);
return true;
}
@ -9761,7 +9756,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
// When removing a summary, we should reframe the parent details frame to
// ensure that another summary is used or the default summary is
// generated.
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
}
@ -9784,7 +9779,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
// Similar if we're a table-caption.
(inFlowFrame->IsTableCaption() &&
parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
}
@ -9813,7 +9808,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
#endif
// Good enough to recreate frames for aFrame's parent's content; even if
// aFrame's parent is a pseudo, that'll be the right content node.
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
}
@ -9829,7 +9824,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
// frames may be constructed or destroyed accordingly.
// 2. The type of the first child of a ruby frame determines
// whether a pseudo ruby base container should exist.
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -9852,7 +9847,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's parent)
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -9870,7 +9865,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's grandparent)
RecreateFramesForContent(parent->GetParent()->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetParent()->GetContent(),
InsertionKind::Async);
return true;
}
@ -9878,7 +9874,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
if (aFrame->IsPopupSetFrame()) {
nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
ReconstructDocElementHierarchy(aInsertionKind);
ReconstructDocElementHierarchy(InsertionKind::Async);
return true;
}
}
@ -9890,7 +9886,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
!inFlowFrame->GetNextSibling() &&
((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
(parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
RecreateFramesForContent(parent->GetContent(), aInsertionKind);
RecreateFramesForContent(parent->GetContent(), InsertionKind::Async);
return true;
}
@ -9926,7 +9922,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
}
#endif
ReframeContainingBlock(parent, aInsertionKind);
ReframeContainingBlock(parent);
return true;
}
@ -9985,7 +9981,7 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
if (nonGeneratedAncestor->GetContent() != aContent) {
return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
aInsertionKind);
InsertionKind::Async);
}
if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
@ -10005,7 +10001,8 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
if (!ancestor->IsSVGUseFrame()) {
NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
"Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
return RecreateFramesForContent(ancestor->GetContent(), aInsertionKind);
return RecreateFramesForContent(ancestor->GetContent(),
InsertionKind::Async);
}
}
@ -10016,11 +10013,11 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
// with native anonymous content from the editor.
if (parent && parent->IsLeaf() && parentContent &&
parentContent != aContent) {
return RecreateFramesForContent(parentContent, aInsertionKind);
return RecreateFramesForContent(parentContent, InsertionKind::Async);
}
}
if (frame && MaybeRecreateContainerForFrameRemoval(frame, aInsertionKind)) {
if (frame && MaybeRecreateContainerForFrameRemoval(frame)) {
return;
}
@ -10039,7 +10036,7 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
nullptr : aContent->GetNextSibling();
bool didReconstruct =
ContentRemoved(container, aContent, nextSibling, aInsertionKind,
ContentRemoved(container, aContent, nextSibling,
REMOVE_FOR_RECONSTRUCTION);
if (!didReconstruct) {
@ -10079,7 +10076,6 @@ nsCSSFrameConstructor::DestroyFramesFor(Element* aElement)
return ContentRemoved(aElement->GetParent(),
aElement,
nextSibling,
InsertionKind::Async,
REMOVE_FOR_RECONSTRUCTION);
}
@ -12759,8 +12755,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
nsIFrame* aFrame,
FrameConstructionItemList& aItems,
bool aIsAppend,
nsIFrame* aPrevSibling,
InsertionKind aInsertionKind)
nsIFrame* aPrevSibling)
{
if (aItems.IsEmpty()) {
return false;
@ -12774,7 +12769,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (aFrame->IsXULBoxFrame() &&
!(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
aItems.AnyItemsNeedBlockParent()) {
RecreateFramesForContent(aFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -12793,7 +12788,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame);
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
RecreateFramesForContent(aFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -12804,7 +12799,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
RecreateFramesForContent(aFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
}
@ -12832,7 +12827,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState, isWebkitBox)) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
RecreateFramesForContent(containerFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(containerFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -12855,7 +12850,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// We want to optimize it better, and avoid reframing as much as
// possible. But given the cases above, and the fact that a ruby
// usually won't be very large, it should be fine to reframe it.
RecreateFramesForContent(aFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
@ -13021,7 +13016,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (!aItems.AllWantParentType(parentType)) {
// Reframing aFrame->GetContent() is good enough, since the content of
// table pseudo-frames is the ancestor content.
RecreateFramesForContent(aFrame->GetContent(), aInsertionKind);
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
}
@ -13109,13 +13104,12 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
static_cast<void*>(blockContent));
}
#endif
RecreateFramesForContent(blockContent, aInsertionKind);
RecreateFramesForContent(blockContent, InsertionKind::Async);
return true;
}
void
nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
InsertionKind aInsertionKind)
nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
{
#ifdef DEBUG
@ -13157,14 +13151,14 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
}
#endif
RecreateFramesForContent(blockContent->AsElement(), aInsertionKind);
RecreateFramesForContent(blockContent->AsElement(), InsertionKind::Async);
return;
}
}
// If we get here, we're screwed!
RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
aInsertionKind);
InsertionKind::Async);
}
void

Просмотреть файл

@ -79,9 +79,14 @@ public:
/**
* Whether insertion should be done synchronously or asynchronously.
*
* Generally, insertion is synchronous if we're reconstructing something from
* frame construction/reconstruction, and async if we're removing stuff, like
* from ContentRemoved.
* Generally, insertion is synchronous if we're entering frame construction
* from restyle processing, and async if we're removing stuff, or need to
* reconstruct some ancestor.
*
* Note that constructing async from frame construction will post a restyle
* event, but won't need another whole refresh driver tick to go in. Instead
* change hint processing will keep going as long as there are changes in the
* queue.
*/
enum class InsertionKind
{
@ -177,8 +182,7 @@ private:
// Returns true if parent was recreated due to frameset child, false otherwise.
bool MaybeRecreateForFrameset(nsIFrame* aParentFrame,
nsIContent* aStartChild,
nsIContent* aEndChild,
InsertionKind);
nsIContent* aEndChild);
/**
* For each child in the aStartChild/aEndChild range, calls
@ -300,14 +304,12 @@ public:
*
* The return value indicates whether this "reconstruct an ancestor" action
* took place. If true is returned, that means that the frame subtree rooted
* at some ancestor of aChild's frame was destroyed and either has been
* reconstructed or will be reconstructed async, depending on the value of
* aInsertionKind.
* at some ancestor of aChild's frame was destroyed and will be reconstructed
* async.
*/
bool ContentRemoved(nsIContent* aContainer,
nsIContent* aChild,
nsIContent* aOldNextSibling,
InsertionKind aInsertionKind,
RemoveFlags aFlags);
void CharacterDataChanged(nsIContent* aContent,
@ -1875,8 +1877,7 @@ private:
// indicates whether this happened. aFrame must be the result of a
// GetPrimaryFrame() call on a content node (which means its parent is also
// not null).
bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
InsertionKind aInsertionKind);
bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame);
nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@ -1998,10 +1999,9 @@ private:
nsIFrame* aFrame,
FrameConstructionItemList& aItems,
bool aIsAppend,
nsIFrame* aPrevSibling,
InsertionKind);
nsIFrame* aPrevSibling);
void ReframeContainingBlock(nsIFrame* aFrame, InsertionKind aInsertionKind);
void ReframeContainingBlock(nsIFrame* aFrame);
//----------------------------------------

Просмотреть файл

@ -260,6 +260,9 @@ user_pref("toolkit.telemetry.bhrPing.enabled", false);
// to suppress the leak. Running locally does not reproduce the issue,
// so disable this until we rewrite the pingsender in Rust (bug 1339035).
user_pref("toolkit.telemetry.shutdownPingSender.enabledFirstSession", false);
// Don't send the 'first-shutdown' during tests, otherwise tests expecting
// main and subsession pings will fail.
user_pref("toolkit.telemetry.firstShutdownPing.enabled", false);
// A couple of preferences with default values to test that telemetry preference
// watching is working.

Просмотреть файл

@ -166,8 +166,8 @@ const SQL_BOOKMARK_TAGS_FRAGMENT =
// TODO bug 412736: in case of a frecency tie, we might break it with h.typed
// and h.visit_count. That is slower though, so not doing it yet...
// NB: as a slight performance optimization, we only evaluate the "btitle"
// and "tags" queries for bookmarked entries.
// NB: as a slight performance optimization, we only evaluate the "bookmarked"
// condition once, and avoid evaluating "btitle" and "tags" when it is false.
function defaultQuery(conditions = "") {
let query =
`SELECT :query_type, h.url, h.title, ${SQL_BOOKMARK_TAGS_FRAGMENT},
@ -177,16 +177,20 @@ function defaultQuery(conditions = "") {
ON t.url = h.url
AND t.userContextId = :userContextId
WHERE h.frecency <> 0
AND AUTOCOMPLETE_MATCH(:searchString, h.url,
CASE WHEN bookmarked THEN
IFNULL(btitle, h.title)
ELSE h.title END,
CASE WHEN bookmarked THEN
tags
ELSE '' END,
AND CASE WHEN bookmarked
THEN
AUTOCOMPLETE_MATCH(:searchString, h.url,
IFNULL(btitle, h.title), tags,
h.visit_count, h.typed,
bookmarked, t.open_count,
1, t.open_count,
:matchBehavior, :searchBehavior)
ELSE
AUTOCOMPLETE_MATCH(:searchString, h.url,
h.title, '',
h.visit_count, h.typed,
0, t.open_count,
:matchBehavior, :searchBehavior)
END
${conditions}
ORDER BY h.frecency DESC, h.id DESC
LIMIT :maxResults`;

Просмотреть файл

@ -1699,7 +1699,24 @@ var Impl = {
};
p.push(TelemetryController.submitExternalPing(getPingType(shutdownPayload), shutdownPayload, options)
.catch(e => this._log.error("saveShutdownPings - failed to submit shutdown ping", e)));
}
// Send a duplicate of first-shutdown pings as a new ping type, in order to properly
// evaluate first session profiles (see bug 1390095).
const sendFirstShutdownPing =
Services.prefs.getBoolPref(Utils.Preferences.ShutdownPingSender, false) &&
Services.prefs.getBoolPref(Utils.Preferences.FirstShutdownPingEnabled, false) &&
TelemetryReportingPolicy.isFirstRun();
if (sendFirstShutdownPing) {
let options = {
addClientId: true,
addEnvironment: true,
usePingSender: true,
};
p.push(TelemetryController.submitExternalPing("first-shutdown", shutdownPayload, options)
.catch(e => this._log.error("saveShutdownPings - failed to submit first shutdown ping", e)));
}
}
// As a temporary measure, we want to submit saved-session too if extended Telemetry is enabled
// to keep existing performance analysis working.

Просмотреть файл

@ -29,6 +29,7 @@ this.TelemetryUtils = {
ArchiveEnabled: "toolkit.telemetry.archive.enabled",
CachedClientId: "toolkit.telemetry.cachedClientID",
FirstRun: "toolkit.telemetry.reportingpolicy.firstRun",
FirstShutdownPingEnabled: "toolkit.telemetry.firstShutdownPing.enabled",
HealthPingEnabled: "toolkit.telemetry.healthping.enabled",
OverrideOfficialCheck: "toolkit.telemetry.send.overrideOfficialCheck",
Server: "toolkit.telemetry.server",

Просмотреть файл

@ -0,0 +1,10 @@
"first-shutdown" ping
==================
This ping is a duplicate of the main-ping sent on first shutdown. Enabling pingsender
for first sessions will impact existing engagment metrics. The ``first-shutdown`` ping enables a
more accurate view of users that churn after the first session. This ping exists as a
stopgap until existing metrics are re-evaluated for use first session ``main-pings``.
See :doc:`main-ping` for details about this payload.

Просмотреть файл

@ -58,6 +58,10 @@ Preferences
Allow the ``shutdown`` ping to be sent using the :doc:`ping sender <pingsender>` from the first browsing session.
``toolkit.telemetry.firstShutdownPing.enabled``
Allow a duplicate of the shutdown ping from the first browsing session to be sent as a separate ``first-shutdown`` ping.
``toolkit.telemetry.newProfilePing.enabled``
Enable the :doc:`../data/new-profile` ping on new profiles.

Просмотреть файл

@ -320,6 +320,7 @@ if (runningInParent) {
Services.prefs.setBoolPref(TelemetryUtils.Preferences.ShutdownPingSender, false);
Services.prefs.setBoolPref(TelemetryUtils.Preferences.ShutdownPingSenderFirstSession, false);
Services.prefs.setBoolPref("toolkit.telemetry.newProfilePing.enabled", false);
Services.prefs.setBoolPref(TelemetryUtils.Preferences.FirstShutdownPingEnabled, false);
// Ensure browser experiments are also disabled, to avoid network activity
// when toggling PREF_ENABLED.
Services.prefs.setBoolPref("experiments.enabled", false);

Просмотреть файл

@ -1483,6 +1483,126 @@ add_task(async function test_sendShutdownPing() {
PingServer.resetPingHandler();
});
add_task(async function test_sendFirstShutdownPing() {
if (gIsAndroid ||
(AppConstants.platform == "linux" && OS.Constants.Sys.bits == 32)) {
// We don't support the pingsender on Android, yet, see bug 1335917.
// We also don't suppor the pingsender testing on Treeherder for
// Linux 32 bit (due to missing libraries). So skip it there too.
// See bug 1310703 comment 78.
return;
}
let storageContainsFirstShutdown = async function() {
let pendingPings = await TelemetryStorage.loadPendingPingList();
let pings = await Promise.all(
pendingPings.map(async (p) => {
return TelemetryStorage.loadPendingPing(p.id)
})
);
return pings.find(p => p.type == "first-shutdown")
}
let checkShutdownNotSent = async function() {
// The failure-mode of the ping-sender is used to check that a ping was
// *not* sent. This can be combined with the state of the storage to infer
// the appropriate behavior from the preference flags.
// Assert failure if we recive a ping.
PingServer.registerPingHandler((req, res) => {
const receivedPing = decodeRequestPayload(req);
Assert.ok(false, `No ping should be received in this test (got ${receivedPing.id}).`);
});
// Assert that pings are sent on first run, forcing a forced application
// quit. This should be equivalent to the first test in this suite.
Preferences.set(TelemetryUtils.Preferences.FirstRun, true);
TelemetryReportingPolicy.testUpdateFirstRun();
await TelemetryController.testReset();
Services.obs.notifyObservers(null, "quit-application-forced");
await TelemetryController.testShutdown();
Assert.ok(await storageContainsFirstShutdown(),
"The 'first-shutdown' ping must be saved to disk.")
await TelemetryStorage.testClearPendingPings();
// Assert that it's not sent during subsequent runs
Preferences.set(TelemetryUtils.Preferences.FirstRun, false);
TelemetryReportingPolicy.testUpdateFirstRun();
await TelemetryController.testReset();
Services.obs.notifyObservers(null, "quit-application-forced");
await TelemetryController.testShutdown();
Assert.ok(!(await storageContainsFirstShutdown()),
"The 'first-shutdown' ping should only be written during first run.")
await TelemetryStorage.testClearPendingPings();
// Assert that the the ping is only sent if the flag is enabled.
Preferences.set(TelemetryUtils.Preferences.FirstRun, true);
Preferences.set(TelemetryUtils.Preferences.FirstShutdownPingEnabled, false);
TelemetryReportingPolicy.testUpdateFirstRun();
await TelemetryController.testReset();
await TelemetryController.testShutdown();
Assert.ok(!(await storageContainsFirstShutdown()),
"The 'first-shutdown' ping should only be written if enabled")
await TelemetryStorage.testClearPendingPings();
// Assert that the the ping is not collected when the ping-sender is disabled.
// The information would be made irrelevant by the main-ping in the second session.
Preferences.set(TelemetryUtils.Preferences.FirstShutdownPingEnabled, true);
Preferences.set(TelemetryUtils.Preferences.ShutdownPingSender, false);
TelemetryReportingPolicy.testUpdateFirstRun();
await TelemetryController.testReset();
await TelemetryController.testShutdown();
Assert.ok(!(await storageContainsFirstShutdown()),
"The 'first-shutdown' ping should only be written if ping-sender is enabled")
// Clear the state and prepare for the next test.
await TelemetryStorage.testClearPendingPings();
PingServer.clearRequests();
PingServer.resetPingHandler();
}
// Remove leftover pending pings from other tests
await TelemetryStorage.testClearPendingPings();
PingServer.clearRequests();
Telemetry.clearScalars();
// Set testing invariants for FirstShutdownPingEnabled
Preferences.set(TelemetryUtils.Preferences.ShutdownPingSender, true);
Preferences.set(TelemetryUtils.Preferences.ShutdownPingSenderFirstSession, false)
// Set primary conditions of the 'first-shutdown' ping
Preferences.set(TelemetryUtils.Preferences.FirstShutdownPingEnabled, true);
Preferences.set(TelemetryUtils.Preferences.FirstRun, true);
TelemetryReportingPolicy.testUpdateFirstRun();
// Assert general 'first-shutdown' use-case.
await TelemetryController.testReset();
await TelemetryController.testShutdown();
let ping = await PingServer.promiseNextPing();
checkPingFormat(ping, "first-shutdown", true, true);
Assert.equal(ping.payload.info.reason, REASON_SHUTDOWN);
Assert.equal(ping.clientId, gClientID);
await TelemetryStorage.testClearPendingPings();
// Assert that the shutdown is not sent under various conditions
await checkShutdownNotSent();
// Reset the pref and restart Telemetry.
Preferences.set(TelemetryUtils.Preferences.ShutdownPingSender, false);
Preferences.set(TelemetryUtils.Preferences.ShutdownPingSenderFirstSession, false);
Preferences.set(TelemetryUtils.Preferences.FirstShutdownPingEnabled, false);
Preferences.reset(TelemetryUtils.Preferences.FirstRun);
PingServer.resetPingHandler();
});
add_task(async function test_savedSessionData() {
// Create the directory which will contain the data file, if it doesn't already
// exist.