diff --git a/b2g/config/hamachi/config.json b/b2g/config/hamachi/config.json
index 4c1f03751d3..f31cbdc7edb 100644
--- a/b2g/config/hamachi/config.json
+++ b/b2g/config/hamachi/config.json
@@ -14,7 +14,7 @@
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
"{objdir}/dist/b2g-*.tar.gz",
"{workdir}/sources.xml",
- "{workdir}/out/target/product/hamachi/fota-update.mar"
+ "{workdir}/out/target/product/hamachi/*.mar"
],
"env": {
"VARIANT": "user",
diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in
index 88c712ace8a..cf2d50f6fa8 100644
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -388,7 +388,7 @@
#endif
@BINPATH@/components/SiteSpecificUserAgent.js
@BINPATH@/components/SiteSpecificUserAgent.manifest
-@BINPATH@/components/storage-mozStorage.js
+@BINPATH@/components/storage-json.js
@BINPATH@/components/crypto-SDR.js
@BINPATH@/components/jsconsole-clhandler.manifest
@BINPATH@/components/jsconsole-clhandler.js
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 2be3b148d22..4dc978ef075 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1129,6 +1129,18 @@ var gBrowserInit = {
}
}, 10000);
+ // Load the Login Manager data from disk off the main thread, some time
+ // after startup. If the data is required before the timeout, for example
+ // because a restored page contains a password field, it will be loaded on
+ // the main thread, and this initialization request will be ignored.
+ setTimeout(function() {
+ try {
+ Services.logins;
+ } catch (ex) {
+ Cu.reportError(ex);
+ }
+ }, 3000);
+
// The object handling the downloads indicator is also initialized here in the
// delayed startup function, but the actual indicator element is not loaded
// unless there are downloads to be displayed.
diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js
index c68c32e6ec9..9097db9ba85 100644
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -328,6 +328,9 @@ const PanelUI = {
tempPanel.setAttribute("type", "arrow");
tempPanel.setAttribute("id", "customizationui-widget-panel");
tempPanel.setAttribute("class", "cui-widget-panel");
+ if (this._disableAnimations) {
+ tempPanel.setAttribute("animate", "false");
+ }
tempPanel.setAttribute("context", "");
document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
// If the view has a footer, set a convenience class on the panel.
@@ -363,6 +366,19 @@ const PanelUI = {
}
},
+ /**
+ * NB: The enable- and disableSingleSubviewPanelAnimations methods only
+ * affect the hiding/showing animations of single-subview panels (tempPanel
+ * in the showSubView method).
+ */
+ disableSingleSubviewPanelAnimations: function() {
+ this._disableAnimations = true;
+ },
+
+ enableSingleSubviewPanelAnimations: function() {
+ this._disableAnimations = false;
+ },
+
onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer, aWasRemoval) {
if (aContainer != this.contents) {
return;
diff --git a/browser/components/customizableui/test/browser_988072_sidebar_events.js b/browser/components/customizableui/test/browser_988072_sidebar_events.js
index e4fe5510e84..a893bb53b8c 100644
--- a/browser/components/customizableui/test/browser_988072_sidebar_events.js
+++ b/browser/components/customizableui/test/browser_988072_sidebar_events.js
@@ -41,6 +41,16 @@ function createSidebarItem() {
gSidebarMenu.insertBefore(gTestSidebarItem, gSidebarMenu.firstChild);
}
+function addWidget() {
+ CustomizableUI.addWidgetToArea("sidebar-button", "nav-bar");
+ PanelUI.disableSingleSubviewPanelAnimations();
+}
+
+function removeWidget() {
+ CustomizableUI.removeWidgetFromArea("sidebar-button");
+ PanelUI.enableSingleSubviewPanelAnimations();
+}
+
// Filters out the trailing menuseparators from the sidebar list
function getSidebarList() {
let sidebars = [...gSidebarMenu.children];
@@ -76,7 +86,7 @@ let showSidebarPopup = Task.async(function*() {
// Check the sidebar widget shows the default items
add_task(function*() {
- CustomizableUI.addWidgetToArea("sidebar-button", "nav-bar");
+ addWidget();
yield showSidebarPopup();
@@ -89,13 +99,14 @@ add_task(function*() {
document.getElementById("customizationui-widget-panel").hidePopup();
yield subviewHiddenPromise;
- return resetCustomization();
+ removeWidget();
});
function add_sidebar_task(description, setup, teardown) {
add_task(function*() {
info(description);
createSidebarItem();
+ addWidget();
yield setup();
CustomizableUI.addWidgetToArea("sidebar-button", "nav-bar");
@@ -114,7 +125,7 @@ function add_sidebar_task(description, setup, teardown) {
yield teardown();
gTestSidebarItem.remove();
- return resetCustomization();
+ removeWidget();
});
}
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index d935f0a2204..da9fcad6ab8 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -105,13 +105,13 @@ const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
// Seconds of idle before trying to create a bookmarks backup.
-const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 10 * 60;
+const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
// Minimum interval between backups. We try to not create more than one backup
// per interval.
const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
// Maximum interval between backups. If the last backup is older than these
// days we will try to create a new one more aggressively.
-const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 5;
+const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3;
// Factory object
const BrowserGlueServiceFactory = {
diff --git a/browser/devtools/debugger/test/browser_dbg_addon-panels.js b/browser/devtools/debugger/test/browser_dbg_addon-panels.js
index 71f31718866..43dab85bff3 100644
--- a/browser/devtools/debugger/test/browser_dbg_addon-panels.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-panels.js
@@ -27,7 +27,7 @@ function test() {
// Check only valid tabs are shown
let tabs = addonDebugger.frame.contentDocument.getElementById("toolbox-tabs").children;
- let expectedTabs = ["options", "webconsole", "jsdebugger", "scratchpad"];
+ let expectedTabs = ["webconsole", "jsdebugger", "scratchpad"];
is(tabs.length, expectedTabs.length, "displaying only " + expectedTabs.length + " tabs in addon debugger");
Array.forEach(tabs, (tab, i) => {
diff --git a/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js b/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js
index 6bd0a88a644..d30e2e68c0b 100644
--- a/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js
+++ b/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js
@@ -58,7 +58,7 @@ function testSelectTool(aToolbox) {
function testPreferenceAndUIStateIsConsistent() {
let checkNodes = [...panelWin.document.querySelectorAll("#enabled-toolbox-buttons-box > checkbox")];
- let toolboxButtonNodes = [...doc.querySelectorAll("#toolbox-buttons > toolbarbutton")];
+ let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
let toggleableTools = toolbox.toolboxButtons;
for (let tool of toggleableTools) {
@@ -74,7 +74,7 @@ function testPreferenceAndUIStateIsConsistent() {
function testToggleToolboxButtons() {
let checkNodes = [...panelWin.document.querySelectorAll("#enabled-toolbox-buttons-box > checkbox")];
- let toolboxButtonNodes = [...doc.querySelectorAll("#toolbox-buttons > toolbarbutton")];
+ let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
let visibleButtons = toolboxButtonNodes.filter(button=>!button.hasAttribute("hidden"));
let toggleableTools = toolbox.toolboxButtons;
diff --git a/browser/devtools/framework/toolbox.js b/browser/devtools/framework/toolbox.js
index dbfe7239a54..b100081d95e 100644
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -555,7 +555,7 @@ Toolbox.prototype = {
this._pickerButton.className = "command-button command-button-invertable";
this._pickerButton.setAttribute("tooltiptext", toolboxStrings("pickButton.tooltip"));
- let container = this.doc.querySelector("#toolbox-buttons");
+ let container = this.doc.querySelector("#toolbox-picker-container");
container.appendChild(this._pickerButton);
this._togglePicker = this.highlighterUtils.togglePicker.bind(this.highlighterUtils);
@@ -690,21 +690,29 @@ Toolbox.prototype = {
vbox.id = "toolbox-panel-" + id;
}
- // If there is no tab yet, or the ordinal to be added is the largest one.
- if (tabs.childNodes.length == 0 ||
- +tabs.lastChild.getAttribute("ordinal") <= toolDefinition.ordinal) {
- tabs.appendChild(radio);
+ if (id === "options") {
+ // Options panel is special. It doesn't belong in the same container as
+ // the other tabs.
+ let optionTabContainer = this.doc.getElementById("toolbox-option-container");
+ optionTabContainer.appendChild(radio);
deck.appendChild(vbox);
} else {
- // else, iterate over all the tabs to get the correct location.
- Array.some(tabs.childNodes, (node, i) => {
- if (+node.getAttribute("ordinal") > toolDefinition.ordinal) {
- tabs.insertBefore(radio, node);
- deck.insertBefore(vbox, deck.childNodes[i]);
- return true;
- }
- return false;
- });
+ // If there is no tab yet, or the ordinal to be added is the largest one.
+ if (tabs.childNodes.length == 0 ||
+ tabs.lastChild.getAttribute("ordinal") <= toolDefinition.ordinal) {
+ tabs.appendChild(radio);
+ deck.appendChild(vbox);
+ } else {
+ // else, iterate over all the tabs to get the correct location.
+ Array.some(tabs.childNodes, (node, i) => {
+ if (+node.getAttribute("ordinal") > toolDefinition.ordinal) {
+ tabs.insertBefore(radio, node);
+ deck.insertBefore(vbox, deck.childNodes[i]);
+ return true;
+ }
+ return false;
+ });
+ }
}
this._addKeysToWindow();
@@ -805,6 +813,15 @@ Toolbox.prototype = {
let tab = this.doc.getElementById("toolbox-tab-" + id);
tab.setAttribute("selected", "true");
+ // If options is selected, the separator between it and the
+ // command buttons should be hidden.
+ let sep = this.doc.getElementById("toolbox-controls-separator");
+ if (id === "options") {
+ sep.setAttribute("invisible", "true");
+ } else {
+ sep.removeAttribute("invisible");
+ }
+
if (this.currentToolId == id) {
// re-focus tool to get key events again
this.focusTool(id);
@@ -831,20 +848,13 @@ Toolbox.prototype = {
let tabstrip = this.doc.getElementById("toolbox-tabs");
// select the right tab, making 0th index the default tab if right tab not
- // found
- let index = 0;
- let tabs = tabstrip.childNodes;
- for (let i = 0; i < tabs.length; i++) {
- if (tabs[i] === tab) {
- index = i;
- break;
- }
- }
- tabstrip.selectedItem = tab;
+ // found.
+ tabstrip.selectedItem = tab || tabstrip.childNodes[0];
// and select the right iframe
let deck = this.doc.getElementById("toolbox-deck");
- deck.selectedIndex = index;
+ let panel = this.doc.getElementById("toolbox-panel-" + id);
+ deck.selectedPanel = panel;
this.currentToolId = id;
this._refreshConsoleDisplay();
@@ -907,8 +917,10 @@ Toolbox.prototype = {
* Loads the tool next to the currently selected tool.
*/
selectNextTool: function() {
+ let tools = this.doc.querySelectorAll(".devtools-tab");
let selected = this.doc.querySelector(".devtools-tab[selected]");
- let next = selected.nextSibling || selected.parentNode.firstChild;
+ let nextIndex = [...tools].indexOf(selected) + 1;
+ let next = tools[nextIndex] || tools[0];
let tool = next.getAttribute("toolid");
return this.selectTool(tool);
},
@@ -917,9 +929,11 @@ Toolbox.prototype = {
* Loads the tool just left to the currently selected tool.
*/
selectPreviousTool: function() {
+ let tools = this.doc.querySelectorAll(".devtools-tab");
let selected = this.doc.querySelector(".devtools-tab[selected]");
- let previous = selected.previousSibling || selected.parentNode.lastChild;
- let tool = previous.getAttribute("toolid");
+ let prevIndex = [...tools].indexOf(selected) - 1;
+ let prev = tools[prevIndex] || tools[tools.length - 1];
+ let tool = prev.getAttribute("toolid");
return this.selectTool(tool);
},
diff --git a/browser/devtools/framework/toolbox.xul b/browser/devtools/framework/toolbox.xul
index 6507a1410cb..a21c9506d1c 100644
--- a/browser/devtools/framework/toolbox.xul
+++ b/browser/devtools/framework/toolbox.xul
@@ -51,26 +51,17 @@
-#ifdef XP_MACOSX
-
-
-
-
-#endif
-
-
+
+
-#ifndef XP_MACOSX
+
-#endif
diff --git a/browser/devtools/main.js b/browser/devtools/main.js
index 76b55b9a5e3..41b145ae8c8 100644
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -86,7 +86,7 @@ Tools.webConsole = {
key: l10n("cmd.commandkey", webConsoleStrings),
accesskey: l10n("webConsoleCmd.accesskey", webConsoleStrings),
modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
- ordinal: 1,
+ ordinal: 2,
icon: "chrome://browser/skin/devtools/tool-webconsole.svg",
invertIconForLightTheme: true,
url: "chrome://browser/content/devtools/webconsole.xul",
@@ -117,7 +117,7 @@ Tools.inspector = {
id: "inspector",
accesskey: l10n("inspector.accesskey", inspectorStrings),
key: l10n("inspector.commandkey", inspectorStrings),
- ordinal: 2,
+ ordinal: 1,
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
icon: "chrome://browser/skin/devtools/tool-inspector.svg",
invertIconForLightTheme: true,
diff --git a/browser/devtools/styleeditor/styleeditor.xul b/browser/devtools/styleeditor/styleeditor.xul
index 67f3ea067c9..5fea157fd3a 100644
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -159,7 +159,7 @@
&csscoverage.unused;
-
&csscoverage.noMatch;
+
&csscoverage.noMatches;
${page.url}
image {
@@ -302,10 +302,6 @@
}
.devtools-closebutton:hover {
- opacity: 0.8;
-}
-
-.devtools-closebutton:hover:active {
opacity: 1;
}
@@ -457,10 +453,6 @@
* Rules that apply to the global toolbox like command buttons,
* devtools tabs, docking buttons, etc. */
-#toolbox-controls {
- margin: 0 4px;
-}
-
#toolbox-controls > toolbarbutton,
#toolbox-dock-buttons > toolbarbutton {
-moz-appearance: none;
@@ -500,7 +492,7 @@
#toolbox-dock-window,
#toolbox-dock-bottom,
#toolbox-dock-side {
- opacity: 0.6;
+ opacity: 0.8;
}
#toolbox-dock-window:hover,
@@ -510,14 +502,16 @@
}
#toolbox-controls-separator {
- width: 3px;
+ width: 2px;
background-image: linear-gradient(hsla(204,45%,98%,0), hsla(204,45%,98%,.1), hsla(204,45%,98%,0)),
linear-gradient(hsla(206,37%,4%,0), hsla(206,37%,4%,.6), hsla(206,37%,4%,0)),
linear-gradient(hsla(204,45%,98%,0), hsla(204,45%,98%,.1), hsla(204,45%,98%,0));
background-size: 1px 100%;
background-repeat: no-repeat;
background-position: 0, 1px, 2px;
- -moz-margin-start: 8px;
+}
+#toolbox-controls-separator[invisible] {
+ visibility: hidden;
}
/* Command buttons */
@@ -650,7 +644,9 @@
max-width: 127px;
margin: 0;
padding: 0;
- -moz-border-start: 1px solid;
+ border-style: solid;
+ border-width: 0;
+ -moz-border-start-width: 1px;
-moz-box-align: center;
}
@@ -691,18 +687,6 @@
background-color: rgba(44, 187, 15, .2);
}
-.devtools-tab:first-child {
- -moz-border-start-width: 0;
-}
-
-.theme-light .devtools-tab:last-child {
- -moz-border-end: 1px solid #aaa;
-}
-
-.theme-dark .devtools-tab:last-child {
- -moz-border-end: 1px solid #42484f;
-}
-
.devtools-tab > image {
border: none;
-moz-margin-end: 0;
@@ -712,10 +696,6 @@
width: 16px; /* Prevents collapse during theme switching */
}
-#toolbox-tab-options > image {
- margin: 0 8px;
-}
-
.devtools-tab > label {
white-space: nowrap;
}
@@ -729,7 +709,7 @@
opacity: 1;
}
-.theme-dark #toolbox-tabs .devtools-tab[selected] {
+.theme-dark .devtools-tab[selected] {
color: #f5f7fa;
background-color: #1a4666;
box-shadow: 0 2px 0 #d7f1ff inset,
@@ -737,7 +717,7 @@
0 -2px 0 rgba(0,0,0,.2) inset;
}
-.theme-light #toolbox-tabs .devtools-tab[selected] {
+.theme-light .devtools-tab[selected] {
color: #f5f7fa;
background-color: #4c9ed9;
box-shadow: 0 2px 0 #d7f1ff inset,
@@ -745,29 +725,51 @@
0 -2px 0 rgba(0,0,0,.06) inset;
}
-.devtools-tab[selected]:not(:first-child),
-.devtools-tab[highlighted]:not(:first-child) {
+#toolbox-tabs .devtools-tab[selected]:not(:first-child),
+#toolbox-tabs .devtools-tab[highlighted]:not(:first-child) {
border-width: 0;
-moz-padding-start: 1px;
}
-.devtools-tab[selected]:last-child,
-.devtools-tab[highlighted]:last-child {
+#toolbox-tabs .devtools-tab[selected]:last-child,
+#toolbox-tabs .devtools-tab[highlighted]:last-child {
-moz-padding-end: 1px;
}
-.devtools-tab[selected] + .devtools-tab,
-.devtools-tab[highlighted] + .devtools-tab {
+#toolbox-tabs .devtools-tab[selected] + .devtools-tab,
+#toolbox-tabs .devtools-tab[highlighted] + .devtools-tab {
-moz-border-start-width: 0;
-moz-padding-start: 1px;
}
+#toolbox-tabs .devtools-tab:first-child[selected] {
+ -moz-border-start-width: 0;
+}
+
+#toolbox-tabs .devtools-tab:last-child {
+ -moz-border-end-width: 1px;
+}
+
.devtools-tab:not([highlighted]) > .highlighted-icon,
.devtools-tab[selected] > .highlighted-icon,
.devtools-tab:not([selected])[highlighted] > .default-icon {
visibility: collapse;
}
+/* The options tab is special - it doesn't have the same parent
+ as the other tabs (toolbox-option-container vs toolbox-tabs) */
+#toolbox-option-container .devtools-tab:not([selected]) {
+ background-color: transparent;
+}
+#toolbox-option-container .devtools-tab {
+ border-color: transparent;
+ border-width: 0;
+ -moz-padding-start: 1px;
+}
+#toolbox-tab-options > image {
+ margin: 0 8px;
+}
+
/* Invert the colors of certain dark theme images for displaying
* inside of the light theme.
*/
diff --git a/build/valgrind/cross-architecture.sup b/build/valgrind/cross-architecture.sup
index 3b2d99e1561..0ad214b49f6 100644
--- a/build/valgrind/cross-architecture.sup
+++ b/build/valgrind/cross-architecture.sup
@@ -100,3 +100,12 @@
fun:_ZN22nsComponentManagerImpl17ManifestComponentERNS_25ManifestProcessingContextEiPKPc
...
}
+{
+ Bug 1017112
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:PK11_InitPin
+ fun:_ZN11nsPK11Token12InitPasswordEPKDs
+ ...
+}
diff --git a/content/media/AudioStream.cpp b/content/media/AudioStream.cpp
index 9956280adbd..9db5a820582 100644
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -152,7 +152,10 @@ AudioStream::AudioStream()
, mAudioClock(MOZ_THIS_IN_INITIALIZER_LIST())
, mLatencyRequest(HighLatency)
, mReadPoint(0)
- , mLostFrames(0)
+ , mWrittenFramesPast(0)
+ , mLostFramesPast(0)
+ , mWrittenFramesLast(0)
+ , mLostFramesLast(0)
, mDumpFile(nullptr)
, mVolume(1.0)
, mBytesPerFrame(0)
@@ -780,9 +783,28 @@ AudioStream::GetPositionInFramesUnlocked()
// Adjust the reported position by the number of silent frames written
// during stream underruns.
+ // Since frames sent to DataCallback is not consumed by the backend immediately,
+ // it will be an over adjustment if we return |position - mLostFramesPast - mLostFramesLast|.
+ // On the other hand, we need to keep the whole history of frames sent to DataCallback
+ // in order to adjust position correctly which will require more storage.
+ // We choose a simple way to store the history where |mWrittenFramesPast| and
+ // |mLostFramesPast| are the sum of frames from 1th to |N-1|th callbacks, and
+ // |mWrittenFramesLast| and |mLostFramesLast| represent the frames sent in last callback.
+ // When |position| lies in
+ // [mWrittenFramesPast+mLostFramesPast, mWrittenFramesPast+mLostFramesPast+mWrittenFramesLast+mLostFramesLast],
+ // we will be able to adjust position precisely which should be the major case.
+ // If |position| falls in [0, mWrittenFramesPast+mLostFramesPast), there will be an
+ // error in the adjustment. However that is fine as long as we can ensure the
+ // adjusted position is mono-increasing to avoid audio clock going backward.
uint64_t adjustedPosition = 0;
- if (position >= mLostFrames) {
- adjustedPosition = position - mLostFrames;
+ if (position <= mWrittenFramesPast) {
+ adjustedPosition = position;
+ } else if (position <= mWrittenFramesPast + mLostFramesPast) {
+ adjustedPosition = mWrittenFramesPast;
+ } else if (position <= mWrittenFramesPast + mLostFramesPast + mWrittenFramesLast) {
+ adjustedPosition = position - mLostFramesPast;
+ } else {
+ adjustedPosition = mWrittenFramesPast + mWrittenFramesLast;
}
return std::min(adjustedPosition, INT64_MAX);
}
@@ -929,6 +951,9 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
uint32_t servicedFrames = 0;
int64_t insertTime;
+ mWrittenFramesPast += mWrittenFramesLast;
+ mLostFramesPast += mLostFramesLast;
+
// NOTE: wasapi (others?) can call us back *after* stop()/Shutdown() (mState == SHUTDOWN)
// Bug 996162
@@ -992,6 +1017,8 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
}
underrunFrames = aFrames - servicedFrames;
+ mWrittenFramesLast = servicedFrames;
+ mLostFramesLast = underrunFrames;
if (mState != DRAINING) {
uint8_t* rpos = static_cast(aBuffer) + FramesToBytes(aFrames - underrunFrames);
@@ -1000,7 +1027,6 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
("AudioStream %p lost %d frames", this, underrunFrames));
}
- mLostFrames += underrunFrames;
servicedFrames += underrunFrames;
}
diff --git a/content/media/AudioStream.h b/content/media/AudioStream.h
index fa08f21662a..e995c7e370f 100644
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -65,8 +65,6 @@ public:
// Get the current pitch preservation state.
// Called on the audio thread.
bool GetPreservesPitch();
- // Get the number of frames written to the backend.
- int64_t GetWritten();
private:
// This AudioStream holds a strong reference to this AudioClock. This
// pointer is garanteed to always be valid.
@@ -372,9 +370,14 @@ private:
};
nsAutoTArray mInserts;
- // Sum of silent frames written when DataCallback requests more frames
- // than are available in mBuffer.
- uint64_t mLostFrames;
+ // Suppose we have received DataCallback for N times, |mWrittenFramesPast|
+ // and |mLostFramesPast| are the sum of frames written to the backend from
+ // 1st to |N-1|th DataCallbacks.
+ uint64_t mWrittenFramesPast; // non-silent frames
+ uint64_t mLostFramesPast; // silent frames
+ // Frames written to the backend in Nth DataCallback.
+ uint64_t mWrittenFramesLast; // non-silent frames
+ uint64_t mLostFramesLast; // silent frames
// Output file for dumping audio
FILE* mDumpFile;
diff --git a/content/svg/document/src/SVGDocument.cpp b/content/svg/document/src/SVGDocument.cpp
index c5280aef795..bfcb9651cec 100644
--- a/content/svg/document/src/SVGDocument.cpp
+++ b/content/svg/document/src/SVGDocument.cpp
@@ -140,7 +140,11 @@ SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded()
}
}
- EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::NumberControlSheet());
+ nsCSSStyleSheet* sheet = nsLayoutStylesheetCache::NumberControlSheet();
+ if (sheet) {
+ // number-control.css can be behind a pref
+ EnsureOnDemandBuiltInUASheet(sheet);
+ }
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::FormsSheet());
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::HTMLSheet());
EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::UASheet());
diff --git a/gfx/2d/Tools.h b/gfx/2d/Tools.h
index 3034d2122cd..8a12edb1989 100644
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -138,14 +138,21 @@ struct AlignedArray
T *mPtr;
};
+/**
+ * Returns aStride increased, if necessary, so that it divides exactly into
+ * |alignment|.
+ *
+ * Note that currently |alignment| must be a power-of-2. If for some reason we
+ * want to support NPOT alignment we can revert back to this functions old
+ * implementation.
+ */
template
int32_t GetAlignedStride(int32_t aStride)
{
- if (aStride % alignment) {
- return aStride + (alignment - (aStride % alignment));
- }
-
- return aStride;
+ static_assert(alignment > 0 && (alignment & (alignment-1)) == 0,
+ "This implementation currently require power-of-two alignment");
+ const int32_t mask = alignment - 1;
+ return (aStride + mask) & ~mask;
}
}
diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp
index 6eef998b0e4..5ee051e9623 100644
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -106,11 +106,25 @@ ImageHost::Composite(EffectChain& aEffectChain,
gfx::Rect pictureRect(0, 0,
mPictureRect.width,
mPictureRect.height);
- //XXX: We might have multiple texture sources here (e.g. 3 YCbCr textures), and we're
- // only iterating over the tiles of the first one. Are we assuming that the tiling
- // will be identical? Can we ensure that somehow?
BigImageIterator* it = source->AsBigImageIterator();
if (it) {
+
+ // This iteration does not work if we have multiple texture sources here
+ // (e.g. 3 YCbCr textures). There's nothing preventing the different
+ // planes from having different resolutions or tile sizes. For example, a
+ // YCbCr frame could have Cb and Cr planes that are half the resolution of
+ // the Y plane, in such a way that the Y plane overflows the maximum
+ // texture size and the Cb and Cr planes do not. Then the Y plane would be
+ // split into multiple tiles and the Cb and Cr planes would just be one
+ // tile each.
+ // To handle the general case correctly, we'd have to create a grid of
+ // intersected tiles over all planes, and then draw each grid tile using
+ // the corresponding source tiles from all planes, with appropriate
+ // per-plane per-tile texture coords.
+ // DrawQuad currently assumes that all planes use the same texture coords.
+ MOZ_ASSERT(it->GetTileCount() == 1 || !source->GetNextSibling(),
+ "Can't handle multi-plane BigImages");
+
it->BeginBigImageIteration();
do {
nsIntRect tileRect = it->GetTileRect();
diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp
index ffe376801f0..f6b42ca59b4 100644
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -307,11 +307,24 @@ CompositorOGL::Initialize()
mGLContext->fGenBuffers(1, &mQuadVBO);
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+ // 4 quads, with the number of the quad (vertexID) encoded in w.
GLfloat vertices[] = {
- /* First quad vertices */
- 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
- /* Then quad texcoords */
- 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 0.0f, 2.0f,
+ 1.0f, 0.0f, 0.0f, 2.0f,
+ 0.0f, 1.0f, 0.0f, 2.0f,
+ 1.0f, 1.0f, 0.0f, 2.0f,
+ 0.0f, 0.0f, 0.0f, 3.0f,
+ 1.0f, 0.0f, 0.0f, 3.0f,
+ 0.0f, 1.0f, 0.0f, 3.0f,
+ 1.0f, 1.0f, 0.0f, 3.0f,
};
HeapCopyOfStackArray verticesOnHeap(vertices);
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
@@ -528,9 +541,7 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
aTexCoordRect,
layerRects,
textureRects);
- for (int n = 0; n < rects; ++n) {
- BindAndDrawQuad(aProg, layerRects[n], textureRects[n]);
- }
+ BindAndDrawQuads(aProg, rects, layerRects, textureRects);
}
void
@@ -1499,26 +1510,27 @@ CompositorOGL::BindQuadVBO() {
void
CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
- mGLContext->fVertexAttribPointer(aAttribIndex, 2,
- LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
- (GLvoid*) QuadVBOVertexOffset());
+ mGLContext->fVertexAttribPointer(aAttribIndex, 4,
+ LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+ (GLvoid*) 0);
}
void
CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
- mGLContext->fVertexAttribPointer(aAttribIndex, 2,
- LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
- (GLvoid*) QuadVBOTexCoordOffset());
+ mGLContext->fVertexAttribPointer(aAttribIndex, 4,
+ LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+ (GLvoid*) 0);
}
void
-CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
- const Rect& aLayerRect,
- const Rect& aTextureRect)
+CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
+ int aQuads,
+ const Rect* aLayerRects,
+ const Rect* aTextureRects)
{
NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
- aProg->SetLayerRect(aLayerRect);
+ aProg->SetLayerRects(aLayerRects);
GLuint vertAttribIndex = aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
GLuint texCoordAttribIndex = aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
@@ -1530,11 +1542,11 @@ CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
QuadVBOTexCoordsAttrib(texCoordAttribIndex);
mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
- aProg->SetTextureRect(aTextureRect);
+ aProg->SetTextureRects(aTextureRects);
}
mGLContext->fEnableVertexAttribArray(vertAttribIndex);
- mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+ mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4 * aQuads);
}
GLuint
diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h
index a9f59617533..787aaea8a09 100644
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -352,15 +352,22 @@ private:
GLuint aSourceFrameBuffer,
GLuint *aFBO, GLuint *aTexture);
- GLintptr QuadVBOVertexOffset() { return 0; }
- GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
-
void BindQuadVBO();
void QuadVBOVerticesAttrib(GLuint aAttribIndex);
void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
+ void BindAndDrawQuads(ShaderProgramOGL *aProg,
+ int aQuads,
+ const gfx::Rect* aLayerRect,
+ const gfx::Rect* aTextureRect);
void BindAndDrawQuad(ShaderProgramOGL *aProg,
const gfx::Rect& aLayerRect,
- const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f));
+ const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f)) {
+ gfx::Rect layerRects[4];
+ gfx::Rect textureRects[4];
+ layerRects[0] = aLayerRect;
+ textureRects[0] = aTextureRect;
+ BindAndDrawQuads(aProg, 1, layerRects, textureRects);
+ }
void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
const gfx::Rect& aRect,
const gfx::Rect& aTexCoordRect,
diff --git a/gfx/layers/opengl/OGLShaderProgram.cpp b/gfx/layers/opengl/OGLShaderProgram.cpp
index 7570cd395eb..59b1a8ba1dc 100644
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -32,10 +32,10 @@ AddUniforms(ProgramProfileOGL& aProfile)
static const char *sKnownUniformNames[] = {
"uLayerTransform",
"uMaskTransform",
- "uLayerRect",
+ "uLayerRects",
"uMatrixProj",
"uTextureTransform",
- "uTextureRect",
+ "uTextureRects",
"uRenderTargetOffset",
"uLayerOpacity",
"uTexture",
@@ -146,7 +146,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
AddUniforms(result);
vs << "uniform mat4 uMatrixProj;" << endl;
- vs << "uniform vec4 uLayerRect;" << endl;
+ vs << "uniform vec4 uLayerRects[4];" << endl;
vs << "uniform mat4 uLayerTransform;" << endl;
vs << "uniform vec4 uRenderTargetOffset;" << endl;
@@ -154,8 +154,8 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
vs << "uniform mat4 uTextureTransform;" << endl;
- vs << "uniform vec4 uTextureRect;" << endl;
- vs << "attribute vec2 aTexCoord;" << endl;
+ vs << "uniform vec4 uTextureRects[4];" << endl;
+ vs << "attribute vec4 aTexCoord;" << endl;
vs << "varying vec2 vTexCoord;" << endl;
}
@@ -166,7 +166,9 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
}
vs << "void main() {" << endl;
- vs << " vec4 finalPosition = vec4(aVertexCoord.xy * uLayerRect.zw + uLayerRect.xy, 0.0, 1.0);" << endl;
+ vs << " int vertexID = int(aVertexCoord.w);" << endl;
+ vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
+ vs << " vec4 finalPosition = vec4(aVertexCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
vs << " finalPosition = uLayerTransform * finalPosition;" << endl;
vs << " finalPosition.xyz /= finalPosition.w;" << endl;
@@ -184,7 +186,8 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
- vs << " vec2 texCoord = aTexCoord * uTextureRect.zw + uTextureRect.xy;" << endl;
+ vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
+ vs << " vec2 texCoord = aTexCoord.xy * textureRect.zw + textureRect.xy;" << endl;
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
}
diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h
index 216bf4ca812..b09935c1392 100644
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -52,10 +52,10 @@ public:
LayerTransform = 0,
MaskTransform,
- LayerRect,
+ LayerRects,
MatrixProj,
TextureTransform,
- TextureRect,
+ TextureRects,
RenderTargetOffset,
LayerOpacity,
Texture,
@@ -322,9 +322,12 @@ public:
SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
}
- void SetLayerRect(const gfx::Rect& aRect) {
- float vals[4] = { float(aRect.x), float(aRect.y), float(aRect.width), float(aRect.height) };
- SetUniform(KnownUniform::LayerRect, 4, vals);
+ void SetLayerRects(const gfx::Rect* aRects) {
+ float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
+ aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
+ aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
+ aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
+ SetUniform(KnownUniform::LayerRects, 16, vals);
}
void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) {
@@ -336,9 +339,12 @@ public:
SetMatrixUniform(KnownUniform::TextureTransform, aMatrix);
}
- void SetTextureRect(const gfx::Rect& aRect) {
- float vals[4] = { float(aRect.x), float(aRect.y), float(aRect.width), float(aRect.height) };
- SetUniform(KnownUniform::TextureRect, 4, vals);
+ void SetTextureRects(const gfx::Rect* aRects) {
+ float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
+ aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
+ aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
+ aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
+ SetUniform(KnownUniform::TextureRects, 16, vals);
}
void SetRenderOffset(const nsIntPoint& aOffset) {
@@ -471,6 +477,7 @@ protected:
case 2: mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 3: mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); break;
case 4: mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); break;
+ case 16: mGL->fUniform4fv(ku.mLocation, 4, ku.mValue.f16v); break;
default:
NS_NOTREACHED("Bogus aLength param");
}
diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp
index d2620c47690..7f8e938df21 100644
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -251,6 +251,15 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
(mTexImage->GetSize() != size && !aSrcOffset) ||
mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
+ GLint maxTextureSize;
+ mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ if (size.width > maxTextureSize || size.height > maxTextureSize) {
+ NS_WARNING("Texture exceeds maximum texture size, refusing upload");
+ return false;
+ }
+ // Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
+ // because CreateTextureImage might still choose to create a tiled
+ // texture image.
mTexImage = CreateBasicTextureImage(mGL, size,
gfx::ContentForFormat(aSurface->GetFormat()),
WrapMode(mGL, mFlags),
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index 2c602dd20b9..5d61d3c2771 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -123,6 +123,7 @@ gfxFontEntry::gfxFontEntry() :
mHasSpaceFeaturesNonKerning(false),
mSkipDefaultFeatureSpaceCheck(false),
mCheckedForGraphiteTables(false),
+ mCheckedForGraphiteSmallCaps(false),
mHasCmapTable(false),
mGrFaceInitialized(false),
mCheckedForColorGlyph(false),
@@ -156,6 +157,7 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
mHasSpaceFeaturesNonKerning(false),
mSkipDefaultFeatureSpaceCheck(false),
mCheckedForGraphiteTables(false),
+ mCheckedForGraphiteSmallCaps(false),
mHasCmapTable(false),
mGrFaceInitialized(false),
mCheckedForColorGlyph(false),
@@ -879,6 +881,89 @@ gfxFontEntry::CheckForGraphiteTables()
mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
}
+bool
+gfxFontEntry::SupportsOpenTypeSmallCaps(int32_t aScript)
+{
+ if (!mSmallCapsSupport) {
+ mSmallCapsSupport = new nsDataHashtable();
+ }
+
+ bool result;
+ if (mSmallCapsSupport->Get(uint32_t(aScript), &result)) {
+ return result;
+ }
+
+ result = false;
+
+ hb_face_t *face = GetHBFace();
+
+ if (hb_ot_layout_has_substitution(face)) {
+ // Decide what harfbuzz script code will be used for shaping
+ hb_script_t hbScript;
+ if (aScript <= MOZ_SCRIPT_INHERITED) {
+ // For unresolved "common" or "inherited" runs, default to Latin
+ // for now. (Compare gfxHarfBuzzShaper.)
+ hbScript = HB_SCRIPT_LATIN;
+ } else {
+ hbScript = hb_script_t(GetScriptTagForCode(aScript));
+ }
+
+ // Get the OpenType tag(s) that match this script code
+ hb_tag_t scriptTags[4] = {
+ HB_TAG_NONE,
+ HB_TAG_NONE,
+ HB_TAG_NONE,
+ HB_TAG_NONE
+ };
+ hb_ot_tags_from_script(hbScript, &scriptTags[0], &scriptTags[1]);
+
+ // Replace the first remaining NONE with DEFAULT
+ hb_tag_t* scriptTag = &scriptTags[0];
+ while (*scriptTag != HB_TAG_NONE) {
+ ++scriptTag;
+ }
+ *scriptTag = HB_OT_TAG_DEFAULT_SCRIPT;
+
+ // Now check for 'smcp' under the first of those scripts that is present
+ const hb_tag_t kGSUB = HB_TAG('G','S','U','B');
+ const hb_tag_t kSMCP = HB_TAG('s','m','c','p');
+ scriptTag = &scriptTags[0];
+ while (*scriptTag != HB_TAG_NONE) {
+ unsigned int scriptIndex;
+ if (hb_ot_layout_table_find_script(face, kGSUB, *scriptTag,
+ &scriptIndex)) {
+ if (hb_ot_layout_language_find_feature(face, kGSUB,
+ scriptIndex,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ kSMCP, nullptr)) {
+ result = true;
+ }
+ break;
+ }
+ ++scriptTag;
+ }
+ }
+
+ hb_face_destroy(face);
+
+ mSmallCapsSupport->Put(uint32_t(aScript), result);
+
+ return result;
+}
+
+bool
+gfxFontEntry::SupportsGraphiteSmallCaps()
+{
+ if (!mCheckedForGraphiteSmallCaps) {
+ gr_face* face = GetGrFace();
+ mHasGraphiteSmallCaps =
+ gr_face_find_fref(face, TRUETYPE_TAG('s','m','c','p')) != nullptr;
+ ReleaseGrFace(face);
+ mCheckedForGraphiteSmallCaps = true;
+ }
+ return mHasGraphiteSmallCaps;
+}
+
bool
gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
nsTArray& aLayerGlyphs,
@@ -2011,6 +2096,7 @@ gfxFontShaper::MergeFontFeatures(
if (styleRuleFeatures.IsEmpty() &&
aFontFeatures.IsEmpty() &&
!aDisableLigatures &&
+ !aStyle->smallCaps &&
numAlts == 0) {
return false;
}
@@ -2022,6 +2108,10 @@ gfxFontShaper::MergeFontFeatures(
aMergedFeatures.Put(HB_TAG('c','l','i','g'), 0);
}
+ if (aStyle->smallCaps) {
+ aMergedFeatures.Put(HB_TAG('s','m','c','p'), 1);
+ }
+
// add feature values from font
uint32_t i, count;
@@ -2608,6 +2698,16 @@ gfxFont::SpaceMayParticipateInShaping(int32_t aRunScript)
return false;
}
+bool
+gfxFont::SupportsSmallCaps(int32_t aScript)
+{
+ if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
+ return GetFontEntry()->SupportsGraphiteSmallCaps();
+ }
+
+ return GetFontEntry()->SupportsOpenTypeSmallCaps(aScript);
+}
+
bool
gfxFont::HasFeatureSet(uint32_t aFeature, bool& aFeatureOn)
{
@@ -5444,13 +5544,14 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
// create the glyph run for this range
if (matchedFont) {
- if (mStyle.smallCaps) {
- if (!matchedFont->InitSmallCapsRun(aContext, aTextRun,
- aString + runStart,
- aOffset + runStart,
- matchedLength,
- range.matchType,
- aRunScript)) {
+ if (mStyle.smallCaps &&
+ !matchedFont->SupportsSmallCaps(aRunScript)) {
+ if (!matchedFont->InitFakeSmallCapsRun(aContext, aTextRun,
+ aString + runStart,
+ aOffset + runStart,
+ matchedLength,
+ range.matchType,
+ aRunScript)) {
matchedFont = nullptr;
}
} else {
@@ -5549,28 +5650,28 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
}
bool
-gfxFont::InitSmallCapsRun(gfxContext *aContext,
- gfxTextRun *aTextRun,
- const uint8_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- uint8_t aMatchType,
- int32_t aScript)
+gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
+ gfxTextRun *aTextRun,
+ const uint8_t *aText,
+ uint32_t aOffset,
+ uint32_t aLength,
+ uint8_t aMatchType,
+ int32_t aScript)
{
NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast(aText),
aLength);
- return InitSmallCapsRun(aContext, aTextRun, unicodeString.get(),
- aOffset, aLength, aMatchType, aScript);
+ return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(),
+ aOffset, aLength, aMatchType, aScript);
}
bool
-gfxFont::InitSmallCapsRun(gfxContext *aContext,
- gfxTextRun *aTextRun,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- uint8_t aMatchType,
- int32_t aScript)
+gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
+ gfxTextRun *aTextRun,
+ const char16_t *aText,
+ uint32_t aOffset,
+ uint32_t aLength,
+ uint8_t aMatchType,
+ int32_t aScript)
{
bool ok = true;
diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h
index c9fde71965a..b860cd1ff22 100644
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -273,6 +273,9 @@ public:
bool IgnoreGDEF() const { return mIgnoreGDEF; }
bool IgnoreGSUB() const { return mIgnoreGSUB; }
+ bool SupportsOpenTypeSmallCaps(int32_t aScript);
+ bool SupportsGraphiteSmallCaps();
+
virtual bool IsSymbolFont();
virtual bool HasFontTable(uint32_t aTableTag);
@@ -541,6 +544,8 @@ public:
bool mSkipDefaultFeatureSpaceCheck : 1;
bool mHasGraphiteTables : 1;
bool mCheckedForGraphiteTables : 1;
+ bool mHasGraphiteSmallCaps : 1;
+ bool mCheckedForGraphiteSmallCaps : 1;
bool mHasCmapTable : 1;
bool mGrFaceInitialized : 1;
bool mCheckedForColorGlyph : 1;
@@ -562,6 +567,7 @@ public:
nsTArray mFontsUsingSVGGlyphs;
nsAutoPtr mMathTable;
nsTArray mFeatureSettings;
+ nsAutoPtr> mSmallCapsSupport;
uint32_t mLanguageOverride;
// Color Layer font support
@@ -1608,6 +1614,9 @@ public:
return mFontEntry->HasGraphiteTables();
}
+ // whether the font supports "real" small caps or should fake them
+ bool SupportsSmallCaps(int32_t aScript);
+
// Subclasses may choose to look up glyph ids for characters.
// If they do not override this, gfxHarfBuzzShaper will fetch the cmap
// table and use that.
@@ -1808,21 +1817,21 @@ public:
return mFontEntry->GetUVSGlyph(aCh, aVS);
}
- bool InitSmallCapsRun(gfxContext *aContext,
- gfxTextRun *aTextRun,
- const uint8_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- uint8_t aMatchType,
- int32_t aScript);
+ bool InitFakeSmallCapsRun(gfxContext *aContext,
+ gfxTextRun *aTextRun,
+ const uint8_t *aText,
+ uint32_t aOffset,
+ uint32_t aLength,
+ uint8_t aMatchType,
+ int32_t aScript);
- bool InitSmallCapsRun(gfxContext *aContext,
- gfxTextRun *aTextRun,
- const char16_t *aText,
- uint32_t aOffset,
- uint32_t aLength,
- uint8_t aMatchType,
- int32_t aScript);
+ bool InitFakeSmallCapsRun(gfxContext *aContext,
+ gfxTextRun *aTextRun,
+ const char16_t *aText,
+ uint32_t aOffset,
+ uint32_t aLength,
+ uint8_t aMatchType,
+ int32_t aScript);
// call the (virtual) InitTextRun method to do glyph generation/shaping,
// limiting the length of text passed by processing the run in multiple
diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp
index d847f9e65d2..871d2f35e48 100644
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -412,7 +412,7 @@ VectorImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const
}
nsWindowSizes windowSizes(WindowsMallocSizeOf);
- doc->DocAddSizeOfExcludingThis(&windowSizes);
+ doc->DocAddSizeOfIncludingThis(&windowSizes);
return windowSizes.getTotalSize();
}
diff --git a/js/src/jit-test/tests/ion/dce-with-rinstructions.js b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
index 89bb7858e22..ff5cdec030e 100644
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -163,6 +163,35 @@ function radd_object(i) {
return i;
}
+var uceFault_sub_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sub_number'));
+function rsub_number(i) {
+ var x = 1 - i;
+ if (uceFault_sub_number(i) || uceFault_sub_number(i))
+ assertEq(x, -98 /* = 1 - 99 */);
+ return i;
+}
+
+var uceFault_sub_float = eval(uneval(uceFault).replace('uceFault', 'uceFault_sub_float'));
+function rsub_float(i) {
+ var t = Math.fround(1/3);
+ var fi = Math.fround(i);
+ var x = Math.fround(Math.fround(Math.fround(Math.fround(t - fi) - t) - fi) - t);
+ if (uceFault_sub_float(i) || uceFault_sub_float(i))
+ assertEq(x, -198.3333282470703); /* != -198.33333334326744 (when computed with double subtractions) */
+ return i;
+}
+
+var uceFault_sub_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_sub_object'));
+function rsub_object(i) {
+ var t = i;
+ var o = { valueOf: function () { return t; } };
+ var x = o - i; /* computed with t == i, not 1000 */
+ t = 1000;
+ if (uceFault_sub_object(i) || uceFault_sub_object(i))
+ assertEq(x, 0);
+ return i;
+}
+
for (i = 0; i < 100; i++) {
rbitnot_number(i);
rbitnot_object(i);
@@ -180,6 +209,9 @@ for (i = 0; i < 100; i++) {
radd_float(i);
radd_string(i);
radd_object(i);
+ rsub_number(i);
+ rsub_float(i);
+ rsub_object(i);
}
// Test that we can refer multiple time to the same recover instruction, as well
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index fda8f0e4d95..8b4716f8250 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4300,6 +4300,11 @@ class MSub : public MBinaryArithInstruction
void computeRange(TempAllocator &alloc);
bool truncate(TruncateKind kind);
TruncateKind operandTruncateKind(size_t index) const;
+
+ bool writeRecoverData(CompactBufferWriter &writer) const;
+ bool canRecoverOnBailout() const {
+ return specialization_ != MIRType_None;
+ }
};
class MMul : public MBinaryArithInstruction
diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp
index 26455eb3743..48308732dcc 100644
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -330,6 +330,40 @@ RAdd::recover(JSContext *cx, SnapshotIterator &iter) const
return true;
}
+bool
+MSub::writeRecoverData(CompactBufferWriter &writer) const
+{
+ MOZ_ASSERT(canRecoverOnBailout());
+ writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
+ writer.writeByte(specialization_ == MIRType_Float32);
+ return true;
+}
+
+RSub::RSub(CompactBufferReader &reader)
+{
+ isFloatOperation_ = reader.readByte();
+}
+
+bool
+RSub::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+ RootedValue lhs(cx, iter.read());
+ RootedValue rhs(cx, iter.read());
+ RootedValue result(cx);
+
+ MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
+ if (!js::SubValues(cx, &lhs, &rhs, &result))
+ return false;
+
+ // MIRType_Float32 is a specialization embedding the fact that the result is
+ // rounded to a Float32.
+ if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
+ return false;
+
+ iter.storeInstructionResult(result);
+ return true;
+}
+
bool
MNewObject::writeRecoverData(CompactBufferWriter &writer) const
{
diff --git a/js/src/jit/Recover.h b/js/src/jit/Recover.h
index 7bdb45ff70d..a291a952198 100644
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -25,6 +25,7 @@ namespace jit {
_(Rsh) \
_(Ursh) \
_(Add) \
+ _(Sub) \
_(NewObject) \
_(NewDerivedTypedObject)
@@ -181,6 +182,21 @@ class RAdd MOZ_FINAL : public RInstruction
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
+class RSub MOZ_FINAL : public RInstruction
+{
+ private:
+ bool isFloatOperation_;
+
+ public:
+ RINSTRUCTION_HEADER_(Sub)
+
+ virtual uint32_t numOperands() const {
+ return 2;
+ }
+
+ bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
class RNewObject MOZ_FINAL : public RInstruction
{
private:
diff --git a/js/src/tests/browser.js b/js/src/tests/browser.js
index e0e178f5f37..50892829c43 100644
--- a/js/src/tests/browser.js
+++ b/js/src/tests/browser.js
@@ -64,7 +64,7 @@ function DocumentWrite(s)
}
function print() {
- var s = '';
+ var s = 'TEST-INFO | ';
var a;
for (var i = 0; i < arguments.length; i++)
{
diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp
index 00b87024119..a52a970a1ca 100644
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1840,6 +1840,9 @@ AddTransformedBoundsToRegion(const nsIntRegion& aRegion,
nsIntRegion* aDest)
{
nsIntRect bounds = aRegion.GetBounds();
+ if (bounds.IsEmpty()) {
+ return;
+ }
gfxRect transformed =
aTransform.TransformBounds(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
transformed.RoundOut();
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp
index 7023b6abdc7..79ecb44c8cd 100644
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2156,6 +2156,68 @@ FindTileStart(nscoord aDirtyCoord, nscoord aTilePos, nscoord aTileDim)
return NSToCoordRound(multiples*aTileDim + aTilePos);
}
+static gfxFloat
+LinearGradientStopPositionForPoint(const gfxPoint& aGradientStart,
+ const gfxPoint& aGradientEnd,
+ const gfxPoint& aPoint)
+{
+ gfxPoint d = aGradientEnd - aGradientStart;
+ gfxPoint p = aPoint - aGradientStart;
+ /**
+ * Compute a parameter t such that a line perpendicular to the
+ * d vector, passing through aGradientStart + d*t, also
+ * passes through aPoint.
+ *
+ * t is given by
+ * (p.x - d.x*t)*d.x + (p.y - d.y*t)*d.y = 0
+ *
+ * Solving for t we get
+ * numerator = d.x*p.x + d.y*p.y
+ * denominator = d.x^2 + d.y^2
+ * t = numerator/denominator
+ *
+ * In nsCSSRendering::PaintGradient we know the length of d
+ * is not zero.
+ */
+ double numerator = d.x * p.x + d.y * p.y;
+ double denominator = d.x * d.x + d.y * d.y;
+ return numerator / denominator;
+}
+
+static bool
+RectIsBeyondLinearGradientEdge(const gfxRect& aRect,
+ const gfxMatrix& aPatternMatrix,
+ const nsTArray& aStops,
+ const gfxPoint& aGradientStart,
+ const gfxPoint& aGradientEnd,
+ gfxRGBA* aOutEdgeColor)
+{
+ gfxFloat topLeft = LinearGradientStopPositionForPoint(
+ aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.TopLeft()));
+ gfxFloat topRight = LinearGradientStopPositionForPoint(
+ aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.TopRight()));
+ gfxFloat bottomLeft = LinearGradientStopPositionForPoint(
+ aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.BottomLeft()));
+ gfxFloat bottomRight = LinearGradientStopPositionForPoint(
+ aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.BottomRight()));
+
+ const ColorStop& firstStop = aStops[0];
+ if (topLeft < firstStop.mPosition && topRight < firstStop.mPosition &&
+ bottomLeft < firstStop.mPosition && bottomRight < firstStop.mPosition) {
+ *aOutEdgeColor = firstStop.mColor;
+ return true;
+ }
+
+ const ColorStop& lastStop = aStops.LastElement();
+ if (topLeft >= lastStop.mPosition && topRight >= lastStop.mPosition &&
+ bottomLeft >= lastStop.mPosition && bottomRight >= lastStop.mPosition) {
+ *aOutEdgeColor = lastStop.mColor;
+ return true;
+ }
+
+ return false;
+}
+
void
nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
@@ -2362,11 +2424,13 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
nsRefPtr gradientPattern;
bool forceRepeatToCoverTiles = false;
gfxMatrix matrix;
+ gfxPoint gradientStart;
+ gfxPoint gradientEnd;
if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
// Compute the actual gradient line ends we need to pass to cairo after
// stops have been normalized.
- gfxPoint gradientStart = lineStart + (lineEnd - lineStart)*stopOrigin;
- gfxPoint gradientEnd = lineStart + (lineEnd - lineStart)*stopEnd;
+ gradientStart = lineStart + (lineEnd - lineStart)*stopOrigin;
+ gradientEnd = lineStart + (lineEnd - lineStart)*stopEnd;
gfxPoint gradientStopStart = lineStart + (lineEnd - lineStart)*firstStop;
gfxPoint gradientStopEnd = lineStart + (lineEnd - lineStart)*lastStop;
@@ -2488,6 +2552,9 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
gfxRect areaToFill =
nsLayoutUtils::RectToGfxRect(aFillArea, appUnitsPerDevPixel);
+ gfxRect dirtyAreaToFill = nsLayoutUtils::RectToGfxRect(dirty, appUnitsPerDevPixel);
+ dirtyAreaToFill.RoundOut();
+
gfxMatrix ctm = ctx->CurrentMatrix();
bool isCTMPreservingAxisAlignedRectangles = ctm.PreservesAxisAlignedRectangles();
@@ -2535,8 +2602,18 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
}
ctx->NewPath();
ctx->Rectangle(fillRect);
- ctx->Translate(tileRect.TopLeft());
- ctx->SetPattern(gradientPattern);
+
+ gfxRect dirtyFillRect = fillRect.Intersect(dirtyAreaToFill);
+ gfxRect fillRectRelativeToTile = dirtyFillRect - tileRect.TopLeft();
+ gfxRGBA edgeColor;
+ if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR && !isRepeat &&
+ RectIsBeyondLinearGradientEdge(fillRectRelativeToTile, matrix, stops,
+ gradientStart, gradientEnd, &edgeColor)) {
+ ctx->SetColor(edgeColor);
+ } else {
+ ctx->Translate(tileRect.TopLeft());
+ ctx->SetPattern(gradientPattern);
+ }
ctx->Fill();
ctx->SetMatrix(ctm);
}
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index bbc3233abc9..70a5e3edd2d 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1623,12 +1623,10 @@ GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
if (!parent)
break;
nsIAtom* parentType = parent->GetType();
-#ifdef ANDROID
// Treat the slider thumb as being as an active scrolled root
- // on mobile so that it can move without repainting.
+ // so that it can move without repainting.
if (parentType == nsGkAtoms::sliderFrame)
break;
-#endif
// Sticky frames are active if their nearest scrollable frame
// is also active, just keep a record of sticky frames that we
// encounter for now.
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index 067f7a7da78..0354471e170 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2183,7 +2183,7 @@ void
ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists,
- bool& aCreateLayer,
+ bool aCreateLayer,
bool aPositioned)
{
nsITheme* theme = mOuter->PresContext()->GetTheme();
@@ -2438,9 +2438,9 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
}
- // We put scrollbars in their own layers when this is the root scroll
- // frame and we are a toplevel content document. In this situation, the
- // scrollbar(s) would normally be assigned their own layer anyway, since
+ // We put non-overlay scrollbars in their own layers when this is the root
+ // scroll frame and we are a toplevel content document. In this situation,
+ // the scrollbar(s) would normally be assigned their own layer anyway, since
// they're not scrolled with the rest of the document. But when both
// scrollbars are visible, the layer's visible rectangle would be the size
// of the viewport, so most layer implementations would create a layer buffer
@@ -2475,16 +2475,9 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
aDirtyRect, aLists);
-#ifdef MOZ_WIDGET_GONK
- // TODO: only layerize the overlay scrollbars if this scrollframe can be
- // panned asynchronously. For now just always layerize on B2G because.
- // that's where we want the layerized scrollbars
- createLayersForScrollbars = true;
-#endif
if (addScrollBars) {
// Add overlay scrollbars.
- AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
- true);
+ AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, true, true);
}
return;
@@ -2685,14 +2678,9 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
scrolledContent.BorderBackground()->AppendNewToBottom(layerItem);
}
// Now display overlay scrollbars and the resizer, if we have one.
-#ifdef MOZ_WIDGET_GONK
- // TODO: only layerize the overlay scrollbars if this scrollframe can be
- // panned asynchronously. For now just always layerize on B2G because.
- // that's where we want the layerized scrollbars
- createLayersForScrollbars = true;
-#endif
- AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent,
- createLayersForScrollbars, true);
+ // Always create layers for these, so that we don't create a giant layer
+ // covering the whole scrollport if both scrollbars are visible.
+ AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent, true, true);
scrolledContent.MoveTo(aLists);
}
diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h
index 63d8c33e8a8..85b032535d3 100644
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -68,7 +68,7 @@ public:
void AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists,
- bool& aCreateLayer,
+ bool aCreateLayer,
bool aPositioned);
bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in
index d6754ce9e92..5274bb59641 100644
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -592,12 +592,14 @@ hb_ot_layout_collect_lookups
hb_ot_layout_feature_get_lookups
hb_ot_layout_has_positioning
hb_ot_layout_has_substitution
+hb_ot_layout_language_find_feature
hb_ot_layout_language_get_feature_indexes
hb_ot_layout_language_get_feature_tags
hb_ot_layout_language_get_required_feature_index
hb_ot_layout_lookup_collect_glyphs
hb_ot_layout_script_get_language_tags
hb_ot_layout_table_choose_script
+hb_ot_layout_table_find_script
hb_ot_layout_table_get_script_tags
hb_ot_tag_to_language
hb_ot_tag_to_script
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index 3c08f3e926e..c9fc9b1868b 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -845,7 +845,7 @@ skip-if(B2G&&browserIsRemote) == 401946-1.xul about:blank # bug 974780
== 402567-1.html 402567-1-ref.html
== 402567-2.html 402567-2-ref.html
== 402567-3.html 402567-3-ref.html
-skip-if(B2G) == 402567-4.html 402567-4-ref.html
+skip-if(B2G) fuzzy-if(gtk2Widget,2,40) == 402567-4.html 402567-4-ref.html
random-if(B2G&&browserIsRemote) == 402629-1.html 402629-1-ref.html
random-if(B2G&&browserIsRemote) == 402629-2.html 402629-2-ref.html
random-if(B2G&&browserIsRemote) == 402629-3.html 402629-3-ref.html
diff --git a/layout/reftests/canvas/text-small-caps-1-ref.html b/layout/reftests/canvas/text-small-caps-1-ref.html
index 4464352739c..0d5b0793ed4 100644
--- a/layout/reftests/canvas/text-small-caps-1-ref.html
+++ b/layout/reftests/canvas/text-small-caps-1-ref.html
@@ -9,11 +9,11 @@
+SMALL CAPS
+
diff --git a/layout/reftests/canvas/text-small-caps-1.html b/layout/reftests/canvas/text-small-caps-1.html
index 12a343c4bf4..9312a4e8671 100644
--- a/layout/reftests/canvas/text-small-caps-1.html
+++ b/layout/reftests/canvas/text-small-caps-1.html
@@ -9,11 +9,11 @@
diff --git a/layout/reftests/fonts/sil/Charis-license.txt b/layout/reftests/fonts/sil/Charis-license.txt
new file mode 100755
index 00000000000..b3a335dc785
--- /dev/null
+++ b/layout/reftests/fonts/sil/Charis-license.txt
@@ -0,0 +1,94 @@
+This Font Software is Copyright (c) 1997-2013, SIL International (http://scripts.sil.org/)
+with Reserved Font Names "Charis" and "SIL".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/layout/reftests/fonts/sil/CharisSIL-R.ttf b/layout/reftests/fonts/sil/CharisSIL-R.ttf
new file mode 100755
index 00000000000..f0abfe0cfcb
Binary files /dev/null and b/layout/reftests/fonts/sil/CharisSIL-R.ttf differ
diff --git a/layout/reftests/forms/textarea/reftest.list b/layout/reftests/forms/textarea/reftest.list
index b17c77a4cea..901b12917db 100644
--- a/layout/reftests/forms/textarea/reftest.list
+++ b/layout/reftests/forms/textarea/reftest.list
@@ -1,6 +1,6 @@
skip-if(B2G) fails-if(Android) == resize.html resize-ref.html
# an offset seems to apply to the native resizer on windows so skip this test for now
-skip-if(B2G) fails-if(Android) skip-if(winWidget) == resize-background.html resize-background-ref.html
+skip-if(B2G) fails-if(Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) == resize-background.html resize-background-ref.html
skip-if(B2G) fails-if(Android) != ltr.html rtl.html
skip-if(B2G) fails-if(Android) != ltr-scrollbar.html rtl-scrollbar.html
skip-if(B2G) fails-if(Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html
diff --git a/layout/reftests/image-element/reftest.list b/layout/reftests/image-element/reftest.list
index 79d2d20a619..9844f073394 100644
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -17,7 +17,7 @@ random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref
== element-paint-background-size-02.html element-paint-background-size-02-ref.html
== element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
-== element-paint-native-widget.html element-paint-native-widget-ref.html
+fuzzy-if(gtk2Widget,1,32) fuzzy-if(cocoaWidget,1,106) == element-paint-native-widget.html element-paint-native-widget-ref.html
== element-paint-subimage-sampling-restriction.html about:blank
== element-paint-clippath.html element-paint-clippath-ref.html
== element-paint-sharpness-01a.html element-paint-sharpness-01b.html
diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list
index be045ad4cda..f11127bff99 100644
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -3,8 +3,8 @@ skip-if(B2G) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html
skip-if(B2G) HTTP(..) == marker-string.html marker-string-ref.html
skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
-skip-if(!gtk2Widget) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
-skip-if(B2G) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
+skip-if(!gtk2Widget) fuzzy-if(gtk2Widget,1,104) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
+skip-if(B2G) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
fuzzy-if(OSX==10.8,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html
skip-if(B2G) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
diff --git a/layout/reftests/text-transform/fake-small-caps-1-ref.html b/layout/reftests/text-transform/fake-small-caps-1-ref.html
new file mode 100644
index 00000000000..3b14167ad2f
--- /dev/null
+++ b/layout/reftests/text-transform/fake-small-caps-1-ref.html
@@ -0,0 +1,22 @@
+
+
+