Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Noemi Erli 2018-07-14 01:22:25 +03:00
commit e9d21cd259
155 changed files with 2568 additions and 1937 deletions

View File

@ -849,11 +849,6 @@ toolbarspring {
}
}
#editBMPanel_tagsSelector {
/* override default listbox width from xul.css */
width: auto;
}
menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
display: none;
}

View File

@ -5,6 +5,7 @@
# 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/.
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/usercontext/usercontext.css" type="text/css"?>

View File

@ -747,8 +747,6 @@ var gEditItemOverlay = {
if (tagsSelectorRow.collapsed)
return;
// Save the current scroll position and restore it after the rebuild.
let firstIndex = tagsSelector.getIndexOfFirstVisibleRow();
let selectedIndex = tagsSelector.selectedIndex;
let selectedTag = selectedIndex >= 0 ? tagsSelector.selectedItem.label
: null;
@ -759,24 +757,22 @@ var gEditItemOverlay = {
let tagsInField = this._getTagsArrayFromTagsInputField();
let allTags = PlacesUtils.tagging.allTags;
for (let tag of allTags) {
let elt = document.createElement("listitem");
elt.setAttribute("type", "checkbox");
elt.setAttribute("label", tag);
let fragment = document.createDocumentFragment();
for (var i = 0; i < allTags.length; i++) {
let tag = allTags[i];
let elt = document.createElement("richlistitem");
elt.appendChild(document.createElement("image"));
let label = document.createElement("label");
label.setAttribute("value", tag);
elt.appendChild(label);
if (tagsInField.includes(tag))
elt.setAttribute("checked", "true");
tagsSelector.appendChild(elt);
fragment.appendChild(elt);
if (selectedTag === tag)
selectedIndex = tagsSelector.getIndexOfItem(elt);
selectedIndex = i;
}
tagsSelector.appendChild(fragment);
// Restore position.
// The listbox allows to scroll only if the required offset doesn't
// overflow its capacity, thus need to adjust the index for removals.
firstIndex =
Math.min(firstIndex,
tagsSelector.itemCount - tagsSelector.getNumberOfVisibleRows());
tagsSelector.scrollToIndex(firstIndex);
if (selectedIndex >= 0 && tagsSelector.itemCount > 0) {
selectedIndex = Math.min(selectedIndex, tagsSelector.itemCount - 1);
tagsSelector.selectedIndex = selectedIndex;
@ -796,12 +792,17 @@ var gEditItemOverlay = {
this._rebuildTagsSelectorList();
// This is a no-op if we've added the listener.
tagsSelector.addEventListener("CheckboxStateChange", this);
tagsSelector.addEventListener("mousedown", this);
tagsSelector.addEventListener("keypress", this);
} else {
expander.className = "expander-down";
expander.setAttribute("tooltiptext",
expander.getAttribute("tooltiptextdown"));
tagsSelectorRow.collapsed = true;
// This is a no-op if we've removed the listener.
tagsSelector.removeEventListener("mousedown", this);
tagsSelector.removeEventListener("keypress", this);
}
},
@ -845,25 +846,24 @@ var gEditItemOverlay = {
},
// EventListener
handleEvent(aEvent) {
switch (aEvent.type) {
case "CheckboxStateChange":
// Update the tags field when items are checked/unchecked in the listbox
let tags = this._getTagsArrayFromTagsInputField();
let tagCheckbox = aEvent.target;
let curTagIndex = tags.indexOf(tagCheckbox.label);
let tagsSelector = this._element("tagsSelector");
tagsSelector.selectedItem = tagCheckbox;
if (tagCheckbox.checked) {
if (curTagIndex == -1)
tags.push(tagCheckbox.label);
} else if (curTagIndex != -1) {
tags.splice(curTagIndex, 1);
handleEvent(event) {
switch (event.type) {
case "mousedown":
if (event.button == 0) {
// Make sure the event is triggered on an item and not the empty space.
let item = event.target.closest("richlistbox,richlistitem");
if (item.localName == "richlistitem") {
this.toggleItemCheckbox(item);
}
}
break;
case "keypress":
if (event.key == " ") {
let item = event.target.currentItem;
if (item) {
this.toggleItemCheckbox(item);
}
}
this._element("tagsField").value = tags.join(", ");
this._updateTags();
break;
case "unload":
this.uninitPanel(false);
@ -871,6 +871,27 @@ var gEditItemOverlay = {
}
},
toggleItemCheckbox(item) {
// Update the tags field when items are checked/unchecked in the listbox
let tags = this._getTagsArrayFromTagsInputField();
let curTagIndex = tags.indexOf(item.label);
let tagsSelector = this._element("tagsSelector");
tagsSelector.selectedItem = item;
if (!item.hasAttribute("checked")) {
item.setAttribute("checked", "true");
if (curTagIndex == -1)
tags.push(item.label);
} else {
item.removeAttribute("checked");
if (curTagIndex != -1)
tags.splice(curTagIndex, 1);
}
this._element("tagsField").value = tags.join(", ");
this._updateTags();
},
_initTagsField() {
let tags;
if (this._paneInfo.isURI)

View File

@ -107,9 +107,10 @@
</vbox>
<vbox id="editBMPanel_tagsSelectorRow"
collapsed="true">
<listbox id="editBMPanel_tagsSelector"
height="150"/>
collapsed="true">
<richlistbox id="editBMPanel_tagsSelector"
styled="true"
height="150"/>
</vbox>
<vbox id="editBMPanel_keywordRow"

View File

@ -5,6 +5,15 @@
const TEST_URL = "about:buildconfig";
function scrolledIntoView(item, parentItem) {
let itemRect = item.getBoundingClientRect();
let parentItemRect = parentItem.getBoundingClientRect();
let pointInView = y => parentItemRect.top < y && y < parentItemRect.bottom;
// Partially visible items are also considered visible.
return pointInView(itemRect.top) || pointInView(itemRect.bottom);
}
add_task(async function() {
await PlacesUtils.bookmarks.eraseEverything();
let tags = ["a", "b", "c", "d", "e", "f", "g",
@ -63,32 +72,30 @@ add_task(async function() {
isnot(listItem, null, "Valid listItem found");
tagsSelector.ensureElementIsVisible(listItem);
let visibleIndex = tagsSelector.getIndexOfFirstVisibleRow();
let scrollTop = tagsSelector.scrollTop;
ok(listItem.checked, "Item is checked " + i);
ok(listItem.hasAttribute("checked"), "Item is checked " + i);
let selectedTag = listItem.label;
// Uncheck the tag.
let promiseNotification = PlacesTestUtils.waitForNotification(
"onItemChanged", (id, property) => property == "tags");
listItem.checked = false;
EventUtils.synthesizeMouseAtCenter(listItem.firstChild, {});
await promiseNotification;
is(visibleIndex, tagsSelector.getIndexOfFirstVisibleRow(),
"Scroll position did not change");
is(scrollTop, tagsSelector.scrollTop, "Scroll position did not change");
// The listbox is rebuilt, so we have to get the new element.
let newItem = tagsSelector.selectedItem;
isnot(newItem, null, "Valid new listItem found");
ok(!newItem.checked, "New listItem is unchecked " + i);
ok(!newItem.hasAttribute("checked"), "New listItem is unchecked " + i);
is(newItem.label, selectedTag, "Correct tag is still selected");
// Check the tag.
promiseNotification = PlacesTestUtils.waitForNotification(
"onItemChanged", (id, property) => property == "tags");
newItem.checked = true;
EventUtils.synthesizeMouseAtCenter(newItem.firstChild, {});
await promiseNotification;
is(visibleIndex, tagsSelector.getIndexOfFirstVisibleRow(),
"Scroll position did not change");
is(scrollTop, tagsSelector.scrollTop, "Scroll position did not change");
}
// Remove the second bookmark, then nuke some of the tags.
@ -101,28 +108,24 @@ add_task(async function() {
isnot(listItem, null, "Valid listItem found");
tagsSelector.ensureElementIsVisible(listItem);
let firstVisibleTag = tags[tagsSelector.getIndexOfFirstVisibleRow()];
let items = [...tagsSelector.children];
let topTag = items.find(e => scrolledIntoView(e, tagsSelector)).label;
ok(listItem.checked, "Item is checked " + i);
ok(listItem.hasAttribute("checked"), "Item is checked " + i);
// Uncheck the tag.
let promiseNotification = PlacesTestUtils.waitForNotification(
"onItemChanged", (id, property) => property == "tags");
listItem.checked = false;
EventUtils.synthesizeMouseAtCenter(listItem.firstChild, {});
await promiseNotification;
// Ensure the first visible tag is still visible in the list.
let firstVisibleIndex = tagsSelector.getIndexOfFirstVisibleRow();
let lastVisibleIndex = firstVisibleIndex + tagsSelector.getNumberOfVisibleRows() - 1;
let expectedTagIndex = tags.indexOf(firstVisibleTag);
ok(expectedTagIndex >= firstVisibleIndex &&
expectedTagIndex <= lastVisibleIndex,
"Scroll position is correct");
// The listbox is rebuilt, so we have to get the new element.
let topItem = [...tagsSelector.children].find(e => e.label == topTag);
ok(scrolledIntoView(topItem, tagsSelector), "Scroll position is correct");
let newItem = tagsSelector.selectedItem;
isnot(newItem, null, "Valid new listItem found");
ok(newItem.checked, "New listItem is checked " + i);
ok(newItem.hasAttribute("checked"), "New listItem is checked " + i);
is(tagsSelector.selectedItem.label,
tags[Math.min(i + 1, tags.length - 2)],
"The next tag is now selected");

View File

@ -9,7 +9,7 @@ function checkTagsSelector(aAvailableTags, aCheckedTags) {
"Found expected number of tags in the tags selector");
Array.prototype.forEach.call(children, function(aChild) {
let tag = aChild.getAttribute("label");
let tag = aChild.querySelector("label").getAttribute("value");
ok(true, "Found tag '" + tag + "' in the selector");
ok(aAvailableTags.includes(tag), "Found expected tag");
let checked = aChild.getAttribute("checked") == "true";

View File

@ -23,14 +23,6 @@ add_task(async function() {
ok(checkbox.checked, "Checkbox is checked");
await checkPageScrolling(container, "checkbox");
// Test listbox
let listbox = doc.getElementById("listbox");
let listitem = doc.getElementById("listitem");
listbox.focus();
EventUtils.sendString(" ");
ok(listitem.selected, "Listitem is selected");
await checkPageScrolling(container, "listbox");
// Test radio
let radiogroup = doc.getElementById("radiogroup");
radiogroup.focus();

View File

@ -15,13 +15,6 @@
<checkbox id="checkbox" label="checkbox" />
</hbox>
<hbox style="height: 50px;">
<listbox id="listbox">
<listitem id="listitem" label="listitem" />
<listitem label="listitem" />
</listbox>
</hbox>
<hbox>
<radiogroup id="radiogroup">
<radio id="radio" label="radio" />

View File

@ -22,18 +22,13 @@ var gLanguagesDialog = {
_selectedItemID: null,
init() {
if (!this._availableLanguagesList.length)
this._loadAvailableLanguages();
},
onLoad() {
Preferences.get("intl.accept_languages").on("change",
() => this._readAcceptLanguages().catch(Cu.reportError));
// Ugly hack used to trigger extra reflow in order to work around XUL bug 1194844;
// see bug 1194346.
forceReflow() {
this._activeLanguages.style.fontKerning = "none";
setTimeout(() => {
this._activeLanguages.style.removeProperty("font-kerning");
}, 0);
if (!this._availableLanguagesList.length) {
document.mozSubdialogReady = this._loadAvailableLanguages();
}
},
get _activeLanguages() {
@ -44,7 +39,7 @@ var gLanguagesDialog = {
return document.getElementById("availableLanguages");
},
_loadAvailableLanguages() {
async _loadAvailableLanguages() {
// This is a parser for: resource://gre/res/language.properties
// The file is formatted like so:
// ab[-cd].accept=true|false
@ -85,7 +80,8 @@ var gLanguagesDialog = {
this._availableLanguagesList.push(li);
}
this._buildAvailableLanguageList();
await this._buildAvailableLanguageList();
await this._readAcceptLanguages();
},
async _buildAvailableLanguageList() {
@ -132,23 +128,25 @@ var gLanguagesDialog = {
this._availableLanguages.setAttribute("label", this._availableLanguages.getAttribute("placeholder"));
},
async readAcceptLanguages() {
async _readAcceptLanguages() {
while (this._activeLanguages.hasChildNodes())
this._activeLanguages.firstChild.remove();
var selectedIndex = 0;
var preference = Preferences.get("intl.accept_languages");
if (preference.value == "")
return undefined;
return;
var languages = preference.value.toLowerCase().split(/\s*,\s*/);
for (var i = 0; i < languages.length; ++i) {
var listitem = document.createElement("listitem");
var listitem = document.createElement("richlistitem");
var label = document.createElement("label");
listitem.appendChild(label);
listitem.id = languages[i];
if (languages[i] == this._selectedItemID)
selectedIndex = i;
this._activeLanguages.appendChild(listitem);
var localeName = this._getLocaleName(languages[i]);
document.l10n.setAttributes(listitem, "languages-code-format", {
document.l10n.setAttributes(label, "languages-active-code-format", {
locale: localeName,
code: languages[i],
});
@ -171,12 +169,6 @@ var gLanguagesDialog = {
// Update states of accept-language list and buttons according to
// privacy.resistFingerprinting and privacy.spoof_english.
this.readSpoofEnglish();
return undefined;
},
writeAcceptLanguages() {
return undefined;
},
onAvailableLanguageSelect() {
@ -210,7 +202,7 @@ var gLanguagesDialog = {
this._availableLanguages.selectedItem = null;
// Rebuild the available list with the added item removed...
this._buildAvailableLanguageList();
this._buildAvailableLanguageList().catch(Cu.reportError);
},
removeLanguage() {
@ -237,7 +229,7 @@ var gLanguagesDialog = {
var preference = Preferences.get("intl.accept_languages");
preference.value = string;
this._buildAvailableLanguageList();
this._buildAvailableLanguageList().catch(Cu.reportError);
},
_getLocaleName(localeCode) {
@ -350,8 +342,3 @@ var gLanguagesDialog = {
return document.getElementById("spoofEnglish").checked ? 2 : 1;
}
};
// These focus and resize handlers hack around XUL bug 1194844
// by triggering extra reflow (see bug 1194346).
window.addEventListener("focus", () => gLanguagesDialog.forceReflow());
window.addEventListener("resize", () => gLanguagesDialog.forceReflow());

View File

@ -15,7 +15,7 @@
buttons="accept,cancel,help"
persist="lastSelected screenX screenY"
role="dialog"
onload="gLanguagesDialog.init();"
onload="gLanguagesDialog.onLoad();"
helpTopic="prefs-languages"
ondialoghelp="openPrefsHelp()">
@ -49,11 +49,9 @@
</columns>
<rows>
<row flex="1">
<listbox id="activeLanguages" flex="1" rows="6"
seltype="multiple" onselect="gLanguagesDialog.onLanguageSelect();"
preference="intl.accept_languages"
onsyncfrompreference="return gLanguagesDialog.readAcceptLanguages();"
onsynctopreference="return gLanguagesDialog.writeAcceptLanguages();"/>
<richlistbox id="activeLanguages" flex="1" height="200"
seltype="multiple"
onselect="gLanguagesDialog.onLanguageSelect();"/>
<vbox>
<button id="up" class="up" oncommand="gLanguagesDialog.moveUp();" disabled="true"
data-l10n-id="languages-customize-moveup"

View File

@ -45,3 +45,6 @@ languages-customize-add =
# $code (String) - Locale code of the locale (for example: "is", "es-CL")
languages-code-format =
.label = { $locale } [{ $code }]
languages-active-code-format =
.value = { languages-code-format.label }

View File

@ -58,6 +58,14 @@
visibility: collapse;
}
#editBMPanel_tagsSelector > richlistitem > image {
-moz-appearance: checkbox;
-moz-box-align: center;
margin: 0 2px;
min-width: 13px;
min-height: 13px;
}
/* Bookmark panel dropdown menu items */
#editBMPanel_folderMenuList[selectedIndex="0"],

View File

@ -60,6 +60,20 @@
visibility: collapse;
}
#editBMPanel_tagsSelector > richlistitem > image {
-moz-appearance: checkbox;
-moz-box-align: center;
margin: 0px 2px;
border: 1px solid -moz-DialogText;
min-width: 13px;
min-height: 13px;
background: -moz-Field no-repeat 50% 50%;
}
#editBMPanel_tagsSelector > richlistitem[checked="true"] > image {
background-image: url("chrome://global/skin/checkbox/cbox-check.gif");
}
/* ----- BOOKMARK PANEL DROPDOWN MENU ITEMS ----- */

View File

@ -209,6 +209,10 @@ button > hbox > label {
font-size: 90%;
}
#activeLanguages > richlistitem {
padding: 0.3em;
}
#downloadFolder {
margin-inline-start: 0;
padding-inline-start: 30px;

View File

@ -63,6 +63,16 @@
visibility: collapse;
}
#editBMPanel_tagsSelector > richlistitem > image {
-moz-appearance: checkbox;
-moz-box-align: center;
margin: 0px 2px;
border: 1px solid -moz-DialogText;
min-width: 13px;
min-height: 13px;
background: -moz-Field no-repeat 50% 50%;
}
/* ::::: bookmark panel dropdown icons ::::: */

View File

@ -379,7 +379,7 @@ ElementEditor.prototype = {
const val = this.doc.createElement("span");
val.classList.add("attr-value");
val.classList.add("theme-fg-color6");
val.classList.add("theme-fg-color4");
inner.appendChild(val);
inner.appendChild(this.doc.createTextNode('"'));

View File

@ -110,7 +110,7 @@ DomNodePreview.prototype = {
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color6"
"class": "theme-fg-color4"
},
textContent: "#"
});
@ -120,7 +120,7 @@ DomNodePreview.prototype = {
parent: this.idEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
"class": "attribute-value theme-fg-color4"
}
});
@ -149,7 +149,7 @@ DomNodePreview.prototype = {
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "theme-fg-color6"
"class": "theme-fg-color4"
},
textContent: "."
});
@ -159,7 +159,7 @@ DomNodePreview.prototype = {
parent: this.classEl,
nodeType: "span",
attributes: {
"class": "attribute-value theme-fg-color6"
"class": "attribute-value theme-fg-color4"
}
});

View File

@ -131,8 +131,7 @@ body {
background-color: var(--theme-highlight-bluegrey);
}
.theme-fg-color4,
.theme-fg-color6 {
.theme-fg-color4 {
color: var(--theme-highlight-purple);
}
@ -148,7 +147,6 @@ body {
background-color: #b26b47;
}
.theme-fg-color7,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error,

View File

@ -123,11 +123,7 @@ body {
background-color: var(--theme-highlight-bluegrey);
}
.theme-fg-color4 {
color: var(--theme-highlight-orange);
}
.theme-fg-color6,
.theme-fg-color4,
.cm-s-mozilla .cm-string,
.cm-s-mozilla .cm-string-2,
.variable-or-property .token-string,
@ -140,7 +136,6 @@ body {
background-color: hsl(24,85%,39%);
}
.theme-fg-color7,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error,

View File

@ -385,8 +385,6 @@ ul.children + .tag-line::before {
.theme-selected ~ .editor .theme-fg-color3,
.theme-selected ~ .editor .theme-fg-color4,
.theme-selected ~ .editor .theme-fg-color5,
.theme-selected ~ .editor .theme-fg-color6,
.theme-selected ~ .editor .theme-fg-color7,
.theme-selected ~ .editor .close::before {
color: var(--theme-selection-color);
}

View File

@ -29,6 +29,7 @@
#include "gfxPrefs.h"
#include "ImageOps.h"
#include "mozAutoDocUpdate.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
@ -8870,21 +8871,10 @@ nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
}
if (aWindow) {
nsCOMPtr<nsIHttpChannel> httpChannel;
nsIDocument* document = aWindow->GetExtantDoc();
if (document) {
httpChannel = do_QueryInterface(document->GetChannel());
}
// If this is not a tracking resource, nothing is disabled.
if (!httpChannel || !httpChannel->GetIsTrackingResource()) {
return false;
}
// Maybe we want to grant this origin.
nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
if (documentURI &&
nsGlobalWindowInner::Cast(aWindow)->IsFirstPartyStorageAccessGrantedFor(documentURI)) {
AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
documentURI)) {
return false;
}
@ -8910,13 +8900,8 @@ nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
return false;
}
nsCOMPtr<nsILoadInfo> loadInfo;
rv = aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return !loadInfo->IsFirstPartyStorageAccessGrantedFor(uri);
return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
uri);
}
// static, private

View File

@ -12,6 +12,7 @@
#include "nsDocument.h"
#include "nsIDocumentInlines.h"
#include "mozilla/AnimationComparator.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BinarySearch.h"
@ -12454,7 +12455,8 @@ nsIDocument::MaybeAllowStorageForOpener()
return;
}
nsGlobalWindowInner::Cast(openerInner)->AddFirstPartyStorageAccessGrantedFor(origin);
AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(origin,
openerInner);
}
bool

View File

@ -36,7 +36,6 @@
#if defined(MOZ_WIDGET_ANDROID)
#include "mozilla/dom/WindowOrientationObserver.h"
#endif
#include "mozilla/StaticPrefs.h"
#include "nsDOMOfflineResourceList.h"
#include "nsError.h"
#include "nsIIdleService.h"
@ -334,10 +333,6 @@ using mozilla::dom::cache::CacheStorage;
// Min idle notification time in seconds.
#define MIN_IDLE_NOTIFICATION_TIME_S 1
// Anti-tracking permission expiration
#define ANTITRACKING_EXPIRATION 2592000000 // 30 days.
#define ANTITRACKING_PERM_KEY "3rdPartyStorage"
static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
static bool gIdleObserversAPIFuzzTimeDisabled = false;
@ -922,8 +917,7 @@ nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter *aOuterWindow)
mObservingDidRefresh(false),
mIteratingDocumentFlushedResolvers(false),
mCanSkipCCGeneration(0),
mBeforeUnloadListenerCount(0),
mStorageGrantedOriginPopulated(false)
mBeforeUnloadListenerCount(0)
{
mIsInnerWindow = true;
@ -1241,7 +1235,6 @@ nsGlobalWindowInner::FreeInnerObjects()
}
UnlinkHostObjectURIs();
ReleaseFirstPartyStorageAccessGrantedOrigins();
NotifyWindowIDDestroyed("inner-window-destroyed");
@ -1565,7 +1558,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
tmp->UnlinkHostObjectURIs();
tmp->ReleaseFirstPartyStorageAccessGrantedOrigins();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
@ -8062,289 +8054,6 @@ nsGlobalWindowInner::GetRegionalPrefsLocales(nsTArray<nsString>& aLocales)
}
}
void
nsGlobalWindowInner::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
bool aOverwritten)
{
MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
if (aOverwritten) {
SaveFirstPartyStorageAccessGrantedFor(aOrigin);
}
for (StorageGrantedOrigin& data : mStorageGrantedOrigins) {
if (data.mOrigin == aOrigin) {
data.mOverwritten = aOverwritten;
return;
}
}
bool wasAllowed =
nsContentUtils::StorageDisabledByAntiTracking(this, nullptr, nullptr);
StorageGrantedOrigin* data = mStorageGrantedOrigins.AppendElement();
data->mOrigin = aOrigin;
data->mOverwritten = aOverwritten;
if (!wasAllowed &&
nsContentUtils::StorageDisabledByAntiTracking(this, nullptr, nullptr)) {
PropagateFirstPartyStorageAccessGrantedToWorkers(this);
}
// Let's store the origin in the loadInfo as well.
if (mDoc) {
nsCOMPtr<nsIChannel> channel = mDoc->GetChannel();
if (channel) {
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
if (loadInfo) {
loadInfo->AddFirstPartyStorageAccessGrantedFor(aOrigin);
}
}
}
}
void
nsGlobalWindowInner::GetFirstPartyStorageAccessGrantedOrigins(nsTArray<nsString>& aOrigin)
{
aOrigin.Clear();
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
return;
}
MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
for (const StorageGrantedOrigin& data : mStorageGrantedOrigins) {
aOrigin.AppendElement(data.mOrigin);
}
}
bool
nsGlobalWindowInner::IsFirstPartyStorageAccessGrantedFor(nsIURI* aURI)
{
MOZ_ASSERT(aURI);
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
return true;
}
MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
if (mStorageGrantedOrigins.IsEmpty()) {
return false;
}
nsAutoString origin;
nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
for (const StorageGrantedOrigin& data : mStorageGrantedOrigins) {
if (data.mOrigin.Equals(origin)) {
return true;
}
}
return false;
}
void
nsGlobalWindowInner::ReleaseFirstPartyStorageAccessGrantedOrigins()
{
mStorageGrantedOriginPopulated = false;
mStorageGrantedOrigins.Clear();
}
namespace mozilla {
namespace dom {
extern void
SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
const nsACString& aParentOrigin,
const nsACString& aGrantedOrigin);
} // namespace dom
} // namespace mozilla
void
nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin)
{
MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
// Now we need the principal and the origin of the parent window.
nsIPrincipal* parentPrincipal = GetTopLevelStorageAreaPrincipal();
if (NS_WARN_IF(!parentPrincipal)) {
return;
}
nsAutoCString parentOrigin;
nsresult rv = parentPrincipal->GetOriginNoSuffix(parentOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
// Let's take the principal and the origin of the current window.
nsIPrincipal* principal = GetPrincipal();
if (NS_WARN_IF(!principal)) {
return;
}
NS_ConvertUTF16toUTF8 grantedOrigin(aOrigin);
if (XRE_IsParentProcess()) {
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(principal,
parentOrigin,
grantedOrigin);
return;
}
// We have this external function because ContentChild includes windows.h and
// for this reason it cannot be included here.
SendFirstPartyStorageAccessGrantedForOriginToParentProcess(principal,
parentOrigin,
grantedOrigin);
}
/* static */ void
nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
const nsCString& aParentOrigin,
const nsCString& aGrantedOrigin)
{
MOZ_ASSERT(XRE_IsParentProcess());
if (NS_WARN_IF(!aPrincipal)) {
// The child process is sending something wrong. Let's ignore it.
return;
}
nsAutoCString origin;
nsresult rv = aPrincipal->GetOriginNoSuffix(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
if (NS_WARN_IF(!pm)) {
return;
}
int64_t when = (PR_Now() / PR_USEC_PER_MSEC) + ANTITRACKING_EXPIRATION;
// We store a permission for the 3rd party principal, to know that we grant
// the storage permission when loaded by the current parent origin.
nsAutoCString type;
if (origin == aGrantedOrigin) {
type = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s", aParentOrigin.get());
} else {
type = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s", aParentOrigin.get(),
aGrantedOrigin.get());
}
rv = pm->AddFromPrincipal(aPrincipal, type.get(),
nsIPermissionManager::ALLOW_ACTION,
nsIPermissionManager::EXPIRE_TIME, when);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void
nsGlobalWindowInner::MaybeRestoreFirstPartyStorageAccessGrantedOrigins()
{
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
return;
}
if (mStorageGrantedOriginPopulated) {
return;
}
mStorageGrantedOriginPopulated = true;
// Now we need the principal and the origin of the parent window.
nsIPrincipal* parentPrincipal = GetTopLevelStorageAreaPrincipal();
if (!parentPrincipal) {
// No parent window.
return;
}
nsAutoCString parentOrigin;
nsresult rv = parentPrincipal->GetOriginNoSuffix(parentOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
// Let's take the principal and the origin of the current window.
nsIPrincipal* principal = GetPrincipal();
if (NS_WARN_IF(!principal)) {
return;
}
nsAutoCString origin;
rv = principal->GetOriginNoSuffix(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsCOMPtr<nsIPermissionManager> pm = services::GetPermissionManager();
if (NS_WARN_IF(!pm)) {
return;
}
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = pm->GetAllForPrincipal(principal, getter_AddRefs(enumerator));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
bool more = false;
nsCOMPtr<nsISupports> iter;
nsCOMPtr<nsIPermission> perm;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
rv = enumerator->GetNext(getter_AddRefs(iter));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
perm = do_QueryInterface(iter);
if (NS_WARN_IF(!perm)) {
return;
}
nsAutoCString type;
rv = perm->GetType(type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (!StringBeginsWith(type, NS_LITERAL_CSTRING(ANTITRACKING_PERM_KEY "^"))) {
continue;
}
nsCCharSeparatedTokenizer token(type, '^');
MOZ_ASSERT(token.hasMoreTokens());
auto value = token.nextToken();
MOZ_ASSERT(value.EqualsLiteral(ANTITRACKING_PERM_KEY));
nsAutoCString originA;
if (token.hasMoreTokens()) {
originA = token.nextToken();
}
// This permission was granted for another top-level window.
if (originA != parentOrigin) {
continue;
}
nsAutoCString originB;
if (token.hasMoreTokens()) {
originB = token.nextToken();
}
AddFirstPartyStorageAccessGrantedFor(NS_ConvertUTF8toUTF16(originB.IsEmpty() ? origin : originB),
false /* no overwrite */);
}
}
IntlUtils*
nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError)
{

View File

@ -717,20 +717,6 @@ public:
mozilla::dom::IntlUtils*
GetIntlUtils(mozilla::ErrorResult& aRv);
void
AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin, bool aOverwritten = true);
void
GetFirstPartyStorageAccessGrantedOrigins(nsTArray<nsString>& aOrigins);
bool
IsFirstPartyStorageAccessGrantedFor(nsIURI* aURI);
static void
SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(nsIPrincipal* aPrincipal,
const nsCString& aParentOrigin,
const nsCString& aGrantedOrigin);
public:
void Alert(nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
@ -1073,15 +1059,6 @@ protected:
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
void
ReleaseFirstPartyStorageAccessGrantedOrigins();
void
SaveFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin);
void
MaybeRestoreFirstPartyStorageAccessGrantedOrigins();
// Array of idle observers that are notified of idle events.
nsTObserverArray<IdleObserverHolder> mIdleObservers;
@ -1129,9 +1106,6 @@ protected:
// Get the parent, returns null if this is a toplevel window
nsPIDOMWindowOuter* GetParentInternal();
// Get the parent principal, returns null if this is a toplevel window.
nsIPrincipal* GetTopLevelStorageAreaPrincipal();
public:
// popup tracking
bool IsPopupSpamWindow();
@ -1249,6 +1223,9 @@ public:
public:
virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() override;
// Get the parent principal, returns null if this is a toplevel window.
nsIPrincipal* GetTopLevelStorageAreaPrincipal();
protected:
static void NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow);
void NotifyWindowIDDestroyed(const char* aTopic);
@ -1502,13 +1479,6 @@ protected:
nsTArray<mozilla::UniquePtr<PromiseDocumentFlushedResolver>> mDocumentFlushedResolvers;
struct StorageGrantedOrigin {
nsString mOrigin;
bool mOverwritten;
};
nsTArray<StorageGrantedOrigin> mStorageGrantedOrigins;
bool mStorageGrantedOriginPopulated;
static InnerWindowByIdTable* sInnerWindowsById;
// Members in the mChromeFields member should only be used in chrome windows.

View File

@ -17,6 +17,7 @@
#include "nsHistory.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorageManager.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/Storage.h"
@ -7078,7 +7079,7 @@ nsGlobalWindowOuter::MaybeAllowStorageForOpenedWindow(nsIURI* aURI)
return;
}
inner->AddFirstPartyStorageAccessGrantedFor(origin, true);
AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(origin, inner);
}
//*****************************************************************************

View File

@ -3306,25 +3306,6 @@ NextWindowID()
return (processBits << kWindowIDWindowBits) | windowBits;
}
// This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp
// can't include ContentChild.h since it includes windows.h.
void
SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
const nsACString& aParentOrigin,
const nsACString& aGrantedOrigin)
{
MOZ_ASSERT(!XRE_IsParentProcess());
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
// This is not really secure, because here we have the content process sending
// the request of storing a permission.
Unused << cc->SendFirstPartyStorageAccessGrantedForOrigin(IPC::Principal(aPrincipal),
nsCString(aParentOrigin),
nsCString(aGrantedOrigin));
}
mozilla::ipc::IPCResult
ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
const uint32_t& aAction)

View File

@ -863,11 +863,6 @@ private:
uint64_t
NextWindowID();
void
SendFirstPartyStorageAccessGrantedForOriginToParentProcess(nsIPrincipal* aPrincipal,
const nsACString& aParentOrigin,
const nsACString& aGrantedOrigin);
} // namespace dom
} // namespace mozilla

View File

@ -29,6 +29,7 @@
#include "mozilla/a11y/AccessibleWrap.h"
#include "mozilla/a11y/Compatibility.h"
#endif
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StyleSheetInlines.h"
@ -117,7 +118,6 @@
#include "nsDebugImpl.h"
#include "nsFrameLoader.h"
#include "nsFrameMessageManager.h"
#include "nsGlobalWindowInner.h"
#include "nsHashPropertyBag.h"
#include "nsIAlertsService.h"
#include "nsIClipboard.h"
@ -5760,12 +5760,12 @@ ContentParent::RecvBHRThreadHang(const HangDetails& aDetails)
}
mozilla::ipc::IPCResult
ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aPrincipal,
const nsCString& aParentOrigin,
ContentParent::RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aParentPrincipal,
const nsCString& aTrackingOrigin,
const nsCString& aGrantedOrigin)
{
nsGlobalWindowInner::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(aPrincipal,
aParentOrigin,
aGrantedOrigin);
AntiTrackingCommon::SaveFirstPartyStorageAccessGrantedForOriginOnParentProcess(aParentPrincipal,
aTrackingOrigin,
aGrantedOrigin);
return IPC_OK();
}

View File

@ -1225,8 +1225,8 @@ public:
const HangDetails& aHangDetails) override;
virtual mozilla::ipc::IPCResult
RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aPrincipal,
const nsCString& aParentOrigin,
RecvFirstPartyStorageAccessGrantedForOrigin(const Principal& aParentPrincipal,
const nsCString& aTrackingOrigin,
const nsCString& aGrantedOrigin) override;
// Notify the ContentChild to enable the input event prioritization when

View File

@ -118,19 +118,7 @@ MemMapSnapshot::Freeze(AutoMemMap& aMem)
MOZ_TRY(NS_NewNativeLocalFile(mPath, /* followLinks = */ false,
getter_AddRefs(file)));
auto result = aMem.init(file);
#ifdef XP_LINUX
// On Linux automation runs, every few hundred thousand calls, our attempt to
// stat the file that we just successfully opened fails with EBADF (bug
// 1472889). Presumably this is a race with a background thread that double
// closes a file, but is difficult to diagnose, so work around it by making a
// second mapping attempt if the first one fails.
if (!result.isOk()) {
aMem.reset();
result = aMem.init(file);
}
#endif
return result;
return aMem.init(file);
}
#else

View File

@ -1160,11 +1160,11 @@ parent:
async AddPerformanceMetrics(nsID aID, PerformanceInfo[] aMetrics);
/*
* A 3rd party context (aPrincipal) has received the permission granted to
* have access to aGrantedOrigin when loaded by aParentOrigin.
* A 3rd party tracking origin (aTrackingOrigin) has received the permission
* granted to have access to aGrantedOrigin when loaded by aParentPrincipal.
*/
async FirstPartyStorageAccessGrantedForOrigin(Principal aPrincipal,
nsCString aParentOrigin,
async FirstPartyStorageAccessGrantedForOrigin(Principal aParentPrincipal,
nsCString aTrackingOrigin,
nsCString aGrantedOrigin);
both:

View File

@ -1081,10 +1081,6 @@ TabChild::DestroyWindow()
mRemoteFrame = nullptr;
}
if (mApzcTreeManager) {
mApzcTreeManager->Destroy();
mApzcTreeManager = nullptr;
}
if (mLayersId.IsValid()) {
StaticMutexAutoLock lock(sTabChildrenMutex);

View File

@ -23,6 +23,7 @@
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/MessagePortTimelineMarker.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/TimelineConsumers.h"
#include "mozilla/TimelineMarker.h"
#include "mozilla/Unused.h"
@ -253,7 +254,7 @@ MessagePort::UnshippedEntangle(MessagePort* aEntangledPort)
void
MessagePort::Initialize(const nsID& aUUID,
const nsID& aDestinationUUID,
uint32_t aSequenceID, bool mNeutered,
uint32_t aSequenceID, bool aNeutered,
ErrorResult& aRv)
{
MOZ_ASSERT(mIdentifier);
@ -261,7 +262,7 @@ MessagePort::Initialize(const nsID& aUUID,
mIdentifier->destinationUuid() = aDestinationUUID;
mIdentifier->sequenceId() = aSequenceID;
if (mNeutered) {
if (aNeutered) {
// If this port is neutered we don't want to keep it alive artificially nor
// we want to add listeners or WorkerRefs.
mState = eStateDisentangled;
@ -508,11 +509,10 @@ MessagePort::CloseInternal(bool aSoftly)
}
if (mState == eStateUnshippedEntangled) {
MOZ_ASSERT(mUnshippedEntangledPort);
MOZ_DIAGNOSTIC_ASSERT(mUnshippedEntangledPort);
// This avoids loops.
RefPtr<MessagePort> port = std::move(mUnshippedEntangledPort);
MOZ_ASSERT(mUnshippedEntangledPort == nullptr);
mState = eStateDisentangledForClose;
port->CloseInternal(aSoftly);
@ -743,14 +743,14 @@ MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
MOZ_ASSERT(mUnshippedEntangledPort);
MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty());
RefPtr<MessagePort> port = std::move(mUnshippedEntangledPort);
// Disconnect the entangled port and connect it to PBackground.
if (!mUnshippedEntangledPort->ConnectToPBackground()) {
if (!port->ConnectToPBackground()) {
// We are probably shutting down. We cannot proceed.
return;
}
mUnshippedEntangledPort = nullptr;
// In this case, we don't need to be connected to the PBackground service.
if (mMessages.IsEmpty()) {
aIdentifier.sequenceId() = mIdentifier->sequenceId();
@ -800,7 +800,11 @@ MessagePort::Closed()
bool
MessagePort::ConnectToPBackground()
{
mState = eStateEntangling;
RefPtr<MessagePort> self = this;
auto raii = MakeScopeExit([self] {
self->mState = eStateDisentangled;
self->UpdateMustKeepAlive();
});
mozilla::ipc::PBackgroundChild* actorChild =
mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
@ -820,6 +824,9 @@ MessagePort::ConnectToPBackground()
MOZ_ASSERT(mActor);
mActor->SetPort(this);
mState = eStateEntangling;
raii.release();
return true;
}
@ -847,10 +854,7 @@ MessagePort::UpdateMustKeepAlive()
void
MessagePort::DisconnectFromOwner()
{
if (mIsKeptAlive) {
CloseForced();
}
CloseForced();
DOMEventTargetHelper::DisconnectFromOwner();
}

View File

@ -140,7 +140,7 @@ private:
void DisconnectFromOwner() override;
void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
uint32_t aSequenceID, bool mNeutered, ErrorResult& aRv);
uint32_t aSequenceID, bool aNeutered, ErrorResult& aRv);
bool ConnectToPBackground();

View File

@ -230,8 +230,7 @@ public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
};
class KeepAliveHandler final : public WorkerHolder
, public ExtendableEvent::ExtensionsHandler
class KeepAliveHandler final : public ExtendableEvent::ExtensionsHandler
, public PromiseNativeHandler
{
// This class manages lifetime extensions added by calling WaitUntil()
@ -240,9 +239,8 @@ class KeepAliveHandler final : public WorkerHolder
// which releases the token and prevents further extensions. By doing this,
// we give other pending microtasks a chance to continue adding extensions.
RefPtr<StrongWorkerRef> mWorkerRef;
nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
WorkerPrivate* MOZ_NON_OWNING_REF mWorkerPrivate;
bool mWorkerHolderAdded;
// We start holding a self reference when the first extension promise is
// added. As far as I can tell, the only case where this is useful is when
@ -266,26 +264,32 @@ public:
explicit KeepAliveHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
ExtendableEventCallback* aCallback)
: WorkerHolder("KeepAliveHolder")
, mKeepAliveToken(aKeepAliveToken)
, mWorkerPrivate(GetCurrentThreadWorkerPrivate())
, mWorkerHolderAdded(false)
: mKeepAliveToken(aKeepAliveToken)
, mCallback(aCallback)
, mPendingPromisesCount(0)
, mRejected(false)
{
MOZ_ASSERT(mKeepAliveToken);
MOZ_ASSERT(mWorkerPrivate);
}
bool
UseWorkerHolder()
Init()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!mWorkerHolderAdded);
mWorkerHolderAdded = HoldWorker(mWorkerPrivate, Canceling);
return mWorkerHolderAdded;
MOZ_ASSERT(IsCurrentThreadRunningWorker());
RefPtr<KeepAliveHandler> self = this;
mWorkerRef =
StrongWorkerRef::Create(GetCurrentThreadWorkerPrivate(),
"KeepAliveHandler",
[self]() {
self->MaybeCleanup();
});
if (NS_WARN_IF(!mWorkerRef)) {
return false;
}
return true;
}
bool
@ -318,24 +322,10 @@ public:
RemovePromise(Rejected);
}
bool
Notify(WorkerStatus aStatus) override
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
if (aStatus < Canceling) {
return true;
}
MaybeCleanup();
return true;
}
void
MaybeDone()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
if (mPendingPromisesCount || !mKeepAliveToken) {
return;
@ -356,15 +346,13 @@ private:
void
MaybeCleanup()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
if (!mKeepAliveToken) {
return;
}
if (mWorkerHolderAdded) {
ReleaseWorker();
}
mWorkerRef = nullptr;
mKeepAliveToken = nullptr;
mSelfRef = nullptr;
}
@ -384,8 +372,7 @@ private:
void
RemovePromise(ExtendableEventResult aResult)
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
MOZ_DIAGNOSTIC_ASSERT(mPendingPromisesCount > 0);
// Note: mSelfRef and mKeepAliveToken can be nullptr here
@ -471,7 +458,7 @@ public:
RefPtr<KeepAliveHandler> keepAliveHandler =
new KeepAliveHandler(mKeepAliveToken, aCallback);
if (NS_WARN_IF(!keepAliveHandler->UseWorkerHolder())) {
if (NS_WARN_IF(!keepAliveHandler->Init())) {
return NS_ERROR_FAILURE;
}
@ -671,20 +658,13 @@ private:
* termination during the execution of life cycle events. It is responsible
* with advancing the job queue for install/activate tasks.
*/
class LifeCycleEventWatcher final : public ExtendableEventCallback,
public WorkerHolder
class LifeCycleEventWatcher final : public ExtendableEventCallback
{
WorkerPrivate* mWorkerPrivate;
RefPtr<StrongWorkerRef> mWorkerRef;
RefPtr<LifeCycleEventCallback> mCallback;
bool mDone;
~LifeCycleEventWatcher()
{
if (mDone) {
return;
}
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
// XXXcatalinb: If all the promises passed to waitUntil go out of scope,
// the resulting Promise.all will be cycle collected and it will drop its
// native handlers (including this object). Instead of waiting for a timeout
@ -695,22 +675,17 @@ class LifeCycleEventWatcher final : public ExtendableEventCallback,
public:
NS_INLINE_DECL_REFCOUNTING(LifeCycleEventWatcher, override)
LifeCycleEventWatcher(WorkerPrivate* aWorkerPrivate,
LifeCycleEventCallback* aCallback)
: WorkerHolder("LifeCycleEventWatcher")
, mWorkerPrivate(aWorkerPrivate)
, mCallback(aCallback)
, mDone(false)
explicit LifeCycleEventWatcher(LifeCycleEventCallback* aCallback)
: mCallback(aCallback)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
}
bool
Init()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
// We need to listen for worker termination in case the event handler
// never completes or never resolves the waitUntil promise. There are
@ -719,52 +694,44 @@ public:
// case the registration/update promise will be rejected
// 2. A new service worker is registered which will terminate the current
// installing worker.
if (NS_WARN_IF(!HoldWorker(mWorkerPrivate, Canceling))) {
NS_WARNING("LifeCycleEventWatcher failed to add feature.");
ReportResult(false);
RefPtr<LifeCycleEventWatcher> self = this;
mWorkerRef =
StrongWorkerRef::Create(workerPrivate, "LifeCycleEventWatcher",
[self]() {
self->ReportResult(false);
});
if (NS_WARN_IF(!mWorkerRef)) {
mCallback->SetResult(false);
nsresult rv = workerPrivate->DispatchToMainThread(mCallback);
Unused << NS_WARN_IF(NS_FAILED(rv));
return false;
}
return true;
}
bool
Notify(WorkerStatus aStatus) override
{
if (aStatus < Canceling) {
return true;
}
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
ReportResult(false);
return true;
}
void
ReportResult(bool aResult)
{
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
if (mDone) {
if (!mWorkerRef) {
return;
}
mDone = true;
mCallback->SetResult(aResult);
nsresult rv = mWorkerPrivate->DispatchToMainThread(mCallback);
nsresult rv = mWorkerRef->Private()->DispatchToMainThread(mCallback);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_CRASH("Failed to dispatch life cycle event handler.");
}
ReleaseWorker();
mWorkerRef = nullptr;
}
void
FinishedWithResult(ExtendableEventResult aResult) override
{
MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(IsCurrentThreadRunningWorker());
ReportResult(aResult == Resolved);
// Note, all WaitUntil() rejections are reported to client consoles
@ -798,8 +765,7 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx,
// It is important to initialize the watcher before actually dispatching
// the event in order to catch worker termination while the event handler
// is still executing. This can happen with infinite loops, for example.
RefPtr<LifeCycleEventWatcher> watcher =
new LifeCycleEventWatcher(aWorkerPrivate, mCallback);
RefPtr<LifeCycleEventWatcher> watcher = new LifeCycleEventWatcher(mCallback);
if (!watcher->Init()) {
return true;

View File

@ -1,3 +1,18 @@
Overview of changes leading to 1.8.3
Wednesday, July 11, 2018
====================================
- A couple of Indic / USE bug fixes.
- Disable vectorization, as it was causing unaligned access bus error on
certain 32bit architectures.
Overview of changes leading to 1.8.2
Tuesday, July 3, 2018
====================================
- Fix infinite loop in Khmer shaper.
- Improve hb_blob_create_from_file() for streams.
Overview of changes leading to 1.8.1
Tuesday, June 12, 2018
====================================
@ -5,6 +20,7 @@ Tuesday, June 12, 2018
- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
- Remove HB_SUBSET_BUILTIN build option. Not necessary.
Overview of changes leading to 1.8.0
Tuesday, June 5, 2018
====================================

View File

@ -1,9 +1,7 @@
gfx/harfbuzz status as of 2018-06-12:
This directory contains the HarfBuzz source from the upstream repo:
https://github.com/harfbuzz/harfbuzz
This directory contains the HarfBuzz source from the 'master' branch of
https://github.com/behdad/harfbuzz.
Current version: 1.8.1
Current version: 1.8.3 [commit 2b76767bf572364d3d647cdd139f2044a7ad06b2]
UPDATING:
@ -11,5 +9,9 @@ Our in-tree copy of HarfBuzz does not depend on any generated files from the
upstream build system. Therefore, it should be sufficient to simply overwrite
the in-tree files one the updated ones from upstream to perform updates.
To simplify this, the in-tree copy can be updated by running
sh update.sh
from within the gfx/harfbuzz directory.
If the collection of source files changes, manual updates to moz.build may be
needed as we don't use the upstream makefiles.

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[1.8.1],
[1.8.3],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@ -78,7 +78,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
])
# Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
save_libs="$LIBS"
LIBS="$LIBS -lm"

View File

@ -277,13 +277,13 @@ endif
check: $(DEF_FILES) # For check-symbols.sh
CLEANFILES += $(DEF_FILES)
harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-subset.def: $(HB_SUBSET_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-icu.def: $(HB_ICU_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
GENERATORS = \

View File

@ -4,8 +4,14 @@ from __future__ import print_function, division, absolute_import
import io, os, re, sys
if len (sys.argv) < 3:
sys.exit("usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]")
output_file = sys.argv[1]
header_paths = sys.argv[2:]
headers_content = []
for h in os.environ["headers"].split (' '):
for h in header_paths:
if h.endswith (".h"):
with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
@ -13,7 +19,7 @@ result = """EXPORTS
%s
LIBRARY lib%s-0.dll""" % (
"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
sys.argv[1].replace ('.def', '')
output_file.replace ('.def', '')
)
with open (sys.argv[1], "w") as f: f.write (result)
with open (output_file, "w") as f: f.write (result)

View File

@ -47,6 +47,9 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
data[0][0x034F] = defaults[0]
data[0][0x2060] = defaults[0]
data[0][0x20F0] = defaults[0]
# TODO https://github.com/roozbehp/unicode-data/issues/9
data[0][0x11C44] = 'Consonant_Placeholder'
data[0][0x11C45] = 'Consonant_Placeholder'
for u in range (0xFE00, 0xFE0F + 1):
data[0][u] = defaults[0]
@ -165,7 +168,7 @@ def is_BASE(U, UISC, UGC):
def is_BASE_IND(U, UISC, UGC):
#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
return (UISC in [Consonant_Dead, Modifying_Letter] or
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45]) or
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
False # SPEC-DRAFT-OUTDATED! U == 0x002D
)
def is_BASE_NUM(U, UISC, UGC):
@ -344,6 +347,9 @@ def map_to_use(data):
if 0xA926 <= U <= 0xA92A: UIPC = Top
if U == 0x111CA: UIPC = Bottom
if U == 0x11300: UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
if U == 0x11302: UIPC = Top
if U == 0x1133C: UIPC = Bottom
if U == 0x1171E: UIPC = Left # Correct?!
if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top

View File

@ -172,7 +172,7 @@ struct trak
hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
foreach_grapheme (buffer, start, end)
{
/* TODO This is wrong. */
buffer->pos[start].x_offset += advance_to_add;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[end].x_advance += advance_to_add;
}
@ -184,7 +184,7 @@ struct trak
hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
foreach_grapheme (buffer, start, end)
{
/* TODO This is wrong. */
buffer->pos[start].y_offset += advance_to_add;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[end].y_advance += advance_to_add;
}

View File

@ -31,8 +31,6 @@
#include "hb-private.hh"
#include "hb-object-private.hh"
/*
* hb_blob_t

View File

@ -31,7 +31,6 @@
#endif
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-blob-private.hh"
#ifdef HAVE_SYS_MMAN_H
@ -489,10 +488,10 @@ hb_blob_t::try_make_writable (void)
#if defined(_WIN32) || defined(__CYGWIN__)
# include <windows.h>
#endif
#ifndef _O_BINARY
# define _O_BINARY 0
#else
# ifndef _O_BINARY
# define _O_BINARY 0
# endif
#endif
#ifndef MAP_NORESERVE
@ -508,6 +507,7 @@ struct hb_mapped_file_t
#endif
};
#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
static void
_hb_mapped_file_destroy (hb_mapped_file_t *file)
{
@ -517,11 +517,12 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file)
UnmapViewOfFile (file->contents);
CloseHandle (file->mapping);
#else
free (file->contents);
assert (0); // If we don't have mmap we shouldn't reach here
#endif
free (file);
}
#endif
/**
* hb_blob_create_from_file:
@ -534,77 +535,109 @@ _hb_mapped_file_destroy (hb_mapped_file_t *file)
hb_blob_t *
hb_blob_create_from_file (const char *file_name)
{
// Adopted from glib's gmappedfile.c with Matthias Clasen and
// Allison Lortie permission but changed a lot to suit our need.
bool writable = false;
hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
Allison Lortie permission but changed a lot to suit our need. */
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
#ifdef HAVE_MMAP
int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
# define CLOSE close
int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
if (unlikely (fd == -1)) goto fail_without_close;
struct stat st;
if (unlikely (fstat (fd, &st) == -1)) goto fail;
// See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142
if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail;
file->length = (unsigned long) st.st_size;
file->contents = (char *) mmap (nullptr, file->length,
writable ? PROT_READ|PROT_WRITE : PROT_READ,
file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
MAP_PRIVATE | MAP_NORESERVE, fd, 0);
if (unlikely (file->contents == MAP_FAILED)) goto fail;
#elif defined(_WIN32) || defined(__CYGWIN__)
HANDLE fd = CreateFile (file_name,
writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ,
FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
# define CLOSE CloseHandle
close (fd);
return hb_blob_create (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
close (fd);
fail_without_close:
free (file);
#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
HANDLE fd;
unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
mbstowcs (wchar_file_name, file_name, size);
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
nullptr);
free (wchar_file_name);
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
file->length = (unsigned long) GetFileSize (fd, nullptr);
file->mapping = CreateFileMapping (fd, nullptr,
writable ? PAGE_WRITECOPY : PAGE_READONLY,
0, 0, nullptr);
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (unlikely (file->mapping == nullptr)) goto fail;
file->contents = (char *) MapViewOfFile (file->mapping,
writable ? FILE_MAP_COPY : FILE_MAP_READ,
0, 0, 0);
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
if (unlikely (file->contents == nullptr)) goto fail;
#else
mm = HB_MEMORY_MODE_WRITABLE;
FILE *fd = fopen (file_name, "rb");
# define CLOSE fclose
if (unlikely (!fd)) goto fail_without_close;
fseek (fd, 0, SEEK_END);
file->length = ftell (fd);
rewind (fd);
file->contents = (char *) malloc (file->length);
if (unlikely (!file->contents)) goto fail;
if (unlikely (fread (file->contents, 1, file->length, fd) != file->length))
goto fail;
#endif
CLOSE (fd);
return hb_blob_create (file->contents, file->length, mm, (void *) file,
CloseHandle (fd);
return hb_blob_create (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
CLOSE (fd);
#undef CLOSE
CloseHandle (fd);
fail_without_close:
free (file);
#endif
/* The following tries to read a file without knowing its size beforehand
It's used as a fallback for systems without mmap or to read from pipes */
unsigned long len = 0, allocated = BUFSIZ * 16;
char *data = (char *) malloc (allocated);
if (unlikely (data == nullptr)) return hb_blob_get_empty ();
FILE *fp = fopen (file_name, "rb");
if (unlikely (fp == nullptr)) goto fread_fail_without_close;
while (!feof (fp))
{
if (allocated - len < BUFSIZ)
{
allocated *= 2;
/* Don't allocate and go more than ~536MB, our mmap reader still
can cover files like that but lets limit our fallback reader */
if (unlikely (allocated > (2 << 28))) goto fread_fail;
char *new_data = (char *) realloc (data, allocated);
if (unlikely (new_data == nullptr)) goto fread_fail;
data = new_data;
}
unsigned long addition = fread (data + len, 1, allocated - len, fp);
int err = ferror (fp);
#ifdef EINTR // armcc doesn't have it
if (unlikely (err == EINTR)) continue;
#endif
if (unlikely (err)) goto fread_fail;
len += addition;
}
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) free);
fread_fail:
fclose (fp);
fread_fail_without_close:
free (data);
return hb_blob_get_empty ();
}

View File

@ -31,7 +31,6 @@
#define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-unicode-private.hh"

View File

@ -124,14 +124,14 @@ hb_buffer_t::enlarge (unsigned int size)
hb_glyph_info_t *new_info = nullptr;
bool separate_out = out_info != info;
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))
goto done;
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
goto done;
new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));

View File

@ -28,8 +28,6 @@
#include "hb-private.hh"
#include "hb-mutex-private.hh"
#include "hb-object-private.hh"
#include <locale.h>
#ifdef HAVE_XLOCALE_H
@ -545,6 +543,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
case HB_SCRIPT_OLD_ITALIC:
case HB_SCRIPT_RUNIC:
return HB_DIRECTION_INVALID;
}

View File

@ -29,7 +29,6 @@
#define HB_SHAPER coretext
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-shaper-impl-private.hh"
#include "hb-coretext.h"

View File

@ -28,6 +28,7 @@
#define HB_DEBUG_HH
#include "hb-private.hh"
#include "hb-dsalgs.hh"
#ifndef HB_DEBUG

View File

@ -23,7 +23,6 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#define HB_SHAPER directwrite
#include "hb-shaper-impl-private.hh"

View File

@ -30,6 +30,243 @@
#include "hb-private.hh"
/* Void! For when we need a expression-type of void. */
typedef const struct _hb_void_t *hb_void_t;
#define HB_VOID ((const _hb_void_t *) nullptr)
/*
* Bithacks.
*/
/* Return the number of 1 bits in v. */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_popcount (T v)
{
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (v);
#endif
if (sizeof (T) <= 4)
{
/* "HACKMEM 169" */
uint32_t y;
y = (v >> 1) &033333333333;
y = v - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
}
if (sizeof (T) == 8)
{
unsigned int shift = 32;
return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of bits needed to store number */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanReverse (&where, v);
return 1 + where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanReverse64 (&where, v);
return 1 + where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
unsigned int r = 0;
for (int i = 4; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
unsigned int r = 0;
for (int i = 5; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
hb_bit_storage<uint64_t> ((uint64_t) v);
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanForward (&where, v);
return where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanForward64 (&where, v);
return where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
unsigned int c = 32;
v &= - (int32_t) v;
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
unsigned int c = 64;
v &= - (int64_t) (v);
if (v) c--;
if (v & 0x00000000FFFFFFFFULL) c -= 32;
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
if (v & 0x3333333333333333ULL) c -= 2;
if (v & 0x5555555555555555ULL) c -= 1;
return c;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/*
* Tiny stuff.
*/
#undef MIN
template <typename Type>
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
#undef MAX
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
{
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
static inline unsigned int
hb_ceil_to_4 (unsigned int v)
{
return ((v - 1) | 3) + 1;
}
/*
* Sort and search.
*/
static inline void *
hb_bsearch_r (const void *key, const void *base,
size_t nmemb, size_t size,
@ -53,7 +290,6 @@ hb_bsearch_r (const void *key, const void *base,
}
/* From https://github.com/noporpoise/sort_r */
/* Isaac Turner 29 April 2014 Public Domain */
@ -158,4 +394,471 @@ static inline void hb_sort_r(void *base, size_t nel, size_t width,
sort_r_simple(base, nel, width, compar, arg);
}
template <typename T, typename T2> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
{
for (unsigned int i = 1; i < len; i++)
{
unsigned int j = i;
while (j && compar (&array[j - 1], &array[i]) > 0)
j--;
if (i == j)
continue;
/* Move item i to occupy place for item j, shift what's in between. */
{
T t = array[i];
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
array[j] = t;
}
if (array2)
{
T2 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
array2[j] = t;
}
}
}
template <typename T> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
hb_stable_sort (array, len, compar, (int *) nullptr);
}
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
/* Pain because we don't know whether s is nul-terminated. */
char buf[64];
len = MIN (ARRAY_LENGTH (buf) - 1, len);
strncpy (buf, s, len);
buf[len] = '\0';
char *end;
errno = 0;
unsigned long v = strtoul (buf, &end, base);
if (errno) return false;
if (*end) return false;
*out = v;
return true;
}
#define HB_VECTOR_INIT {0, 0, false, nullptr}
template <typename Type, unsigned int StaticSize=8>
struct hb_vector_t
{
unsigned int len;
unsigned int allocated;
bool successful;
Type *arrayZ;
Type static_array[StaticSize];
void init (void)
{
len = 0;
allocated = ARRAY_LENGTH (static_array);
successful = true;
arrayZ = static_array;
}
inline Type& operator [] (unsigned int i)
{
if (unlikely (i >= len))
return Crap (Type);
return arrayZ[i];
}
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= len))
return Null(Type);
return arrayZ[i];
}
inline Type *push (void)
{
if (unlikely (!resize (len + 1)))
return &Crap(Type);
return &arrayZ[len - 1];
}
inline Type *push (const Type& v)
{
Type *p = push ();
*p = v;
return p;
}
/* Allocate for size but don't adjust len. */
inline bool alloc (unsigned int size)
{
if (unlikely (!successful))
return false;
if (likely (size <= allocated))
return true;
/* Reallocate */
unsigned int new_allocated = allocated;
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 8;
Type *new_array = nullptr;
if (arrayZ == static_array)
{
new_array = (Type *) calloc (new_allocated, sizeof (Type));
if (new_array)
memcpy (new_array, arrayZ, len * sizeof (Type));
}
else
{
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
}
if (unlikely (!new_array))
{
successful = false;
return false;
}
arrayZ = new_array;
allocated = new_allocated;
return true;
}
inline bool resize (int size_)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (!alloc (size))
return false;
if (size > len)
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
len = size;
return true;
}
inline void pop (void)
{
if (!len) return;
len--;
}
inline void remove (unsigned int i)
{
if (unlikely (i >= len))
return;
memmove (static_cast<void *> (&arrayZ[i]),
static_cast<void *> (&arrayZ[i + 1]),
(len - i - 1) * sizeof (Type));
len--;
}
inline void shrink (int size_)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (size < len)
len = size;
}
template <typename T>
inline Type *find (T v) {
for (unsigned int i = 0; i < len; i++)
if (arrayZ[i] == v)
return &arrayZ[i];
return nullptr;
}
template <typename T>
inline const Type *find (T v) const {
for (unsigned int i = 0; i < len; i++)
if (arrayZ[i] == v)
return &arrayZ[i];
return nullptr;
}
inline void qsort (int (*cmp)(const void*, const void*))
{
::qsort (arrayZ, len, sizeof (Type), cmp);
}
inline void qsort (void)
{
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
}
inline void qsort (unsigned int start, unsigned int end)
{
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
}
template <typename T>
inline Type *lsearch (const T &x)
{
for (unsigned int i = 0; i < len; i++)
if (0 == this->arrayZ[i].cmp (&x))
return &arrayZ[i];
return nullptr;
}
template <typename T>
inline Type *bsearch (const T &x)
{
unsigned int i;
return bfind (x, &i) ? &arrayZ[i] : nullptr;
}
template <typename T>
inline const Type *bsearch (const T &x) const
{
unsigned int i;
return bfind (x, &i) ? &arrayZ[i] : nullptr;
}
template <typename T>
inline bool bfind (const T &x, unsigned int *i) const
{
int min = 0, max = (int) this->len - 1;
while (min <= max)
{
int mid = (min + max) / 2;
int c = this->arrayZ[mid].cmp (&x);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
{
*i = mid;
return true;
}
}
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
max++;
*i = max;
return false;
}
inline void fini (void)
{
if (arrayZ != static_array)
free (arrayZ);
arrayZ = nullptr;
allocated = len = 0;
}
};
#define HB_LOCKABLE_SET_INIT {HB_VECTOR_INIT}
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
{
hb_vector_t <item_t, 1> items;
inline void init (void) { items.init (); }
template <typename T>
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
{
l.lock ();
item_t *item = items.find (v);
if (item) {
if (replace) {
item_t old = *item;
*item = v;
l.unlock ();
old.fini ();
}
else {
item = nullptr;
l.unlock ();
}
} else {
item = items.push (v);
l.unlock ();
}
return item;
}
template <typename T>
inline void remove (T v, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (item) {
item_t old = *item;
*item = items[items.len - 1];
items.pop ();
l.unlock ();
old.fini ();
} else {
l.unlock ();
}
}
template <typename T>
inline bool find (T v, item_t *i, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (item)
*i = *item;
l.unlock ();
return !!item;
}
template <typename T>
inline item_t *find_or_insert (T v, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (!item) {
item = items.push (v);
}
l.unlock ();
return item;
}
inline void fini (lock_t &l)
{
if (!items.len) {
/* No need for locking. */
items.fini ();
return;
}
l.lock ();
while (items.len) {
item_t old = items[items.len - 1];
items.pop ();
l.unlock ();
old.fini ();
l.lock ();
}
items.fini ();
l.unlock ();
}
};
template <typename Type>
struct hb_auto_t : Type
{
hb_auto_t (void) { Type::init (); }
~hb_auto_t (void) { Type::fini (); }
private: /* Hide */
void init (void) {}
void fini (void) {}
};
struct hb_bytes_t
{
inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
inline int cmp (const hb_bytes_t &a) const
{
if (len != a.len)
return (int) a.len - (int) len;
return memcmp (a.bytes, bytes, len);
}
static inline int cmp (const void *pa, const void *pb)
{
hb_bytes_t *a = (hb_bytes_t *) pa;
hb_bytes_t *b = (hb_bytes_t *) pb;
return b->cmp (*a);
}
const char *bytes;
unsigned int len;
};
struct HbOpOr
{
static const bool passthru_left = true;
static const bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
};
struct HbOpAnd
{
static const bool passthru_left = false;
static const bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
};
struct HbOpMinus
{
static const bool passthru_left = true;
static const bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
};
struct HbOpXor
{
static const bool passthru_left = true;
static const bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
};
/* Compiler-assisted vectorization. */
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
* using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
* Define that to 0 to disable. */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { return u.v[i]; }
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
template <class Op>
inline hb_vector_size_t process (const hb_vector_size_t &o) const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
return r;
}
inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
{ return process<HbOpOr> (o); }
inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
{ return process<HbOpAnd> (o); }
inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
{ return process<HbOpXor> (o); }
inline hb_vector_size_t operator ~ () const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE && 0
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
r.u.vec[i] = ~u.vec[i];
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
r.u.v[i] = ~u.v[i];
return r;
}
private:
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
union {
elt_t v[byte_size / sizeof (elt_t)];
#if HB_VECTOR_SIZE
typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
vec_t vec[byte_size / sizeof (vec_t)];
#endif
} u;
};
#endif /* HB_DSALGS_HH */

View File

@ -31,7 +31,6 @@
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-shaper-private.hh"
#include "hb-shape-plan-private.hh"

View File

@ -31,7 +31,6 @@
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-face-private.hh"
#include "hb-shaper-private.hh"

View File

@ -28,7 +28,6 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-ft.h"

View File

@ -28,7 +28,6 @@
#define HB_MAP_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
template <typename T>
@ -89,7 +88,7 @@ struct hb_map_t
{
if (unlikely (!successful)) return false;
unsigned int power = _hb_bit_storage (population * 2 + 8);
unsigned int power = hb_bit_storage (population * 2 + 8);
unsigned int new_size = 1u << power;
item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
if (unlikely (!new_items))

View File

@ -33,8 +33,6 @@
#define HB_OBJECT_PRIVATE_HH
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-atomic-private.hh"
#include "hb-mutex-private.hh"

View File

@ -286,6 +286,197 @@ struct TTCHeader
} u;
};
/*
* Mac Resource Fork
*/
struct ResourceRefItem
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
// actual data sanitization is done on ResourceForkHeader sanitizer
return_trace (likely (c->check_struct (this)));
}
HBINT16 id; /* Resource ID, is really should be signed? */
HBINT16 nameOffset; /* Offset from beginning of resource name list
* to resource name, minus means there is no */
HBUINT8 attr; /* Resource attributes */
HBUINT24 dataOffset; /* Offset from beginning of resource data to
* data for this resource */
HBUINT32 reserved; /* Reserved for handle to resource */
public:
DEFINE_SIZE_STATIC (12);
};
struct ResourceTypeItem
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
// RefList sanitization is done on ResourceMap sanitizer
return_trace (likely (c->check_struct (this)));
}
inline unsigned int get_resource_count () const
{
return numRes + 1;
}
inline bool is_sfnt () const
{
return type == HB_TAG ('s','f','n','t');
}
inline const ResourceRefItem& get_ref_item (const void *base,
unsigned int i) const
{
return (base+refList)[i];
}
protected:
Tag type; /* Resource type */
HBUINT16 numRes; /* Number of resource this type in map minus 1 */
OffsetTo<UnsizedArrayOf<ResourceRefItem> >
refList; /* Offset from beginning of resource type list
* to reference list for this type */
public:
DEFINE_SIZE_STATIC (8);
};
struct ResourceMap
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
for (unsigned int i = 0; i < get_types_count (); ++i)
{
const ResourceTypeItem& type = get_type (i);
if (unlikely (!type.sanitize (c)))
return_trace (false);
for (unsigned int j = 0; j < type.get_resource_count (); ++j)
if (unlikely (!get_ref_item (type, j).sanitize (c)))
return_trace (false);
}
return_trace (true);
}
inline const ResourceTypeItem& get_type (unsigned int i) const
{
// Why offset from the second byte of the object? I'm not sure
return ((&reserved[2])+typeList)[i];
}
inline unsigned int get_types_count () const
{
return nTypes + 1;
}
inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type,
unsigned int i) const
{
return type.get_ref_item (&(this+typeList), i);
}
inline const PString& get_name (const ResourceRefItem &item,
unsigned int i) const
{
if (item.nameOffset == -1)
return Null (PString);
return StructAtOffset<PString> (this, nameList + item.nameOffset);
}
protected:
HBUINT8 reserved[16]; /* Reserved for copy of resource header */
LOffsetTo<ResourceMap>
reserved1; /* Reserved for handle to next resource map */
HBUINT16 reserved2; /* Reserved for file reference number */
HBUINT16 attr; /* Resource fork attribute */
OffsetTo<UnsizedArrayOf<ResourceTypeItem> >
typeList; /* Offset from beginning of map to
* resource type list */
HBUINT16 nameList; /* Offset from beginning of map to
* resource name list */
HBUINT16 nTypes; /* Number of types in the map minus 1 */
public:
DEFINE_SIZE_STATIC (30);
};
struct ResourceForkHeader
{
inline unsigned int get_face_count () const
{
const ResourceMap &resource_map = this+map;
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
{
const ResourceTypeItem& type = resource_map.get_type (i);
if (type.is_sfnt ())
return type.get_resource_count ();
}
return 0;
}
inline const LArrayOf<HBUINT8>& get_data (const ResourceTypeItem& type,
unsigned int idx) const
{
const ResourceMap &resource_map = this+map;
unsigned int offset = dataOffset;
offset += resource_map.get_ref_item (type, idx).dataOffset;
return StructAtOffset<LArrayOf<HBUINT8> > (this, offset);
}
inline const OpenTypeFontFace& get_face (unsigned int idx) const
{
const ResourceMap &resource_map = this+map;
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
{
const ResourceTypeItem& type = resource_map.get_type (i);
if (type.is_sfnt () && idx < type.get_resource_count ())
return (OpenTypeFontFace&) get_data (type, idx).arrayZ;
}
return Null (OpenTypeFontFace);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
const ResourceMap &resource_map = this+map;
if (unlikely (!resource_map.sanitize (c)))
return_trace (false);
for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
{
const ResourceTypeItem& type = resource_map.get_type (i);
for (unsigned int j = 0; j < type.get_resource_count (); ++j)
{
const LArrayOf<HBUINT8>& data = get_data (type, j);
if (unlikely (!(data.sanitize (c) &&
((OpenTypeFontFace&) data.arrayZ).sanitize (c))))
return_trace (false);
}
}
return_trace (true);
}
protected:
HBUINT32 dataOffset; /* Offset from beginning of resource fork
* to resource data */
LOffsetTo<ResourceMap>
map; /* Offset from beginning of resource fork
* to resource map */
HBUINT32 dataLen; /* Length of resource data */
HBUINT32 mapLen; /* Length of resource map */
public:
DEFINE_SIZE_STATIC (16);
};
/*
* OpenType Font File
@ -299,6 +490,7 @@ struct OpenTypeFontFile
CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */
DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */
TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */
Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */
};
@ -313,6 +505,7 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return 1;
case TTCTag: return u.ttcHeader.get_face_count ();
// case DFontTag: return u.rfHeader.get_face_count ();
default: return 0;
}
}
@ -327,6 +520,7 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return u.fontFace;
case TTCTag: return u.ttcHeader.get_face (i);
// case DFontTag: return u.rfHeader.get_face (i);
default: return Null(OpenTypeFontFace);
}
}
@ -353,6 +547,7 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return_trace (u.fontFace.sanitize (c));
case TTCTag: return_trace (u.ttcHeader.sanitize (c));
// case DFontTag: return_trace (u.rfHeader.sanitize (c));
default: return_trace (true);
}
}
@ -362,6 +557,7 @@ struct OpenTypeFontFile
Tag tag; /* 4-byte identifier. */
OpenTypeFontFace fontFace;
TTCHeader ttcHeader;
ResourceForkHeader rfHeader;
} u;
public:
DEFINE_SIZE_UNION (4, tag);

View File

@ -30,7 +30,6 @@
#define HB_OPEN_TYPE_PRIVATE_HH
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-blob-private.hh"
#include "hb-face-private.hh"
@ -230,7 +229,7 @@ struct hb_sanitize_context_t :
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
{
const char *p = (const char *) base;
bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
bool overflows = hb_unsigned_mul_overflows (len, record_size);
unsigned int array_size = record_size * len;
bool ok = !overflows && this->check_range (base, array_size);
@ -1033,6 +1032,7 @@ struct ArrayOf
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
typedef ArrayOf<HBUINT8, HBUINT8> PString;
/* Array of Offset's */
template <typename Type, typename OffsetType=HBUINT16>
@ -1177,7 +1177,7 @@ struct BinSearchHeader
{
len.set (v);
assert (len == v);
entrySelector.set (MAX (1u, _hb_bit_storage (v)) - 1);
entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
searchRange.set (16 * (1u << entrySelector));
rangeShift.set (v * 16 > searchRange
? 16 * v - searchRange

View File

@ -89,7 +89,7 @@ struct CmapSubtableFormat4
this->length.set (get_sub_table_size (segments));
this->segCountX2.set (segments.len * 2);
this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
this->entrySelector.set (MAX (1u, hb_bit_storage (segments.len)) - 1);
this->searchRange.set (2 * (1u << this->entrySelector));
this->rangeShift.set (segments.len * 2 > this->searchRange
? 2 * segments.len - this->searchRange

View File

@ -199,7 +199,7 @@ struct hdmx
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && version == 0 &&
!_hb_unsigned_int_mul_overflows (num_records, size_device_record) &&
!hb_unsigned_mul_overflows (num_records, size_device_record) &&
size_device_record >= DeviceRecord::min_size &&
c->check_range (this, get_size()));
}

View File

@ -30,7 +30,6 @@
#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-ot-layout-private.hh"
#include "hb-open-type-private.hh"
#include "hb-set-private.hh"
@ -832,7 +831,12 @@ struct CoverageFormat2
c = &c_;
coverage = 0;
i = 0;
j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
{
/* Broken table. Skip. */
i = c->rangeRecord.len;
}
}
inline bool more (void) { return i < c->rangeRecord.len; }
inline void next (void)
@ -842,7 +846,14 @@ struct CoverageFormat2
i++;
if (more ())
{
hb_codepoint_t old = j;
j = c->rangeRecord[i].start;
if (unlikely (j <= old))
{
/* Broken table. Skip. Important to avoid DoS. */
i = c->rangeRecord.len;
return;
}
coverage = c->rangeRecord[i].value;
}
return;
@ -855,7 +866,8 @@ struct CoverageFormat2
private:
const struct CoverageFormat2 *c;
unsigned int i, j, coverage;
unsigned int i, coverage;
hb_codepoint_t j;
};
private:

View File

@ -99,7 +99,7 @@ struct ValueFormat : HBUINT16
#endif
inline unsigned int get_len (void) const
{ return _hb_popcount ((unsigned int) *this); }
{ return hb_popcount ((unsigned int) *this); }
inline unsigned int get_size (void) const
{ return get_len () * Value::static_size; }
@ -374,7 +374,7 @@ struct AnchorMatrix
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
@ -1074,10 +1074,13 @@ struct MarkBasePosFormat1
if (!skippy_iter.prev ()) return_trace (false);
/* We only want to attach to the first of a MultipleSubst sequence.
* https://github.com/harfbuzz/harfbuzz/issues/740
* Reject others. */
* Reject others...
* ...but stop if we find a mark in the MultipleSubst sequence:
* https://github.com/harfbuzz/harfbuzz/issues/1020 */
if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
(skippy_iter.idx == 0 ||
_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=

View File

@ -511,7 +511,7 @@ struct AlternateSubstFormat1
hb_mask_t lookup_mask = c->lookup_mask;
/* Note: This breaks badly if two features enabled this lookup together. */
unsigned int shift = _hb_ctz (lookup_mask);
unsigned int shift = hb_ctz (lookup_mask);
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);

View File

@ -30,7 +30,6 @@
#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-buffer-private.hh"
#include "hb-map-private.hh"
#include "hb-ot-layout-gdef-table.hh"
@ -388,7 +387,7 @@ struct hb_ot_apply_context_t :
inline bool prev (void)
{
assert (num_items > 0);
while (idx >= num_items)
while (idx > num_items - 1)
{
idx--;
const hb_glyph_info_t &info = c->buffer->out_info[idx];

View File

@ -145,7 +145,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
{
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
unsigned int global_bit_shift = _hb_popcount (HB_GLYPH_FLAG_DEFINED);
unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
m.global_mask = global_bit_mask;
@ -209,7 +209,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
bits_needed = 0;
else
/* Limit to 8 bits per feature. */
bits_needed = MIN(8u, _hb_bit_storage (info->max_value));
bits_needed = MIN(8u, hb_bit_storage (info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
continue; /* Feature disabled, or not enough bits. */

View File

@ -28,7 +28,6 @@
#define HB_OT_OS2_UNICODE_RANGES_HH
#include "hb-private.hh"
#include "hb-dsalgs.hh"
namespace OT {

View File

@ -28,7 +28,6 @@
#define HB_OT_POST_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-dsalgs.hh"
#include "hb-subset-plan.hh"
#define HB_STRING_ARRAY_NAME format1_names

View File

@ -25,7 +25,6 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-ot-shape-complex-arabic-private.hh"
#include "hb-ot-shape-private.hh"

View File

@ -668,8 +668,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
*
* Reports suggest that in some scripts Uniscribe does this only if there
* is *not* a Halant after last consonant already (eg. Kannada), while it
* does it unconditionally in other scripts (eg. Malayalam). We don't
* currently know about other scripts, so we single out Malayalam for now.
* does it unconditionally in other scripts (eg. Malayalam, Bengali). We
* don't currently know about other scripts, so we whitelist Malayalam and
* Bengali for now.
*
* Kannada test case:
* U+0C9A,U+0CCD,U+0C9A,U+0CCD
@ -679,10 +680,16 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* Malayalam test case:
* U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
* With lohit-ttf-20121122/Lohit-Malayalam.ttf
*
* Bengali test case
* U+0998,U+09CD,U+09AF,U+09CD
* With Windows XP vrinda.ttf
* https://github.com/harfbuzz/harfbuzz/issues/1073
*/
if (indic_plan->is_old_spec)
{
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM &&
buffer->props.script != HB_SCRIPT_BENGALI;
for (unsigned int i = base + 1; i < end; i++)
if (info[i].indic_category() == OT_H)
{
@ -1120,6 +1127,24 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* defined as after last standalone halant glyph, after initial matra
* position and before the main consonant. If ZWJ or ZWNJ follow this
* halant, position is moved after it.
*
* IMPLEMENTATION NOTES:
*
* It looks like the last sentence is wrong. Testing, with Windows 7 Uniscribe
* and Devanagari shows that the behavior is best described as:
*
* "If ZWJ follows this halant, matra is NOT repositioned after this halant.
* If ZWNJ follows this halant, position is moved after it."
*
* Test case, with Adobe Devanagari or Nirmala UI:
*
* U+091F,U+094D,U+200C,U+092F,U+093F
* (Matra moves to the middle, after ZWNJ.)
*
* U+091F,U+094D,U+200D,U+092F,U+093F
* (Matra does NOT move, stays to the left.)
*
* https://github.com/harfbuzz/harfbuzz/issues/1070
*/
if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
@ -1133,6 +1158,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
*/
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{
search:
while (new_pos > start &&
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H)))))
new_pos--;
@ -1143,9 +1169,27 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (is_halant (info[new_pos]) &&
info[new_pos].indic_position() != POS_PRE_M)
{
#if 0 // See comment above
/* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
new_pos++;
#endif
if (new_pos + 1 < end)
{
/* -> If ZWJ follows this halant, matra is NOT repositioned after this halant. */
if (info[new_pos + 1].indic_category() == OT_ZWJ)
{
/* Keep searching. */
if (new_pos > start)
{
new_pos--;
goto search;
}
}
/* -> If ZWNJ follows this halant, position is moved after it. */
if (info[new_pos + 1].indic_category() == OT_ZWNJ)
new_pos++;
}
}
else
new_pos = start; /* No move. */

View File

@ -372,22 +372,25 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
break;
}
/* Note! syllable() is a one-byte field. */
for (unsigned int i = base; i < end; i++)
if (info[i].syllable() != 255)
{
unsigned int max = i;
unsigned int j = start + info[i].syllable();
while (j != i)
if (unlikely (end - start >= 127))
buffer->merge_clusters (start, end);
else
/* Note! syllable() is a one-byte field. */
for (unsigned int i = base; i < end; i++)
if (info[i].syllable() != 255)
{
max = MAX (max, j);
unsigned int next = start + info[j].syllable();
info[j].syllable() = 255; /* So we don't process j later again. */
j = next;
unsigned int max = i;
unsigned int j = start + info[i].syllable();
while (j != i)
{
max = MAX (max, j);
unsigned int next = start + info[j].syllable();
info[j].syllable() = 255; /* So we don't process j later again. */
j = next;
}
if (i != max)
buffer->merge_clusters (i, max + 1);
}
if (i != max)
buffer->merge_clusters (i, max + 1);
}
/* Put syllable back in. */
for (unsigned int i = start; i < end; i++)

View File

@ -560,7 +560,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Grantha */
/* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
/* 11300 */ VMAbv, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
/* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst,
@ -673,7 +673,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
/* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H,
/* 11C40 */ B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* 11C40 */ B, O, O, O, GB, GB, O, O, O, O, O, O, O, O, O, O,
/* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,

View File

@ -829,12 +829,12 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
c->buffer->deallocate_var_all ();
c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR)))
{
c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR,
(unsigned) HB_BUFFER_MAX_LEN_MIN);
}
if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR)))
{
c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR,
(unsigned) HB_BUFFER_MAX_OPS_MIN);

View File

@ -58,6 +58,7 @@
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)
/* Compile-time custom allocator support. */
#if defined(hb_malloc_impl) \
@ -72,18 +73,41 @@ extern "C" void hb_free_impl(void *ptr);
#define calloc hb_calloc_impl
#define realloc hb_realloc_impl
#define free hb_free_impl
#if defined(hb_memalign_impl)
extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
#define posix_memalign hb_memalign_impl
#else
#undef HAVE_POSIX_MEMALIGN
#endif
#endif
/* Compiler attributes */
template <typename T>
struct _hb_alignof
{
struct s
{
char c;
T t;
};
static constexpr unsigned int value = offsetof (s, t);
};
#if __cplusplus < 201103L
#ifndef nullptr
#define nullptr NULL
#endif
#ifndef constexpr
#define constexpr const
#endif
// Static assertions
#ifndef static_assert
#define static_assert(e, msg) \
@ -98,6 +122,10 @@ extern "C" void hb_free_impl(void *ptr);
#define thread_local
#endif
#ifndef alignof
#define alignof(x) (_hb_alignof<x>::value)
#endif // alignof
#endif // __cplusplus < 201103L
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
@ -251,26 +279,6 @@ static int errno = 0; /* Use something better? */
# undef HB_USE_ATEXIT
#endif
/* Basics */
#undef MIN
template <typename Type>
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
#undef MAX
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
#define HB_STMT_START do
#define HB_STMT_END while (0)
@ -322,223 +330,6 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
/* Tiny functions */
/*
* Void!
*/
typedef const struct _hb_void_t *hb_void_t;
#define HB_VOID ((const _hb_void_t *) nullptr)
/* Return the number of 1 bits in v. */
template <typename T>
static inline HB_CONST_FUNC unsigned int
_hb_popcount (T v)
{
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (v);
#endif
if (sizeof (T) <= 4)
{
/* "HACKMEM 169" */
uint32_t y;
y = (v >> 1) &033333333333;
y = v - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
}
if (sizeof (T) == 8)
{
unsigned int shift = 32;
return _hb_popcount<uint32_t> ((uint32_t) v) + _hb_popcount ((uint32_t) (v >> shift));
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return _hb_popcount<uint64_t> ((uint64_t) v) + _hb_popcount ((uint64_t) (v >> shift));
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of bits needed to store number */
template <typename T>
static inline HB_CONST_FUNC unsigned int
_hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanReverse (&where, v);
return 1 + where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanReverse64 (&where, v);
return 1 + where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
unsigned int r = 0;
for (int i = 4; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
unsigned int r = 0;
for (int i = 5; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
_hb_bit_storage<uint64_t> ((uint64_t) v);
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
static inline HB_CONST_FUNC unsigned int
_hb_ctz (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanForward (&where, v);
return where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanForward64 (&where, v);
return where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
unsigned int c = 32;
v &= - (int32_t) v;
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
unsigned int c = 64;
v &= - (int64_t) (v);
if (v) c--;
if (v & 0x00000000FFFFFFFFULL) c -= 32;
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
if (v & 0x3333333333333333ULL) c -= 2;
if (v & 0x5555555555555555ULL) c -= 1;
return c;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (uint64_t) v ? _hb_bit_storage<uint64_t> ((uint64_t) v) :
_hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift;
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
static inline bool
_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
{
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
static inline unsigned int
_hb_ceil_to_4 (unsigned int v)
{
return ((v - 1) | 3) + 1;
}
/*
*
* Utility types
*
*/
#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
@ -620,321 +411,6 @@ struct CrapOrNull<const Type> {
#define CrapOrNull(Type) CrapOrNull<Type>::get ()
/* arrays and maps */
#define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
template <typename Type, unsigned int StaticSize=8>
struct hb_vector_t
{
unsigned int len;
unsigned int allocated;
bool successful;
Type *arrayZ;
Type static_array[StaticSize];
void init (void)
{
len = 0;
allocated = ARRAY_LENGTH (static_array);
successful = true;
arrayZ = static_array;
}
inline Type& operator [] (unsigned int i)
{
if (unlikely (i >= len))
return Crap (Type);
return arrayZ[i];
}
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= len))
return Null(Type);
return arrayZ[i];
}
inline Type *push (void)
{
if (unlikely (!resize (len + 1)))
return &Crap(Type);
return &arrayZ[len - 1];
}
inline Type *push (const Type& v)
{
Type *p = push ();
*p = v;
return p;
}
/* Allocate for size but don't adjust len. */
inline bool alloc (unsigned int size)
{
if (unlikely (!successful))
return false;
if (likely (size <= allocated))
return true;
/* Reallocate */
unsigned int new_allocated = allocated;
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 8;
Type *new_array = nullptr;
if (arrayZ == static_array)
{
new_array = (Type *) calloc (new_allocated, sizeof (Type));
if (new_array)
memcpy (new_array, arrayZ, len * sizeof (Type));
}
else
{
bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
}
if (unlikely (!new_array))
{
successful = false;
return false;
}
arrayZ = new_array;
allocated = new_allocated;
return true;
}
inline bool resize (int size_)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (!alloc (size))
return false;
if (size > len)
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
len = size;
return true;
}
inline void pop (void)
{
if (!len) return;
len--;
}
inline void remove (unsigned int i)
{
if (unlikely (i >= len))
return;
memmove (static_cast<void *> (&arrayZ[i]),
static_cast<void *> (&arrayZ[i + 1]),
(len - i - 1) * sizeof (Type));
len--;
}
inline void shrink (int size_)
{
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
if (size < len)
len = size;
}
template <typename T>
inline Type *find (T v) {
for (unsigned int i = 0; i < len; i++)
if (arrayZ[i] == v)
return &arrayZ[i];
return nullptr;
}
template <typename T>
inline const Type *find (T v) const {
for (unsigned int i = 0; i < len; i++)
if (arrayZ[i] == v)
return &arrayZ[i];
return nullptr;
}
inline void qsort (int (*cmp)(const void*, const void*))
{
::qsort (arrayZ, len, sizeof (Type), cmp);
}
inline void qsort (void)
{
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
}
inline void qsort (unsigned int start, unsigned int end)
{
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
}
template <typename T>
inline Type *lsearch (const T &x)
{
for (unsigned int i = 0; i < len; i++)
if (0 == this->arrayZ[i].cmp (&x))
return &arrayZ[i];
return nullptr;
}
template <typename T>
inline Type *bsearch (const T &x)
{
unsigned int i;
return bfind (x, &i) ? &arrayZ[i] : nullptr;
}
template <typename T>
inline const Type *bsearch (const T &x) const
{
unsigned int i;
return bfind (x, &i) ? &arrayZ[i] : nullptr;
}
template <typename T>
inline bool bfind (const T &x, unsigned int *i) const
{
int min = 0, max = (int) this->len - 1;
while (min <= max)
{
int mid = (min + max) / 2;
int c = this->arrayZ[mid].cmp (&x);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
{
*i = mid;
return true;
}
}
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
max++;
*i = max;
return false;
}
inline void fini (void)
{
if (arrayZ != static_array)
free (arrayZ);
arrayZ = nullptr;
allocated = len = 0;
}
};
template <typename Type>
struct hb_auto_t : Type
{
hb_auto_t (void) { Type::init (); }
~hb_auto_t (void) { Type::fini (); }
private: /* Hide */
void init (void) {}
void fini (void) {}
};
template <typename Type>
struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {};
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
template <typename item_t, typename lock_t>
struct hb_lockable_set_t
{
hb_vector_t <item_t, 1> items;
inline void init (void) { items.init (); }
template <typename T>
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
{
l.lock ();
item_t *item = items.find (v);
if (item) {
if (replace) {
item_t old = *item;
*item = v;
l.unlock ();
old.fini ();
}
else {
item = nullptr;
l.unlock ();
}
} else {
item = items.push (v);
l.unlock ();
}
return item;
}
template <typename T>
inline void remove (T v, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (item) {
item_t old = *item;
*item = items[items.len - 1];
items.pop ();
l.unlock ();
old.fini ();
} else {
l.unlock ();
}
}
template <typename T>
inline bool find (T v, item_t *i, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (item)
*i = *item;
l.unlock ();
return !!item;
}
template <typename T>
inline item_t *find_or_insert (T v, lock_t &l)
{
l.lock ();
item_t *item = items.find (v);
if (!item) {
item = items.push (v);
}
l.unlock ();
return item;
}
inline void fini (lock_t &l)
{
if (!items.len) {
/* No need for locking. */
items.fini ();
return;
}
l.lock ();
while (items.len) {
item_t old = items[items.len - 1];
items.pop ();
l.unlock ();
old.fini ();
l.lock ();
}
items.fini ();
l.unlock ();
}
};
/* ASCII tag/character handling */
static inline bool ISALPHA (unsigned char c)
@ -1027,145 +503,29 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
template <typename T, typename T2> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
{
for (unsigned int i = 1; i < len; i++)
{
unsigned int j = i;
while (j && compar (&array[j - 1], &array[i]) > 0)
j--;
if (i == j)
continue;
/* Move item i to occupy place for item j, shift what's in between. */
{
T t = array[i];
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
array[j] = t;
}
if (array2)
{
T2 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
array2[j] = t;
}
}
}
template <typename T> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
hb_stable_sort (array, len, compar, (int *) nullptr);
}
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
/* Pain because we don't know whether s is nul-terminated. */
char buf[64];
len = MIN (ARRAY_LENGTH (buf) - 1, len);
strncpy (buf, s, len);
buf[len] = '\0';
char *end;
errno = 0;
unsigned long v = strtoul (buf, &end, base);
if (errno) return false;
if (*end) return false;
*out = v;
return true;
}
/* Vectorization */
struct HbOpOr
{
static const bool passthru_left = true;
static const bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
};
struct HbOpAnd
{
static const bool passthru_left = false;
static const bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
};
struct HbOpMinus
{
static const bool passthru_left = true;
static const bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
};
struct HbOpXor
{
static const bool passthru_left = true;
static const bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
};
/* Compiler-assisted vectorization. */
/*
* Disable vectorization for now. To correctly use them, we should
* use posix_memalign() to allocate them. Otherwise, can cause
* misaligned access.
*
* https://bugs.chromium.org/p/chromium/issues/detail?id=860184
*/
#if !defined(HB_VECTOR_SIZE)
# define HB_VECTOR_SIZE 0
#endif
/* The `vector_size' attribute was introduced in gcc 3.1. */
#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
#define HB_VECTOR_SIZE 128
#elif !defined(HB_VECTOR_SIZE)
#define HB_VECTOR_SIZE 0
#if !defined(HB_VECTOR_SIZE)
# if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
# define HB_VECTOR_SIZE 128
# else
# define HB_VECTOR_SIZE 0
# endif
#endif
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { return u.v[i]; }
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
template <class Op>
inline hb_vector_size_t process (const hb_vector_size_t &o) const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
return r;
}
inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
{ return process<HbOpOr> (o); }
inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
{ return process<HbOpAnd> (o); }
inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
{ return process<HbOpXor> (o); }
inline hb_vector_size_t operator ~ () const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE && 0
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
r.u.vec[i] = ~u.vec[i];
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
r.u.v[i] = ~u.v[i];
return r;
}
private:
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
union {
elt_t v[byte_size / sizeof (elt_t)];
#if HB_VECTOR_SIZE
typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
vec_t vec[byte_size / sizeof (vec_t)];
#endif
} u;
};
/* Global runtime options. */
@ -1199,43 +559,52 @@ hb_options (void)
#define VAR 1
/* String type. */
struct hb_bytes_t
{
inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
inline int cmp (const hb_bytes_t &a) const
{
if (len != a.len)
return (int) a.len - (int) len;
return memcmp (a.bytes, bytes, len);
}
static inline int cmp (const void *pa, const void *pb)
{
hb_bytes_t *a = (hb_bytes_t *) pa;
hb_bytes_t *b = (hb_bytes_t *) pb;
return b->cmp (*a);
}
const char *bytes;
unsigned int len;
};
/* fallback for round() */
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
static inline double
round (double x)
_hb_round (double x)
{
if (x >= 0)
return floor (x + 0.5);
else
return ceil (x - 0.5);
}
#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
#define round(x) _hb_round(x)
#endif
/* fallback for posix_memalign() */
static inline int
_hb_memalign(void **memptr, size_t alignment, size_t size)
{
if (unlikely (0 != (alignment & (alignment - 1)) ||
!alignment ||
0 != (alignment & (sizeof (void *) - 1))))
return EINVAL;
char *p = (char *) malloc (size + alignment - 1);
if (unlikely (!p))
return ENOMEM;
size_t off = (size_t) p & (alignment - 1);
if (off)
p += alignment - off;
*memptr = (void *) p;
return 0;
}
#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN)
#define posix_memalign _hb_memalign
#endif
/* Headers we include for everyone. Keep sorted. They express dependency amongst
* themselves, but no other file should include them.*/
#include "hb-atomic-private.hh"
#include "hb-debug.hh"
#include "hb-dsalgs.hh"
#include "hb-mutex-private.hh"
#include "hb-object-private.hh"
#endif /* HB_PRIVATE_HH */

View File

@ -28,7 +28,6 @@
#define HB_SET_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
/*
@ -94,7 +93,7 @@ struct hb_set_t
{
unsigned int pop = 0;
for (unsigned int i = 0; i < len (); i++)
pop += _hb_popcount (v[i]);
pop += hb_popcount (v[i]);
return pop;
}
@ -161,8 +160,8 @@ struct hb_set_t
static const unsigned int PAGE_BITS = 512;
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static inline unsigned int elt_get_min (const elt_t &elt) { return _hb_ctz (elt); }
static inline unsigned int elt_get_max (const elt_t &elt) { return _hb_bit_storage (elt) - 1; }
static inline unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
static inline unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
@ -405,6 +404,7 @@ struct hb_set_t
if (get_population () > larger_set->get_population ())
return false;
/* TODO Optimize to use pages. */
hb_codepoint_t c = INVALID;
while (next (&c))
if (!larger_set->has (c))

View File

@ -28,7 +28,6 @@
#define HB_SHAPE_PLAN_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-shaper-private.hh"

View File

@ -25,7 +25,6 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-shape-plan-private.hh"
#include "hb-shaper-private.hh"
#include "hb-font-private.hh"

View File

@ -24,7 +24,6 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
#include "hb-object-private.hh"
#include "hb-subset-private.hh"
#include "hb-set-private.hh"

View File

@ -32,7 +32,6 @@
#include "hb-subset.h"
#include "hb-subset-private.hh"
#include "hb-object-private.hh"
#include "hb-map-private.hh"
struct hb_subset_plan_t

View File

@ -25,7 +25,6 @@
*/
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-open-type-private.hh"
#include "hb-subset-glyf.hh"
@ -154,7 +153,7 @@ _hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += _hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))

View File

@ -32,7 +32,6 @@
#define HB_UNICODE_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];

View File

@ -25,7 +25,6 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#define HB_SHAPER uniscribe
#include "hb-shaper-impl-private.hh"

View File

@ -38,9 +38,9 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
#define HB_VERSION_MINOR 8
#define HB_VERSION_MICRO 1
#define HB_VERSION_MICRO 3
#define HB_VERSION_STRING "1.8.1"
#define HB_VERSION_STRING "1.8.3"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \

View File

@ -24,9 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb-atomic-private.hh"
#include "hb-mutex-private.hh"
#include "hb-private.hh"
#if defined(HB_ATOMIC_INT_NIL)
#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"

View File

@ -78,6 +78,9 @@ main (int argc, char **argv)
case OpenTypeFontFile::Typ1Tag:
printf ("Obsolete Apple Type1 font in SFNT container\n");
break;
case OpenTypeFontFile::DFontTag:
printf ("DFont Mac Resource Fork\n");
break;
default:
printf ("Unknown font format\n");
break;

32
gfx/harfbuzz/update.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
# Script to update the mozilla in-tree copy of the HarfBuzz library.
# Run this within the /gfx/harfbuzz directory of the source tree.
MY_TEMP_DIR=`mktemp -d -t harfbuzz_update.XXXXXX` || exit 1
VERSION=1.8.3
git clone https://github.com/harfbuzz/harfbuzz ${MY_TEMP_DIR}/harfbuzz
git -C ${MY_TEMP_DIR}/harfbuzz checkout ${VERSION}
COMMIT=$(git -C ${MY_TEMP_DIR}/harfbuzz rev-parse HEAD)
perl -p -i -e "s/(\d+\.)(\d+\.)(\d+)/${VERSION}/" README-mozilla;
perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README-mozilla;
FILES="AUTHORS autogen.sh configure.ac COPYING git.mk harfbuzz.doap Makefile.am NEWS README src THANKS TODO"
for f in $FILES; do
rm -rf $f
mv ${MY_TEMP_DIR}/harfbuzz/$f $f
done
rm -rf src/hb-ucdn
rm -rf ${MY_TEMP_DIR}
hg revert -r . src/moz.build
hg addremove
echo "###"
echo "### Updated HarfBuzz to $COMMIT."
echo "### Remember to verify and commit the changes to source control!"
echo "###"

View File

@ -136,8 +136,6 @@ public:
*/
virtual APZInputBridge* InputBridge() = 0;
virtual void Destroy() {}
protected:
// Discourage destruction outside of decref

View File

@ -51,7 +51,6 @@ APZCTreeManagerChild::Destroy()
mInputBridge->Destroy();
mInputBridge = nullptr;
}
Send__delete__(this);
}
void

View File

@ -26,8 +26,7 @@ public:
void SetCompositorSession(RemoteCompositorSession* aSession);
void SetInputBridge(APZInputBridgeChild* aInputBridge);
void Destroy() override;
void Destroy();
void
SetKeyboardMap(const KeyboardMap& aKeyboardMap) override;

View File

@ -35,11 +35,6 @@ namespace layers {
* PAPZCTreeManagerParent lives in the compositor thread, while PAPZCTreeManagerChild
* lives in the main thread of the main or the content process. APZCTreeManagerParent
* and APZCTreeManagerChild implement this protocol.
*
* There is one instance of PAPZCTreeManager for each top-level window, plus one
* instance for each tab. The child instances are managed by the RemoteCompositorSession
* and TabChild classes, respectively. The parent instances are held in the
* compositor's sIndirectLayerTrees structure.
*/
protocol PAPZCTreeManager
{

View File

@ -0,0 +1,13 @@
<style>
:not(basefont) {
box-shadow: 0 0 8px -moz-win-mediatext;
transform: scaley(56);
}
.cl {
padding-top: 16vw;
}
</style>
<menu>
<menu class="cl"></menu>
<menu style="-webkit-perspective: 1px">
<menu>

View File

@ -164,5 +164,6 @@ load 1325159-1.html
load 1331683.html
skip-if(Android) pref(dom.disable_open_during_load,false) load 1343666.html
load 1408078-1.html
load 1464243.html
load 1467847-1.html

View File

@ -49,6 +49,7 @@
#elif defined(XP_MACOSX)
#include "gfxPlatformMac.h"
#include "gfxQuartzSurface.h"
#include "nsCocoaFeatures.h"
#elif defined(MOZ_WIDGET_GTK)
#include "gfxPlatformGtk.h"
#elif defined(ANDROID)
@ -2720,6 +2721,13 @@ gfxPlatform::InitOMTPConfig()
NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
}
#ifdef XP_MACOSX
if (!nsCocoaFeatures::OnYosemiteOrLater()) {
omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked before OSX 10.10",
NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_OSX_MAVERICKS"));
}
#endif
if (InSafeMode()) {
omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));

View File

@ -10,9 +10,11 @@
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsString.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/dom/BlobURLProtocolHandler.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/StaticPrefs.h"
#include "nsIDocument.h"
#include "nsPrintfCString.h"
@ -128,26 +130,45 @@ ImageCacheKey::SchemeIs(const char* aScheme)
/* static */ void*
ImageCacheKey::GetSpecialCaseDocumentToken(nsIDocument* aDocument, nsIURI* aURI)
{
if (!aDocument) {
return nullptr;
}
// For controlled documents, we cast the pointer into a void* to avoid
// dereferencing it (since we only use it for comparisons).
void* pointer = nullptr;
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (aDocument && swm) {
ErrorResult rv;
if (aDocument->GetController().isSome()) {
pointer = aDocument;
}
if (swm && aDocument->GetController().isSome()) {
return aDocument;
}
// If this document has been marked as tracker, let's use its address to make
// a unique cache key.
if (!pointer && aDocument &&
nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
nullptr, aURI)) {
pointer = aDocument;
// We want to have a unique image cache if the anti-tracking feature is
// enabled for 3rd party resources.
if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled() ||
!nsContentUtils::IsThirdPartyWindowOrChannel(aDocument->GetInnerWindow(),
nullptr, aURI)) {
return nullptr;
}
return pointer;
// If the window is 3rd party resource, let's see if the first party storage
// access is granted for this image.
if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) {
return nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
nullptr, aURI)
? aDocument : nullptr;
}
// Another scenario is if this image is a 3rd party resource loaded by a
// first party context. In this case, we should check if the nsIChannel has
// been marked as tracking resource, but we don't have the channel yet at
// this point. The best approach here is to be conservative: if we are sure
// that the permission is granted, let's return a nullptr. Otherwise, let's
// make a unique image cache.
if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
aURI)) {
return aDocument;
}
return nullptr;
}
} // namespace image

View File

@ -58,10 +58,12 @@ const LOCALIZABLE_ATTRIBUTES = {
th: ["abbr"]
},
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": {
description: ["value"],
global: [
"accesskey", "aria-label", "aria-valuetext", "aria-moz-hint", "label"
],
key: ["key", "keycode"],
label: ["value"],
textbox: ["placeholder"],
toolbarbutton: ["tooltiptext"],
}

View File

@ -339,6 +339,15 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
sandboxedLoadingPrincipalInfo = sandboxedLoadingPrincipalInfoTemp;
}
OptionalPrincipalInfo topLevelStorageAreaPrincipalInfo = mozilla::void_t();
if (aLoadInfo->TopLevelStorageAreaPrincipal()) {
PrincipalInfo topLevelStorageAreaPrincipalInfoTemp;
rv = PrincipalToPrincipalInfo(aLoadInfo->TopLevelStorageAreaPrincipal(),
&topLevelStorageAreaPrincipalInfoTemp);
NS_ENSURE_SUCCESS(rv, rv);
topLevelStorageAreaPrincipalInfo = topLevelStorageAreaPrincipalInfoTemp;
}
OptionalURIParams optionalResultPrincipalURI = mozilla::void_t();
nsCOMPtr<nsIURI> resultPrincipalURI;
Unused << aLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
@ -399,11 +408,11 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
triggeringPrincipalInfo,
principalToInheritInfo,
sandboxedLoadingPrincipalInfo,
topLevelStorageAreaPrincipalInfo,
optionalResultPrincipalURI,
aLoadInfo->GetSecurityFlags(),
aLoadInfo->InternalContentPolicyType(),
static_cast<uint32_t>(aLoadInfo->GetTainting()),
aLoadInfo->GetFirstPartyStorageAccessGrantedOrigins(),
aLoadInfo->GetUpgradeInsecureRequests(),
aLoadInfo->GetBrowserUpgradeInsecureRequests(),
aLoadInfo->GetBrowserWouldUpgradeInsecureRequests(),
@ -478,6 +487,13 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIPrincipal> topLevelStorageAreaPrincipal;
if (loadInfoArgs.topLevelStorageAreaPrincipalInfo().type() != OptionalPrincipalInfo::Tvoid_t) {
topLevelStorageAreaPrincipal =
PrincipalInfoToPrincipal(loadInfoArgs.topLevelStorageAreaPrincipalInfo(), &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIURI> resultPrincipalURI;
if (loadInfoArgs.resultPrincipalURI().type() != OptionalURIParams::Tvoid_t) {
resultPrincipalURI = DeserializeURI(loadInfoArgs.resultPrincipalURI());
@ -544,6 +560,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
triggeringPrincipal,
principalToInherit,
sandboxedLoadingPrincipal,
topLevelStorageAreaPrincipal,
resultPrincipalURI,
clientInfo,
reservedClientInfo,
@ -552,7 +569,6 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
loadInfoArgs.securityFlags(),
loadInfoArgs.contentPolicyType(),
static_cast<LoadTainting>(loadInfoArgs.tainting()),
loadInfoArgs.firstPartyStorageAccessGrantedOrigins(),
loadInfoArgs.upgradeInsecureRequests(),
loadInfoArgs.browserUpgradeInsecureRequests(),
loadInfoArgs.browserWouldUpgradeInsecureRequests(),

View File

@ -773,20 +773,15 @@ ModuleObject::create(JSContext* cx)
if (!self)
return nullptr;
Zone* zone = cx->zone();
IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>();
if (!bindings) {
ReportOutOfMemory(cx);
IndirectBindingMap* bindings = cx->new_<IndirectBindingMap>();
if (!bindings)
return nullptr;
}
self->initReservedSlot(ImportBindingsSlot, PrivateValue(bindings));
FunctionDeclarationVector* funDecls = zone->new_<FunctionDeclarationVector>(zone);
if (!funDecls) {
ReportOutOfMemory(cx);
FunctionDeclarationVector* funDecls = cx->new_<FunctionDeclarationVector>(cx->zone());
if (!funDecls)
return nullptr;
}
self->initReservedSlot(FunctionDeclarationsSlot, PrivateValue(funDecls));
return self;
@ -1133,12 +1128,9 @@ ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObje
MOZ_ASSERT(!self->namespace_());
MOZ_ASSERT(exports->is<ArrayObject>());
Zone* zone = cx->zone();
auto bindings = zone->make_unique<IndirectBindingMap>();
if (!bindings) {
ReportOutOfMemory(cx);
auto bindings = cx->make_unique<IndirectBindingMap>();
if (!bindings)
return nullptr;
}
auto ns = ModuleNamespaceObject::create(cx, self, exports, std::move(bindings));
if (!ns)

View File

@ -7422,7 +7422,7 @@ CClosure::Create(JSContext* cx,
// Allocate a buffer for the return value.
size_t rvSize = CType::GetSize(fninfo->mReturnType);
errResult = result->zone()->make_pod_array<uint8_t>(rvSize);
errResult = cx->make_pod_array<uint8_t>(rvSize);
if (!errResult)
return nullptr;
@ -7714,12 +7714,9 @@ CData::Create(JSContext* cx,
} else {
// Initialize our own buffer.
size_t size = CType::GetSize(typeObj);
data = dataObj->zone()->pod_malloc<char>(size);
if (!data) {
// Report a catchable allocation error.
JS_ReportAllocationOverflow(cx);
data = cx->pod_malloc<char>(size);
if (!data)
return nullptr;
}
if (!source)
memset(data, 0, size);

View File

@ -111,7 +111,7 @@ GCRuntime::tryNewTenuredObject(JSContext* cx, AllocKind kind, size_t thingSize,
{
HeapSlot* slots = nullptr;
if (nDynamicSlots) {
slots = cx->zone()->pod_malloc<HeapSlot>(nDynamicSlots);
slots = cx->maybe_pod_malloc<HeapSlot>(nDynamicSlots);
if (MOZ_UNLIKELY(!slots)) {
if (allowGC)
ReportOutOfMemory(cx);

View File

@ -115,7 +115,7 @@ static inline T*
AllocateObjectBuffer(JSContext* cx, JSObject* obj, uint32_t count)
{
if (cx->helperThread())
return cx->zone()->pod_malloc<T>(count);
return cx->pod_malloc<T>(count);
size_t nbytes = JS_ROUNDUP(count * sizeof(T), sizeof(Value));
T* buffer = static_cast<T*>(cx->nursery().allocateBuffer(obj, nbytes));
if (!buffer)

View File

@ -65,7 +65,7 @@ JS::WeakMapPtr<K, V>::init(JSContext* cx)
{
MOZ_ASSERT(!initialized());
typename WeakMapDetails::Utils<K, V>::PtrType map =
cx->zone()->new_<typename WeakMapDetails::Utils<K,V>::Type>(cx);
cx->new_<typename WeakMapDetails::Utils<K,V>::Type>(cx);
if (!map || !map->init())
return false;
ptr = map;

Some files were not shown because too many files have changed in this diff Show More