зеркало из https://github.com/mozilla/gecko-dev.git
Merge backout.
This commit is contained in:
Коммит
19f5997758
|
@ -269,20 +269,27 @@ NS_IMETHODIMP nsXULTreeAccessible::GetFirstChild(nsIAccessible **aFirstChild)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsXULTreeAccessible::GetLastChild(nsIAccessible **aLastChild)
|
NS_IMETHODIMP
|
||||||
|
nsXULTreeAccessible::GetLastChild(nsIAccessible **aLastChild)
|
||||||
{
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aLastChild);
|
||||||
|
*aLastChild = nsnull;
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
PRInt32 rowCount;
|
PRInt32 rowCount = 0;
|
||||||
mTreeView->GetRowCount(&rowCount);
|
mTreeView->GetRowCount(&rowCount);
|
||||||
if (rowCount > 0) {
|
if (rowCount > 0) {
|
||||||
nsCOMPtr<nsITreeColumn> column = GetLastVisibleColumn(mTree);
|
nsCOMPtr<nsITreeColumn> column = GetLastVisibleColumn(mTree);
|
||||||
return GetCachedTreeitemAccessible(rowCount - 1, column, aLastChild);
|
nsresult rv = GetCachedTreeitemAccessible(rowCount - 1, column, aLastChild);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
else // if there is not any rows, use treecols as tree's last child
|
|
||||||
nsAccessible::GetLastChild(aLastChild);
|
|
||||||
|
|
||||||
return NS_OK;
|
if (*aLastChild)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// If there is not any rows, use treecols as tree's last child.
|
||||||
|
return nsAccessible::GetLastChild(aLastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
// tree's children count is row count + treecols count
|
// tree's children count is row count + treecols count
|
||||||
|
|
|
@ -65,7 +65,7 @@ var StarUI = {
|
||||||
// to avoid impacting startup / new window performance
|
// to avoid impacting startup / new window performance
|
||||||
element.hidden = false;
|
element.hidden = false;
|
||||||
element.addEventListener("popuphidden", this, false);
|
element.addEventListener("popuphidden", this, false);
|
||||||
element.addEventListener("keypress", this, true);
|
element.addEventListener("keypress", this, false);
|
||||||
return this.panel = element;
|
return this.panel = element;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -112,25 +112,25 @@ var StarUI = {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "keypress":
|
case "keypress":
|
||||||
if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
|
if (aEvent.getPreventDefault()) {
|
||||||
// If the panel is visible the ESC key is mapped to the cancel button
|
// The event has already been consumed inside of the panel.
|
||||||
// unless we are editing a folder in the folderTree, or an
|
break;
|
||||||
// autocomplete popup is open.
|
|
||||||
if (!this._element("editBookmarkPanelContent").hidden) {
|
|
||||||
var elt = aEvent.target;
|
|
||||||
if ((elt.localName != "tree" || !elt.hasAttribute("editing")) &&
|
|
||||||
!elt.popupOpen)
|
|
||||||
this.cancelButtonOnCommand();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
|
switch (aEvent.keyCode) {
|
||||||
// hide the panel unless the folder tree or an expander are focused
|
case KeyEvent.DOM_VK_ESCAPE:
|
||||||
// or an autocomplete popup is open.
|
if (!this._element("editBookmarkPanelContent").hidden)
|
||||||
if (aEvent.target.localName != "tree" &&
|
this.cancelButtonOnCommand();
|
||||||
aEvent.target.className != "expander-up" &&
|
break;
|
||||||
aEvent.target.className != "expander-down" &&
|
case KeyEvent.DOM_VK_RETURN:
|
||||||
!aEvent.target.popupOpen)
|
if (aEvent.target.className == "expander-up" ||
|
||||||
|
aEvent.target.className == "expander-down" ||
|
||||||
|
aEvent.target.id == "editBMPanel_newFolderButton") {
|
||||||
|
//XXX Why is this necessary? The getPreventDefault() check should
|
||||||
|
// be enough.
|
||||||
|
break;
|
||||||
|
}
|
||||||
this.panel.hidePopup();
|
this.panel.hidePopup();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,8 @@
|
||||||
value="&clearTimeDuration.suffix;"/>
|
value="&clearTimeDuration.suffix;"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
|
<separator class="thin"/>
|
||||||
|
|
||||||
#ifdef CRH_DIALOG_TREE_VIEW
|
#ifdef CRH_DIALOG_TREE_VIEW
|
||||||
<deck id="durationDeck">
|
<deck id="durationDeck">
|
||||||
<tree id="placesTree" flex="1" hidecolumnpicker="true" rows="10"
|
<tree id="placesTree" flex="1" hidecolumnpicker="true" rows="10"
|
||||||
|
@ -149,7 +151,7 @@
|
||||||
<spacer flex="1"/>
|
<spacer flex="1"/>
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<image id="sanitizeEverythingWarningIcon"/>
|
<image id="sanitizeEverythingWarningIcon"/>
|
||||||
<vbox id="sanitizeEverythingWarningDescBox">
|
<vbox id="sanitizeEverythingWarningDescBox" flex="1">
|
||||||
<description id="sanitizeEverythingWarning"/>
|
<description id="sanitizeEverythingWarning"/>
|
||||||
<description id="sanitizeEverythingUndoWarning">&sanitizeEverythingUndoWarning;</description>
|
<description id="sanitizeEverythingUndoWarning">&sanitizeEverythingUndoWarning;</description>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
- Michael Ventnor <ventnor.bugzilla@yahoo.com.au>
|
- Michael Ventnor <ventnor.bugzilla@yahoo.com.au>
|
||||||
- Mark Pilgrim <pilgrim@gmail.com>
|
- Mark Pilgrim <pilgrim@gmail.com>
|
||||||
- Dão Gottwald <dao@mozilla.com>
|
- Dão Gottwald <dao@mozilla.com>
|
||||||
|
- Paul O’Shannessy <paul@oshannessy.com>
|
||||||
-
|
-
|
||||||
- Alternatively, the contents of this file may be used under the terms of
|
- Alternatively, the contents of this file may be used under the terms of
|
||||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -1487,7 +1488,7 @@
|
||||||
<parameter name="aTab"/>
|
<parameter name="aTab"/>
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
this._endRemoveTab(this._beginRemoveTab(aTab, true, null, true));
|
this._endRemoveTab(this._beginRemoveTab(aTab, false, null, true));
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -1501,7 +1502,7 @@
|
||||||
<!-- Returns everything that _endRemoveTab needs in an array. -->
|
<!-- Returns everything that _endRemoveTab needs in an array. -->
|
||||||
<method name="_beginRemoveTab">
|
<method name="_beginRemoveTab">
|
||||||
<parameter name="aTab"/>
|
<parameter name="aTab"/>
|
||||||
<parameter name="aFireBeforeUnload"/>
|
<parameter name="aTabWillBeMoved"/>
|
||||||
<parameter name="aCloseWindowWithLastTab"/>
|
<parameter name="aCloseWindowWithLastTab"/>
|
||||||
<parameter name="aCloseWindowFastpath"/>
|
<parameter name="aCloseWindowFastpath"/>
|
||||||
<body>
|
<body>
|
||||||
|
@ -1511,7 +1512,7 @@
|
||||||
|
|
||||||
var browser = this.getBrowserForTab(aTab);
|
var browser = this.getBrowserForTab(aTab);
|
||||||
|
|
||||||
if (aFireBeforeUnload) {
|
if (!aTabWillBeMoved) {
|
||||||
let ds = browser.docShell;
|
let ds = browser.docShell;
|
||||||
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
if (ds.contentViewer && !ds.contentViewer.permitUnload())
|
||||||
return null;
|
return null;
|
||||||
|
@ -1550,8 +1551,8 @@
|
||||||
// Dispatch a notification.
|
// Dispatch a notification.
|
||||||
// We dispatch it before any teardown so that event listeners can
|
// We dispatch it before any teardown so that event listeners can
|
||||||
// inspect the tab that's about to close.
|
// inspect the tab that's about to close.
|
||||||
var evt = document.createEvent("Events");
|
var evt = document.createEvent("UIEvent");
|
||||||
evt.initEvent("TabClose", true, false);
|
evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0);
|
||||||
aTab.dispatchEvent(evt);
|
aTab.dispatchEvent(evt);
|
||||||
|
|
||||||
// Remove the tab's filter and progress listener.
|
// Remove the tab's filter and progress listener.
|
||||||
|
@ -1716,7 +1717,7 @@
|
||||||
// First, start teardown of the other browser. Make sure to not
|
// First, start teardown of the other browser. Make sure to not
|
||||||
// fire the beforeunload event in the process. Close the other
|
// fire the beforeunload event in the process. Close the other
|
||||||
// window if this was its last tab.
|
// window if this was its last tab.
|
||||||
var endRemoveArgs = remoteBrowser._beginRemoveTab(aOtherTab, false, true);
|
var endRemoveArgs = remoteBrowser._beginRemoveTab(aOtherTab, true, true);
|
||||||
|
|
||||||
// Unhook our progress listener
|
// Unhook our progress listener
|
||||||
var ourIndex = aOurTab._tPos;
|
var ourIndex = aOurTab._tPos;
|
||||||
|
@ -2280,7 +2281,7 @@
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if (this.mTabs.length == 1)
|
if (this.mTabs.length == 1)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
// tell a new window to take the "dropped" tab
|
// tell a new window to take the "dropped" tab
|
||||||
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||||
|
|
|
@ -115,6 +115,7 @@ _BROWSER_FILES = browser_sanitize-timespans.js \
|
||||||
browser_overflowScroll.js \
|
browser_overflowScroll.js \
|
||||||
browser_sanitizeDialog.js \
|
browser_sanitizeDialog.js \
|
||||||
browser_tabs_owner.js \
|
browser_tabs_owner.js \
|
||||||
|
browser_bug491431.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is bug 491431 test.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Corporation
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Paul O’Shannessy <paul@oshannessy.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
let testPage = "data:text/plain,test bug 491431 Page";
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
let newWin, tabA, tabB;
|
||||||
|
|
||||||
|
// test normal close
|
||||||
|
tabA = gBrowser.addTab(testPage);
|
||||||
|
gBrowser.addEventListener("TabClose", function(aEvent) {
|
||||||
|
gBrowser.removeEventListener("TabClose", arguments.callee, true);
|
||||||
|
ok(!aEvent.detail, "This was a normal tab close");
|
||||||
|
|
||||||
|
// test tab close by moving
|
||||||
|
tabB = gBrowser.addTab(testPage);
|
||||||
|
gBrowser.addEventListener("TabClose", function(aEvent) {
|
||||||
|
gBrowser.removeEventListener("TabClose", arguments.callee, true);
|
||||||
|
executeSoon(function() {
|
||||||
|
ok(aEvent.detail, "This was a tab closed by moving");
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
newWin.close();
|
||||||
|
executeSoon(finish);
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
newWin = gBrowser.replaceTabWithWindow(tabB);
|
||||||
|
}, true);
|
||||||
|
gBrowser.removeTab(tabA);
|
||||||
|
}
|
||||||
|
|
|
@ -374,10 +374,6 @@ var BookmarkPropertiesPanel = {
|
||||||
this._element("siteLocationField")
|
this._element("siteLocationField")
|
||||||
.addEventListener("input", this, false);
|
.addEventListener("input", this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set on document to get the event before an autocomplete popup could
|
|
||||||
// be hidden on Enter.
|
|
||||||
document.addEventListener("keypress", this, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.sizeToContent();
|
window.sizeToContent();
|
||||||
|
@ -388,27 +384,6 @@ var BookmarkPropertiesPanel = {
|
||||||
handleEvent: function BPP_handleEvent(aEvent) {
|
handleEvent: function BPP_handleEvent(aEvent) {
|
||||||
var target = aEvent.target;
|
var target = aEvent.target;
|
||||||
switch (aEvent.type) {
|
switch (aEvent.type) {
|
||||||
case "keypress":
|
|
||||||
function canAcceptDialog(aElement) {
|
|
||||||
// on Enter we accept the dialog unless:
|
|
||||||
// - the folder tree is focused
|
|
||||||
// - an expander is focused
|
|
||||||
// - an autocomplete (eg. tags) popup is open
|
|
||||||
// - a menulist is open
|
|
||||||
// - a multiline textbox is focused
|
|
||||||
return aElement.localName != "tree" &&
|
|
||||||
aElement.className != "expander-up" &&
|
|
||||||
aElement.className != "expander-down" &&
|
|
||||||
!aElement.popupOpen &&
|
|
||||||
!aElement.open &&
|
|
||||||
!(aElement.localName == "textbox" &&
|
|
||||||
aElement.getAttribute("multiline") == "true");
|
|
||||||
}
|
|
||||||
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN &&
|
|
||||||
canAcceptDialog(target))
|
|
||||||
document.documentElement.acceptDialog();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "input":
|
case "input":
|
||||||
if (target.id == "editBMPanel_locationField" ||
|
if (target.id == "editBMPanel_locationField" ||
|
||||||
target.id == "editBMPanel_feedLocationField" ||
|
target.id == "editBMPanel_feedLocationField" ||
|
||||||
|
@ -506,7 +481,6 @@ var BookmarkPropertiesPanel = {
|
||||||
// currently registered EventListener on the EventTarget has no effect.
|
// currently registered EventListener on the EventTarget has no effect.
|
||||||
this._element("tagsSelectorRow")
|
this._element("tagsSelectorRow")
|
||||||
.removeEventListener("DOMAttrModified", this, false);
|
.removeEventListener("DOMAttrModified", this, false);
|
||||||
document.removeEventListener("keypress", this, true);
|
|
||||||
this._element("folderTreeRow")
|
this._element("folderTreeRow")
|
||||||
.removeEventListener("DOMAttrModified", this, false);
|
.removeEventListener("DOMAttrModified", this, false);
|
||||||
this._element("locationField")
|
this._element("locationField")
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
|
|
||||||
<dialog id="bookmarkproperties"
|
<dialog id="bookmarkproperties"
|
||||||
buttons="accept, cancel"
|
buttons="accept, cancel"
|
||||||
defaultButton="none"
|
|
||||||
ondialogaccept="BookmarkPropertiesPanel.onDialogAccept();"
|
ondialogaccept="BookmarkPropertiesPanel.onDialogAccept();"
|
||||||
ondialogcancel="BookmarkPropertiesPanel.onDialogCancel();"
|
ondialogcancel="BookmarkPropertiesPanel.onDialogCancel();"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
|
|
@ -58,5 +58,5 @@ that require it. -->
|
||||||
mockup at bug 480169 -->
|
mockup at bug 480169 -->
|
||||||
<!ENTITY sanitizeEverythingUndoWarning "This action cannot be undone.">
|
<!ENTITY sanitizeEverythingUndoWarning "This action cannot be undone.">
|
||||||
|
|
||||||
<!ENTITY dialog.width "32em">
|
<!ENTITY dialog.width "28em">
|
||||||
<!ENTITY column.width "14em">
|
<!ENTITY column.width "14em">
|
||||||
|
|
|
@ -157,18 +157,6 @@ radio[pane=paneAdvanced] {
|
||||||
/**
|
/**
|
||||||
* Clear Private Data
|
* Clear Private Data
|
||||||
*/
|
*/
|
||||||
#SanitizeDurationBox {
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationChoice {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationLabel {
|
|
||||||
-moz-margin-start: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#SanitizeDialogPane > groupbox {
|
#SanitizeDialogPane > groupbox {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
#sanitizeDurationChoice {
|
||||||
|
-moz-margin-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the duration label with the warning box and item list */
|
||||||
|
#sanitizeDurationLabel {
|
||||||
|
-moz-margin-start: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||||
takes up a little space, causing the end of the dropdown to not be aligned
|
takes up a little space, causing the end of the dropdown to not be aligned
|
||||||
with the warning box. */
|
with the warning box. */
|
||||||
|
@ -32,9 +42,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#sanitizeEverythingWarningDescBox {
|
#sanitizeEverythingWarningDescBox {
|
||||||
padding: 0;
|
padding: 0 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,8 +52,8 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
margin-left: -6px;
|
-moz-margin-start: -6px;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expander-up,
|
.expander-up,
|
||||||
|
@ -73,16 +82,15 @@
|
||||||
|
|
||||||
/* Make the item list the same width as the warning box */
|
/* Make the item list the same width as the warning box */
|
||||||
#itemList {
|
#itemList {
|
||||||
margin-left: 0;
|
-moz-margin-start: 0;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Make the rightmost dialog button ("accept") align wih right side of the
|
/* Align the last dialog button with the end of the warning box */
|
||||||
warning box */
|
|
||||||
.prefWindow-dlgbuttons {
|
.prefWindow-dlgbuttons {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
.dialog-button[dlgtype="accept"] {
|
.dialog-button[dlgtype="accept"] {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,18 +276,6 @@ caption {
|
||||||
/**
|
/**
|
||||||
* Clear Private Data
|
* Clear Private Data
|
||||||
*/
|
*/
|
||||||
#SanitizeDurationBox {
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationChoice {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationLabel {
|
|
||||||
-moz-margin-start: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#SanitizeDialogPane > groupbox {
|
#SanitizeDialogPane > groupbox {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
/* Align the duration label with the warning box and item list */
|
||||||
|
#sanitizeDurationLabel {
|
||||||
|
-moz-margin-start: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||||
takes up a little space, causing the end of the dropdown to not be aligned
|
takes up a little space, causing the end of the dropdown to not be aligned
|
||||||
with the warning box. */
|
with the warning box. */
|
||||||
|
@ -32,9 +38,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#sanitizeEverythingWarningDescBox {
|
#sanitizeEverythingWarningDescBox {
|
||||||
padding: 0;
|
padding: 0 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,8 +48,8 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
margin-left: -2px;
|
-moz-margin-start: -2px;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expander-up,
|
.expander-up,
|
||||||
|
@ -74,16 +79,15 @@
|
||||||
|
|
||||||
/* Make the item list the same width as the warning box */
|
/* Make the item list the same width as the warning box */
|
||||||
#itemList {
|
#itemList {
|
||||||
margin-left: 0;
|
-moz-margin-start: 0;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Make the rightmost dialog button ("accept") align wih right side of the
|
/* Align the last dialog button with the end of the warning box */
|
||||||
warning box */
|
|
||||||
.prefWindow-dlgbuttons {
|
.prefWindow-dlgbuttons {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
.dialog-button[dlgtype="accept"] {
|
.dialog-button[dlgtype="accept"] {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,18 +177,6 @@ radio[pane=paneAdvanced][selected="true"] {
|
||||||
/**
|
/**
|
||||||
* Clear Private Data
|
* Clear Private Data
|
||||||
*/
|
*/
|
||||||
#SanitizeDurationBox {
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationChoice {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sanitizeDurationLabel {
|
|
||||||
-moz-margin-start: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#SanitizeDialogPane > groupbox {
|
#SanitizeDialogPane > groupbox {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
|
#sanitizeDurationChoice {
|
||||||
|
-moz-margin-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the duration label with the warning box and item list */
|
||||||
|
#sanitizeDurationLabel {
|
||||||
|
-moz-margin-start: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||||
takes up a little space, causing the end of the dropdown to not be aligned
|
takes up a little space, causing the end of the dropdown to not be aligned
|
||||||
with the warning box. */
|
with the warning box. */
|
||||||
|
@ -32,9 +42,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#sanitizeEverythingWarningDescBox {
|
#sanitizeEverythingWarningDescBox {
|
||||||
padding: 0;
|
padding: 0 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,8 +52,8 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
margin-left: -1px;
|
-moz-margin-start: -1px;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expander-up,
|
.expander-up,
|
||||||
|
@ -69,16 +78,15 @@
|
||||||
|
|
||||||
/* Make the item list the same width as the warning box */
|
/* Make the item list the same width as the warning box */
|
||||||
#itemList {
|
#itemList {
|
||||||
margin-left: 0;
|
-moz-margin-start: 0;
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Make the rightmost dialog button ("cancel") align wih right side of the
|
/* Align the last dialog button with the end of the warning box */
|
||||||
warning box */
|
|
||||||
.prefWindow-dlgbuttons {
|
.prefWindow-dlgbuttons {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
.dialog-button[dlgtype="cancel"] {
|
.dialog-button[dlgtype="cancel"] {
|
||||||
margin-right: 0;
|
-moz-margin-end: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
#!perl -w
|
|
||||||
package Moz::MacCVS;
|
|
||||||
|
|
||||||
# package Mac::Apps::MacCVS; this should really be the name of the package
|
|
||||||
# but due to our directory hierarchy in mozilla, I am not doing it
|
|
||||||
|
|
||||||
require 5.004;
|
|
||||||
require Exporter;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Exporter;
|
|
||||||
|
|
||||||
use vars qw($VERSION @ISA @EXPORT);
|
|
||||||
|
|
||||||
use Cwd;
|
|
||||||
|
|
||||||
use File::Basename;
|
|
||||||
|
|
||||||
use Mac::StandardFile;
|
|
||||||
use Mac::AppleEvents;
|
|
||||||
use Mac::AppleEvents::Simple;
|
|
||||||
|
|
||||||
@ISA = qw(Exporter);
|
|
||||||
@EXPORT = qw(new describe checkout update);
|
|
||||||
$VERSION = "1.00";
|
|
||||||
|
|
||||||
# If you want to understand the gobbldeygook that's used to build Apple Events,
|
|
||||||
# you should start by reading the AEGizmos documentation.
|
|
||||||
|
|
||||||
|
|
||||||
# Architecture:
|
|
||||||
# cvs session object:
|
|
||||||
# name - session name
|
|
||||||
# session_file - session file
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
my($last_error) = 0;
|
|
||||||
my($gAppSig) = 'Mcvs'; # MacCVS Pro
|
|
||||||
|
|
||||||
#
|
|
||||||
# utility routines
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
sub _checkForEventError($)
|
|
||||||
{
|
|
||||||
my($evt) = @_;
|
|
||||||
|
|
||||||
if ($evt->{ERRNO} != 0)
|
|
||||||
{
|
|
||||||
print STDERR "Error. Script returned '$evt->{ERROR} (error $evt->{ERRNO})\n";
|
|
||||||
$last_error = $evt->{ERRNO};
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1; # success
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Session object methods
|
|
||||||
#
|
|
||||||
|
|
||||||
sub new
|
|
||||||
{
|
|
||||||
my ( $proto, $session_file) = @_;
|
|
||||||
my $class = ref($proto) || $proto;
|
|
||||||
my $self = {};
|
|
||||||
|
|
||||||
if ( defined($session_file) && ( -e $session_file) )
|
|
||||||
{
|
|
||||||
$self->{"name"} = basename( $session_file );
|
|
||||||
$self->{"session_file"} = $session_file;
|
|
||||||
bless $self, $class;
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
print STDERR "MacCVS->new cvs file < $session_file > does not exist\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# makes sure that the session is open
|
|
||||||
# assertSessionOpen()
|
|
||||||
# returns 1 on success
|
|
||||||
sub assertSessionOpen()
|
|
||||||
{
|
|
||||||
my ($self) = shift;
|
|
||||||
|
|
||||||
$last_error = 0;
|
|
||||||
|
|
||||||
my($prm) =
|
|
||||||
q"'----':obj {form:name, want:type(alis), seld:TEXT(@), from:'null'()}";
|
|
||||||
|
|
||||||
my($evt) = do_event(qw/aevt odoc/, $gAppSig, $prm, $self->{session_file});
|
|
||||||
return _checkForEventError($evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
# prints the cvs object, used mostly for debugging
|
|
||||||
sub describe
|
|
||||||
{
|
|
||||||
my($self) = shift;
|
|
||||||
$last_error = 0;
|
|
||||||
print "MacCVS:: name: ", $self->{name}, " session file: ", $self->{session_file}, "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# checkout( self, module, revision, date)
|
|
||||||
# MacCVS checkout command
|
|
||||||
# returns 1 on success.
|
|
||||||
sub checkout()
|
|
||||||
{
|
|
||||||
my($self, $module, $revision, $date ) = @_;
|
|
||||||
unless( defined ($module) ) { $module = ""; } # get rid of the pesky undefined warnings
|
|
||||||
unless( defined ($revision) ) { $revision = ""; }
|
|
||||||
unless( defined ($date) ) { $date = ""; }
|
|
||||||
|
|
||||||
$last_error = 0;
|
|
||||||
|
|
||||||
$self->assertSessionOpen() || die "Error: failed to open MacCVS session file at $self->{session_file}\n";
|
|
||||||
|
|
||||||
my($revstring) = ($revision ne "") ? $revision : "(none)";
|
|
||||||
my($datestring) = ($date ne "") ? $date : "(none)";
|
|
||||||
|
|
||||||
print "Checking out $module with revision $revstring, date $datestring\n";
|
|
||||||
|
|
||||||
my($prm) =
|
|
||||||
q"'----':obj {form:name, want:type(docu), seld:TEXT(@), from:'null'()}, ".
|
|
||||||
q"modl:'TEXT'(@), tagr:'TEXT'(@), tagd:'TEXT'(@) ";
|
|
||||||
|
|
||||||
my($evt) = do_event(qw/MCvs cout/, $gAppSig, $prm, $self->{name}, $module, $revision, $date);
|
|
||||||
return _checkForEventError($evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# update( self, branch tag, list of paths)
|
|
||||||
# MacCVS udate command
|
|
||||||
# returns 1 on success.
|
|
||||||
# NOTE: MacCVS Pro does not correctly support this stuff yet (as of version 2.7d5).
|
|
||||||
sub update()
|
|
||||||
{
|
|
||||||
my($self, $branch, $paths ) = @_;
|
|
||||||
|
|
||||||
$last_error = 0;
|
|
||||||
|
|
||||||
$self->assertSessionOpen() || die "Error: failed to open MacCVS session file at $self->{session_file}\n";
|
|
||||||
|
|
||||||
if ($branch eq "HEAD") {
|
|
||||||
$branch = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
my($paths_list) = "";
|
|
||||||
|
|
||||||
my($path);
|
|
||||||
foreach $path (@$paths)
|
|
||||||
{
|
|
||||||
if ($paths_list ne "") {
|
|
||||||
$paths_list = $paths_list.", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
$paths_list = $paths_list."Ò".$path."Ó";
|
|
||||||
}
|
|
||||||
|
|
||||||
my($prm) =
|
|
||||||
q"'----':obj {form:name, want:type(docu), seld:TEXT(@), from:'null'()}, ".
|
|
||||||
q"tagr:'TEXT'(@), tFls:[";
|
|
||||||
|
|
||||||
$prm = $prm.$paths_list."]";
|
|
||||||
|
|
||||||
my($evt) = do_event(qw/MCvs updt/, $gAppSig, $prm, $self->{name}, $branch);
|
|
||||||
return _checkForEventError($evt);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
sub getLastError()
|
|
||||||
{
|
|
||||||
return $last_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
MacCVS - Interface to MacCVS
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
use MacCVS;
|
|
||||||
$session = MacCVS->new( <session_file_path>) || die "cannot create session";
|
|
||||||
$session->checkout([module] [revision] [date]) || die "Could not check out";
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
This is a MacCVS interface for talking to MacCVS Pro client.
|
|
||||||
MacCVSSession is the class used to manipulate the session
|
|
||||||
|
|
||||||
=item new
|
|
||||||
MacCVS->new( <cvs session file path>);
|
|
||||||
|
|
||||||
Creates a new session. Returns undef on failure.
|
|
||||||
|
|
||||||
=item checkout( <module> [revision] [date] )
|
|
||||||
|
|
||||||
cvs checkout command. Revision and date are optional
|
|
||||||
returns 0 on failure
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item MacCVS Home Page
|
|
||||||
|
|
||||||
http://www.maccvs.org/
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Aleks Totic atotic@netscape.com
|
|
||||||
Simon Fraser sfraser@netscape.com
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__END__
|
|
|
@ -537,32 +537,22 @@ private:
|
||||||
* has set the "security.xpconnect.plugin.unrestricted" pref to allow
|
* has set the "security.xpconnect.plugin.unrestricted" pref to allow
|
||||||
* anybody to script plugin objects from anywhere.
|
* anybody to script plugin objects from anywhere.
|
||||||
*
|
*
|
||||||
* @param cx The context we're running on.
|
|
||||||
* NB: If null, "sameOrigin" does not have any effect.
|
|
||||||
* @param aObj The nsISupports representation of the object in question
|
* @param aObj The nsISupports representation of the object in question
|
||||||
* object, possibly null.
|
* object, possibly null.
|
||||||
* @param aJSObject The JSObject representation of the object in question
|
* @param aJSObject The JSObject representation of the object in question.
|
||||||
* if |cx| is non-null and |aObjectSecurityLevel| is
|
* Only used if |aObjectSecurityLevel| is "sameOrigin".
|
||||||
* "sameOrigin". If null will be calculated from aObj (if
|
|
||||||
* non-null) if and only if aObj is an XPCWrappedJS. The
|
|
||||||
* rationale behind this is that if we're creating a JS
|
|
||||||
* wrapper for an XPCWrappedJS, this object definitely
|
|
||||||
* expects to be exposed to JS.
|
|
||||||
* @param aSubjectPrincipal The nominal subject principal used when
|
* @param aSubjectPrincipal The nominal subject principal used when
|
||||||
* aObjectSecurityLevel is "sameOrigin". If null,
|
* aObjectSecurityLevel is "sameOrigin".
|
||||||
* this is calculated if it's needed.
|
|
||||||
* @param aObjectSecurityLevel Can be one of three values:
|
* @param aObjectSecurityLevel Can be one of three values:
|
||||||
* - allAccess: Allow access no matter what.
|
* - allAccess: Allow access no matter what.
|
||||||
* - noAccess: Deny access no matter what.
|
* - noAccess: Deny access no matter what.
|
||||||
* - sameOrigin: If |cx| is null, behave like noAccess.
|
* - sameOrigin: If both a subject principal and JS
|
||||||
* Otherwise, possibly compute a subject
|
* object have been passed in, returns
|
||||||
* and object principal and return true if
|
* true if the subject subsumes the object,
|
||||||
* and only if the subject has greater than
|
* otherwise, behaves like noAccess.
|
||||||
* or equal privileges to the object.
|
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
CheckXPCPermissions(JSContext* cx,
|
CheckXPCPermissions(nsISupports* aObj, JSObject* aJSObject,
|
||||||
nsISupports* aObj, JSObject* aJSObject,
|
|
||||||
nsIPrincipal* aSubjectPrincipal,
|
nsIPrincipal* aSubjectPrincipal,
|
||||||
const char* aObjectSecurityLevel);
|
const char* aObjectSecurityLevel);
|
||||||
|
|
||||||
|
|
|
@ -784,7 +784,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = CheckXPCPermissions(cx, aObj, aJSObject, subjectPrincipal,
|
rv = CheckXPCPermissions(aObj, aJSObject, subjectPrincipal,
|
||||||
objectSecurityLevel);
|
objectSecurityLevel);
|
||||||
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl
|
#ifdef DEBUG_CAPS_CheckPropertyAccessImpl
|
||||||
if(NS_SUCCEEDED(rv))
|
if(NS_SUCCEEDED(rv))
|
||||||
|
@ -2859,7 +2859,7 @@ nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
|
||||||
if (checkedComponent)
|
if (checkedComponent)
|
||||||
checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
|
checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
|
||||||
|
|
||||||
nsresult rv = CheckXPCPermissions(cx, aObj, nsnull, nsnull, objectSecurityLevel);
|
nsresult rv = CheckXPCPermissions(aObj, nsnull, nsnull, objectSecurityLevel);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
{
|
{
|
||||||
//-- Access denied, report an error
|
//-- Access denied, report an error
|
||||||
|
@ -2970,7 +2970,7 @@ nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
|
||||||
nsCRT::free(cidStr);
|
nsCRT::free(cidStr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
|
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
#ifdef XPC_IDISPATCH_SUPPORT
|
#ifdef XPC_IDISPATCH_SUPPORT
|
||||||
{
|
{
|
||||||
|
@ -3007,7 +3007,7 @@ nsScriptSecurityManager::CanGetService(JSContext *cx,
|
||||||
nsCRT::free(cidStr);
|
nsCRT::free(cidStr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
|
nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
{
|
{
|
||||||
//-- Access denied, report an error
|
//-- Access denied, report an error
|
||||||
|
@ -3046,8 +3046,7 @@ nsScriptSecurityManager::CanAccess(PRUint32 aAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsScriptSecurityManager::CheckXPCPermissions(JSContext* cx,
|
nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj, JSObject* aJSObject,
|
||||||
nsISupports* aObj, JSObject* aJSObject,
|
|
||||||
nsIPrincipal* aSubjectPrincipal,
|
nsIPrincipal* aSubjectPrincipal,
|
||||||
const char* aObjectSecurityLevel)
|
const char* aObjectSecurityLevel)
|
||||||
{
|
{
|
||||||
|
@ -3061,40 +3060,20 @@ nsScriptSecurityManager::CheckXPCPermissions(JSContext* cx,
|
||||||
{
|
{
|
||||||
if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
|
if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
if (cx && PL_strcasecmp(aObjectSecurityLevel, "sameOrigin") == 0)
|
if (aSubjectPrincipal && aJSObject &&
|
||||||
|
PL_strcasecmp(aObjectSecurityLevel, "sameOrigin") == 0)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsIPrincipal* objectPrincipal = doGetObjectPrincipal(aJSObject);
|
||||||
if (!aJSObject)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIXPConnectWrappedJS> xpcwrappedjs =
|
|
||||||
do_QueryInterface(aObj);
|
|
||||||
if (xpcwrappedjs)
|
|
||||||
{
|
|
||||||
rv = xpcwrappedjs->GetJSObject(&aJSObject);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aSubjectPrincipal)
|
// Only do anything if we have both a subject and object
|
||||||
|
// principal.
|
||||||
|
if (objectPrincipal)
|
||||||
{
|
{
|
||||||
// No subject principal passed in. Compute it.
|
PRBool subsumes;
|
||||||
aSubjectPrincipal = GetSubjectPrincipal(cx, &rv);
|
nsresult rv = aSubjectPrincipal->Subsumes(objectPrincipal, &subsumes);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
if (subsumes)
|
||||||
if (aSubjectPrincipal && aJSObject)
|
return NS_OK;
|
||||||
{
|
|
||||||
nsIPrincipal* objectPrincipal = doGetObjectPrincipal(aJSObject);
|
|
||||||
|
|
||||||
// Only do anything if we have both a subject and object
|
|
||||||
// principal.
|
|
||||||
if (objectPrincipal)
|
|
||||||
{
|
|
||||||
PRBool subsumes;
|
|
||||||
rv = aSubjectPrincipal->Subsumes(objectPrincipal, &subsumes);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
if (subsumes)
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
|
else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
|
||||||
|
|
|
@ -3765,7 +3765,7 @@ nsContentUtils::SetNodeTextContent(nsIContent* aContent,
|
||||||
// i is unsigned, so i >= is always true
|
// i is unsigned, so i >= is always true
|
||||||
for (PRUint32 i = 0; i < childCount; ++i) {
|
for (PRUint32 i = 0; i < childCount; ++i) {
|
||||||
nsIContent* child = aContent->GetChildAt(removeIndex);
|
nsIContent* child = aContent->GetChildAt(removeIndex);
|
||||||
if (removeIndex == 0 && child->IsNodeOfType(nsINode::eTEXT)) {
|
if (removeIndex == 0 && child && child->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
nsresult rv = child->SetText(aValue, PR_TRUE);
|
nsresult rv = child->SetText(aValue, PR_TRUE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
#include "nsISelectionController.h"
|
#include "nsISelectionController.h"
|
||||||
#include "nsISelectionPrivate.h"
|
#include "nsISelectionPrivate.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsLayoutUtils.h"
|
||||||
#include "nsISelection2.h"
|
#include "nsISelection2.h"
|
||||||
#include "nsIMEStateManager.h"
|
#include "nsIMEStateManager.h"
|
||||||
|
|
||||||
|
@ -730,6 +731,46 @@ nsContentEventHandler::OnQuerySelectionAsTransferable(nsQueryContentEvent* aEven
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentEventHandler::OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent)
|
||||||
|
{
|
||||||
|
nsresult rv = Init(aEvent);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
nsIFrame* rootFrame = mPresShell->GetRootFrame();
|
||||||
|
nsPoint ptInRoot =
|
||||||
|
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
|
||||||
|
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
|
||||||
|
if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame) {
|
||||||
|
// there is no character at the point.
|
||||||
|
aEvent->mReply.mOffset = nsQueryContentEvent::NOT_FOUND;
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
nsPoint ptInTarget = ptInRoot - targetFrame->GetOffsetTo(rootFrame);
|
||||||
|
nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
|
||||||
|
nsIFrame::ContentOffsets offsets =
|
||||||
|
textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
|
||||||
|
NS_ENSURE_TRUE(offsets.content, NS_ERROR_FAILURE);
|
||||||
|
PRUint32 nativeOffset;
|
||||||
|
rv = GetFlatTextOffsetOfRange(mRootContent, offsets.content, offsets.offset,
|
||||||
|
&nativeOffset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsQueryContentEvent textRect(PR_TRUE, NS_QUERY_TEXT_RECT, aEvent->widget);
|
||||||
|
textRect.InitForQueryTextRect(nativeOffset, 1);
|
||||||
|
rv = OnQueryTextRect(&textRect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
// currently, we don't need to get the actual text.
|
||||||
|
aEvent->mReply.mOffset = nativeOffset;
|
||||||
|
aEvent->mReply.mRect = textRect.mReply.mRect;
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||||
nsINode* aNode,
|
nsINode* aNode,
|
||||||
|
|
|
@ -81,6 +81,8 @@ public:
|
||||||
nsresult OnQueryContentState(nsQueryContentEvent* aEvent);
|
nsresult OnQueryContentState(nsQueryContentEvent* aEvent);
|
||||||
// NS_QUERY_SELECTION_AS_TRANSFERABLE event handler
|
// NS_QUERY_SELECTION_AS_TRANSFERABLE event handler
|
||||||
nsresult OnQuerySelectionAsTransferable(nsQueryContentEvent* aEvent);
|
nsresult OnQuerySelectionAsTransferable(nsQueryContentEvent* aEvent);
|
||||||
|
// NS_QUERY_CHARACTER_AT_POINT event handler
|
||||||
|
nsresult OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent);
|
||||||
|
|
||||||
// NS_SELECTION_* event
|
// NS_SELECTION_* event
|
||||||
nsresult OnSelectionEvent(nsSelectionEvent* aEvent);
|
nsresult OnSelectionEvent(nsSelectionEvent* aEvent);
|
||||||
|
|
|
@ -1758,6 +1758,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
handler.OnQuerySelectionAsTransferable(static_cast<nsQueryContentEvent*>(aEvent));
|
handler.OnQuerySelectionAsTransferable(static_cast<nsQueryContentEvent*>(aEvent));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NS_QUERY_CHARACTER_AT_POINT:
|
||||||
|
{
|
||||||
|
nsContentEventHandler handler(mPresContext);
|
||||||
|
handler.OnQueryCharacterAtPoint(static_cast<nsQueryContentEvent*>(aEvent));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NS_SELECTION_SET:
|
case NS_SELECTION_SET:
|
||||||
{
|
{
|
||||||
nsContentEventHandler handler(mPresContext);
|
nsContentEventHandler handler(mPresContext);
|
||||||
|
|
|
@ -172,11 +172,15 @@ void nsHTMLMediaElement::QueueLoadFromSourceTask()
|
||||||
NS_DispatchToMainThread(event);
|
NS_DispatchToMainThread(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsHTMLMediaElement::MediaLoadListener : public nsIStreamListener
|
class nsHTMLMediaElement::MediaLoadListener : public nsIStreamListener,
|
||||||
|
public nsIChannelEventSink,
|
||||||
|
public nsIInterfaceRequestor
|
||||||
{
|
{
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIREQUESTOBSERVER
|
NS_DECL_NSIREQUESTOBSERVER
|
||||||
NS_DECL_NSISTREAMLISTENER
|
NS_DECL_NSISTREAMLISTENER
|
||||||
|
NS_DECL_NSICHANNELEVENTSINK
|
||||||
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MediaLoadListener(nsHTMLMediaElement* aElement)
|
MediaLoadListener(nsHTMLMediaElement* aElement)
|
||||||
|
@ -190,7 +194,9 @@ private:
|
||||||
nsCOMPtr<nsIStreamListener> mNextListener;
|
nsCOMPtr<nsIStreamListener> mNextListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS2(nsHTMLMediaElement::MediaLoadListener, nsIRequestObserver, nsIStreamListener)
|
NS_IMPL_ISUPPORTS4(nsHTMLMediaElement::MediaLoadListener, nsIRequestObserver,
|
||||||
|
nsIStreamListener, nsIChannelEventSink,
|
||||||
|
nsIInterfaceRequestor)
|
||||||
|
|
||||||
NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||||
{
|
{
|
||||||
|
@ -252,6 +258,21 @@ NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnDataAvailable(nsIRequest*
|
||||||
return mNextListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, aCount);
|
return mNextListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, aCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::OnChannelRedirect(nsIChannel* aOldChannel,
|
||||||
|
nsIChannel* aNewChannel,
|
||||||
|
PRUint32 aFlags)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIChannelEventSink> sink = do_QueryInterface(mNextListener);
|
||||||
|
if (sink)
|
||||||
|
return sink->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsHTMLMediaElement::MediaLoadListener::GetInterface(const nsIID & aIID, void **aResult)
|
||||||
|
{
|
||||||
|
return QueryInterface(aIID, aResult);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMPL_ADDREF_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
NS_IMPL_ADDREF_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
||||||
NS_IMPL_RELEASE_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
NS_IMPL_RELEASE_INHERITED(nsHTMLMediaElement, nsGenericHTMLElement)
|
||||||
|
|
||||||
|
@ -513,8 +534,10 @@ nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
|
||||||
// The listener holds a strong reference to us. This creates a reference
|
// The listener holds a strong reference to us. This creates a reference
|
||||||
// cycle which is manually broken in the listener's OnStartRequest method
|
// cycle which is manually broken in the listener's OnStartRequest method
|
||||||
// after it is finished with the element.
|
// after it is finished with the element.
|
||||||
nsCOMPtr<nsIStreamListener> loadListener = new MediaLoadListener(this);
|
nsRefPtr<MediaLoadListener> loadListener = new MediaLoadListener(this);
|
||||||
if (!loadListener) return NS_ERROR_OUT_OF_MEMORY;
|
if (!loadListener) return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
mChannel->SetNotificationCallbacks(loadListener);
|
||||||
|
|
||||||
nsCOMPtr<nsIStreamListener> listener;
|
nsCOMPtr<nsIStreamListener> listener;
|
||||||
if (ShouldCheckAllowOrigin()) {
|
if (ShouldCheckAllowOrigin()) {
|
||||||
|
|
|
@ -89,6 +89,16 @@ class nsAudioStream
|
||||||
// Block until buffered audio data has been consumed.
|
// Block until buffered audio data has been consumed.
|
||||||
void Drain();
|
void Drain();
|
||||||
|
|
||||||
|
// Pause audio playback
|
||||||
|
void Pause();
|
||||||
|
|
||||||
|
// Resume audio playback
|
||||||
|
void Resume();
|
||||||
|
|
||||||
|
// Return the position in seconds of the sample being played by the
|
||||||
|
// audio hardware.
|
||||||
|
float GetPosition();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double mVolume;
|
double mVolume;
|
||||||
void* mAudioHandle;
|
void* mAudioHandle;
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
|
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsAutoLock.h"
|
#include "nsAutoLock.h"
|
||||||
|
#include "nsIPrincipal.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Media applications want fast, "on demand" random access to media data,
|
* Media applications want fast, "on demand" random access to media data,
|
||||||
|
@ -186,6 +188,13 @@
|
||||||
* we must not acquire any nsMediaDecoder locks or nsMediaStream locks
|
* we must not acquire any nsMediaDecoder locks or nsMediaStream locks
|
||||||
* while holding the nsMediaCache lock. But it's OK to hold those locks
|
* while holding the nsMediaCache lock. But it's OK to hold those locks
|
||||||
* and then get the nsMediaCache lock.
|
* and then get the nsMediaCache lock.
|
||||||
|
*
|
||||||
|
* nsMediaCache associates a principal with each stream. CacheClientSeek
|
||||||
|
* can trigger new HTTP requests; due to redirects to other domains,
|
||||||
|
* each HTTP load can return data with a different principal. This
|
||||||
|
* principal must be passed to NotifyDataReceived, and nsMediaCache
|
||||||
|
* will detect when different principals are associated with data in the
|
||||||
|
* same stream, and replace them with a null principal.
|
||||||
*/
|
*/
|
||||||
class nsMediaCache;
|
class nsMediaCache;
|
||||||
// defined in nsMediaStream.h
|
// defined in nsMediaStream.h
|
||||||
|
@ -215,7 +224,8 @@ public:
|
||||||
mStreamOffset(0), mStreamLength(-1), mPlaybackBytesPerSecond(10000),
|
mStreamOffset(0), mStreamLength(-1), mPlaybackBytesPerSecond(10000),
|
||||||
mPinCount(0), mCurrentMode(MODE_PLAYBACK), mClosed(PR_FALSE),
|
mPinCount(0), mCurrentMode(MODE_PLAYBACK), mClosed(PR_FALSE),
|
||||||
mIsSeekable(PR_FALSE), mCacheSuspended(PR_FALSE),
|
mIsSeekable(PR_FALSE), mCacheSuspended(PR_FALSE),
|
||||||
mMetadataInPartialBlockBuffer(PR_FALSE) {}
|
mMetadataInPartialBlockBuffer(PR_FALSE),
|
||||||
|
mUsingNullPrincipal(PR_FALSE) {}
|
||||||
~nsMediaCacheStream();
|
~nsMediaCacheStream();
|
||||||
|
|
||||||
// Set up this stream with the cache. Can fail on OOM. Must be called
|
// Set up this stream with the cache. Can fail on OOM. Must be called
|
||||||
|
@ -236,6 +246,8 @@ public:
|
||||||
void Close();
|
void Close();
|
||||||
// This returns true when the stream has been closed
|
// This returns true when the stream has been closed
|
||||||
PRBool IsClosed() const { return mClosed; }
|
PRBool IsClosed() const { return mClosed; }
|
||||||
|
// Get the principal for this stream.
|
||||||
|
nsIPrincipal* GetCurrentPrincipal() { return mPrincipal; }
|
||||||
|
|
||||||
// These callbacks are called on the main thread by the client
|
// These callbacks are called on the main thread by the client
|
||||||
// when data has been received via the channel.
|
// when data has been received via the channel.
|
||||||
|
@ -263,7 +275,9 @@ public:
|
||||||
// the starting offset is known via NotifyDataStarted or because
|
// the starting offset is known via NotifyDataStarted or because
|
||||||
// the cache requested the offset in
|
// the cache requested the offset in
|
||||||
// nsMediaChannelStream::CacheClientSeek, or because it defaulted to 0.
|
// nsMediaChannelStream::CacheClientSeek, or because it defaulted to 0.
|
||||||
void NotifyDataReceived(PRInt64 aSize, const char* aData);
|
// We pass in the principal that was used to load this data.
|
||||||
|
void NotifyDataReceived(PRInt64 aSize, const char* aData,
|
||||||
|
nsIPrincipal* aPrincipal);
|
||||||
// Notifies the cache that the channel has closed with the given status.
|
// Notifies the cache that the channel has closed with the given status.
|
||||||
void NotifyDataEnded(nsresult aStatus);
|
void NotifyDataEnded(nsresult aStatus);
|
||||||
|
|
||||||
|
@ -363,9 +377,12 @@ private:
|
||||||
// This is used to NotifyAll to wake up threads that might be
|
// This is used to NotifyAll to wake up threads that might be
|
||||||
// blocked on reading from this stream.
|
// blocked on reading from this stream.
|
||||||
void CloseInternal(nsAutoMonitor* aMonitor);
|
void CloseInternal(nsAutoMonitor* aMonitor);
|
||||||
|
// Update mPrincipal given that data has been received from aPrincipal
|
||||||
|
void UpdatePrincipal(nsIPrincipal* aPrincipal);
|
||||||
|
|
||||||
// This field is main-thread-only.
|
// These fields are main-thread-only.
|
||||||
nsMediaChannelStream* mClient;
|
nsMediaChannelStream* mClient;
|
||||||
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||||
|
|
||||||
// All other fields are all protected by the cache's monitor and
|
// All other fields are all protected by the cache's monitor and
|
||||||
// can be accessed by by any thread.
|
// can be accessed by by any thread.
|
||||||
|
@ -401,6 +418,9 @@ private:
|
||||||
PRPackedBool mCacheSuspended;
|
PRPackedBool mCacheSuspended;
|
||||||
// true if some data in mPartialBlockBuffer has been read as metadata
|
// true if some data in mPartialBlockBuffer has been read as metadata
|
||||||
PRPackedBool mMetadataInPartialBlockBuffer;
|
PRPackedBool mMetadataInPartialBlockBuffer;
|
||||||
|
// true if mPrincipal is a null principal because we saw data from
|
||||||
|
// multiple origins
|
||||||
|
PRPackedBool mUsingNullPrincipal;
|
||||||
|
|
||||||
// Data received for the block containing mChannelOffset. Data needs
|
// Data received for the block containing mChannelOffset. Data needs
|
||||||
// to wait here so we can write back a complete block. The first
|
// to wait here so we can write back a complete block. The first
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
#include "nsIStreamListener.h"
|
#include "nsIStreamListener.h"
|
||||||
|
#include "nsIChannelEventSink.h"
|
||||||
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "prlock.h"
|
#include "prlock.h"
|
||||||
#include "nsMediaCache.h"
|
#include "nsMediaCache.h"
|
||||||
#include "nsTimeStamp.h"
|
#include "nsTimeStamp.h"
|
||||||
|
@ -149,8 +151,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following can be called on the main thread only:
|
// The following can be called on the main thread only:
|
||||||
// Get the current principal for the channel
|
|
||||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
|
||||||
// Get the decoder
|
// Get the decoder
|
||||||
nsMediaDecoder* Decoder() { return mDecoder; }
|
nsMediaDecoder* Decoder() { return mDecoder; }
|
||||||
// Close the stream, stop any listeners, channels, etc.
|
// Close the stream, stop any listeners, channels, etc.
|
||||||
|
@ -161,6 +161,8 @@ public:
|
||||||
virtual void Suspend() = 0;
|
virtual void Suspend() = 0;
|
||||||
// Resume any downloads that have been suspended.
|
// Resume any downloads that have been suspended.
|
||||||
virtual void Resume() = 0;
|
virtual void Resume() = 0;
|
||||||
|
// Get the current principal for the channel
|
||||||
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
||||||
|
|
||||||
// These methods are called off the main thread.
|
// These methods are called off the main thread.
|
||||||
// The mode is initially MODE_PLAYBACK.
|
// The mode is initially MODE_PLAYBACK.
|
||||||
|
@ -317,6 +319,7 @@ public:
|
||||||
virtual nsresult Close();
|
virtual nsresult Close();
|
||||||
virtual void Suspend();
|
virtual void Suspend();
|
||||||
virtual void Resume();
|
virtual void Resume();
|
||||||
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
||||||
// Return PR_TRUE if the stream has been closed.
|
// Return PR_TRUE if the stream has been closed.
|
||||||
PRBool IsClosed() const { return mCacheStream.IsClosed(); }
|
PRBool IsClosed() const { return mCacheStream.IsClosed(); }
|
||||||
|
|
||||||
|
@ -337,13 +340,18 @@ public:
|
||||||
virtual PRBool IsSuspendedByCache();
|
virtual PRBool IsSuspendedByCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class Listener : public nsIStreamListener {
|
class Listener : public nsIStreamListener,
|
||||||
|
public nsIInterfaceRequestor,
|
||||||
|
public nsIChannelEventSink
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Listener(nsMediaChannelStream* aStream) : mStream(aStream) {}
|
Listener(nsMediaChannelStream* aStream) : mStream(aStream) {}
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIREQUESTOBSERVER
|
NS_DECL_NSIREQUESTOBSERVER
|
||||||
NS_DECL_NSISTREAMLISTENER
|
NS_DECL_NSISTREAMLISTENER
|
||||||
|
NS_DECL_NSICHANNELEVENTSINK
|
||||||
|
NS_DECL_NSIINTERFACEREQUESTOR
|
||||||
|
|
||||||
void Revoke() { mStream = nsnull; }
|
void Revoke() { mStream = nsnull; }
|
||||||
|
|
||||||
|
@ -358,10 +366,12 @@ protected:
|
||||||
nsresult OnDataAvailable(nsIRequest* aRequest,
|
nsresult OnDataAvailable(nsIRequest* aRequest,
|
||||||
nsIInputStream* aStream,
|
nsIInputStream* aStream,
|
||||||
PRUint32 aCount);
|
PRUint32 aCount);
|
||||||
|
nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, PRUint32 aFlags);
|
||||||
|
|
||||||
// Opens the channel, using an HTTP byte range request to start at aOffset
|
// Opens the channel, using an HTTP byte range request to start at aOffset
|
||||||
// if possible. Main thread only.
|
// if possible. Main thread only.
|
||||||
nsresult OpenChannel(nsIStreamListener** aStreamListener, PRInt64 aOffset);
|
nsresult OpenChannel(nsIStreamListener** aStreamListener, PRInt64 aOffset);
|
||||||
|
void SetupChannelHeaders();
|
||||||
// Closes the channel. Main thread only.
|
// Closes the channel. Main thread only.
|
||||||
void CloseChannel();
|
void CloseChannel();
|
||||||
|
|
||||||
|
@ -373,9 +383,9 @@ protected:
|
||||||
PRUint32 *aWriteCount);
|
PRUint32 *aWriteCount);
|
||||||
|
|
||||||
// Main thread access only
|
// Main thread access only
|
||||||
|
PRInt64 mLastSeekOffset;
|
||||||
nsRefPtr<Listener> mListener;
|
nsRefPtr<Listener> mListener;
|
||||||
PRUint32 mSuspendCount;
|
PRUint32 mSuspendCount;
|
||||||
PRPackedBool mSeeking;
|
|
||||||
|
|
||||||
// Any thread access
|
// Any thread access
|
||||||
nsMediaCacheStream mCacheStream;
|
nsMediaCacheStream mCacheStream;
|
||||||
|
|
|
@ -190,7 +190,9 @@ PRInt32 nsAudioStream::Available()
|
||||||
return FAKE_BUFFER_SIZE;
|
return FAKE_BUFFER_SIZE;
|
||||||
|
|
||||||
size_t s = 0;
|
size_t s = 0;
|
||||||
sa_stream_get_write_size(static_cast<sa_stream_t*>(mAudioHandle), &s);
|
if (sa_stream_get_write_size(static_cast<sa_stream_t*>(mAudioHandle), &s) != SA_SUCCESS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return s / sizeof(short);
|
return s / sizeof(short);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,3 +220,35 @@ void nsAudioStream::Drain()
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsAudioStream::Pause()
|
||||||
|
{
|
||||||
|
if (!mAudioHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsAudioStream::Resume()
|
||||||
|
{
|
||||||
|
if (!mAudioHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
float nsAudioStream::GetPosition()
|
||||||
|
{
|
||||||
|
if (!mAudioHandle)
|
||||||
|
return -1.0;
|
||||||
|
|
||||||
|
PRInt64 position = 0;
|
||||||
|
if (sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle),
|
||||||
|
SA_POSITION_WRITE_SOFTWARE,
|
||||||
|
&position) == SA_SUCCESS) {
|
||||||
|
return (position / float(mRate) / mChannels / sizeof(short));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1390,10 +1390,47 @@ nsMediaCacheStream::NotifyDataStarted(PRInt64 aOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsMediaCacheStream::NotifyDataReceived(PRInt64 aSize, const char* aData)
|
nsMediaCacheStream::UpdatePrincipal(nsIPrincipal* aPrincipal)
|
||||||
|
{
|
||||||
|
if (!mPrincipal) {
|
||||||
|
NS_ASSERTION(!mUsingNullPrincipal, "Are we using a null principal or not?");
|
||||||
|
if (mUsingNullPrincipal) {
|
||||||
|
// Don't let mPrincipal be set to anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPrincipal = aPrincipal;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPrincipal == aPrincipal) {
|
||||||
|
// Common case
|
||||||
|
NS_ASSERTION(!mUsingNullPrincipal, "We can't receive data from a null principal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mUsingNullPrincipal) {
|
||||||
|
// We've already fallen back to a null principal, so nothing more
|
||||||
|
// to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool equal;
|
||||||
|
nsresult rv = mPrincipal->Equals(aPrincipal, &equal);
|
||||||
|
if (NS_SUCCEEDED(rv) && equal)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Principals are not equal, so set mPrincipal to a null principal.
|
||||||
|
mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
|
||||||
|
mUsingNullPrincipal = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsMediaCacheStream::NotifyDataReceived(PRInt64 aSize, const char* aData,
|
||||||
|
nsIPrincipal* aPrincipal)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
|
UpdatePrincipal(aPrincipal);
|
||||||
|
|
||||||
nsAutoMonitor mon(gMediaCache->Monitor());
|
nsAutoMonitor mon(gMediaCache->Monitor());
|
||||||
PRInt64 size = aSize;
|
PRInt64 size = aSize;
|
||||||
const char* data = aData;
|
const char* data = aData;
|
||||||
|
|
|
@ -65,7 +65,7 @@ using mozilla::TimeStamp;
|
||||||
nsMediaChannelStream::nsMediaChannelStream(nsMediaDecoder* aDecoder,
|
nsMediaChannelStream::nsMediaChannelStream(nsMediaDecoder* aDecoder,
|
||||||
nsIChannel* aChannel, nsIURI* aURI)
|
nsIChannel* aChannel, nsIURI* aURI)
|
||||||
: nsMediaStream(aDecoder, aChannel, aURI),
|
: nsMediaStream(aDecoder, aChannel, aURI),
|
||||||
mSuspendCount(0), mSeeking(PR_FALSE),
|
mLastSeekOffset(0), mSuspendCount(0),
|
||||||
mCacheStream(this),
|
mCacheStream(this),
|
||||||
mLock(nsAutoLock::NewLock("media.channel.stream")),
|
mLock(nsAutoLock::NewLock("media.channel.stream")),
|
||||||
mCacheSuspendCount(0)
|
mCacheSuspendCount(0)
|
||||||
|
@ -89,7 +89,9 @@ nsMediaChannelStream::~nsMediaChannelStream()
|
||||||
// disconnect the old listener from the nsMediaChannelStream and hook up
|
// disconnect the old listener from the nsMediaChannelStream and hook up
|
||||||
// a new listener, so notifications from the old channel are discarded
|
// a new listener, so notifications from the old channel are discarded
|
||||||
// and don't confuse us.
|
// and don't confuse us.
|
||||||
NS_IMPL_ISUPPORTS2(nsMediaChannelStream::Listener, nsIRequestObserver, nsIStreamListener)
|
NS_IMPL_ISUPPORTS4(nsMediaChannelStream::Listener,
|
||||||
|
nsIRequestObserver, nsIStreamListener, nsIChannelEventSink,
|
||||||
|
nsIInterfaceRequestor)
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsMediaChannelStream::Listener::OnStartRequest(nsIRequest* aRequest,
|
nsMediaChannelStream::Listener::OnStartRequest(nsIRequest* aRequest,
|
||||||
|
@ -122,6 +124,22 @@ nsMediaChannelStream::Listener::OnDataAvailable(nsIRequest* aRequest,
|
||||||
return mStream->OnDataAvailable(aRequest, aStream, aCount);
|
return mStream->OnDataAvailable(aRequest, aStream, aCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsMediaChannelStream::Listener::OnChannelRedirect(nsIChannel* aOldChannel,
|
||||||
|
nsIChannel* aNewChannel,
|
||||||
|
PRUint32 aFlags)
|
||||||
|
{
|
||||||
|
if (!mStream)
|
||||||
|
return NS_OK;
|
||||||
|
return mStream->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsMediaChannelStream::Listener::GetInterface(const nsIID & aIID, void **aResult)
|
||||||
|
{
|
||||||
|
return QueryInterface(aIID, aResult);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
||||||
{
|
{
|
||||||
|
@ -148,7 +166,7 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
||||||
ranges);
|
ranges);
|
||||||
PRBool acceptsRanges = ranges.EqualsLiteral("bytes");
|
PRBool acceptsRanges = ranges.EqualsLiteral("bytes");
|
||||||
|
|
||||||
if (!mSeeking) {
|
if (mLastSeekOffset == 0) {
|
||||||
// Look for duration headers from known Ogg content systems. In the case
|
// Look for duration headers from known Ogg content systems. In the case
|
||||||
// of multiple options for obtaining the duration the order of precedence is;
|
// of multiple options for obtaining the duration the order of precedence is;
|
||||||
// 1) The Media resource metadata if possible (done by the decoder itself).
|
// 1) The Media resource metadata if possible (done by the decoder itself).
|
||||||
|
@ -172,12 +190,12 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
||||||
|
|
||||||
PRUint32 responseStatus = 0;
|
PRUint32 responseStatus = 0;
|
||||||
hc->GetResponseStatus(&responseStatus);
|
hc->GetResponseStatus(&responseStatus);
|
||||||
if (mSeeking && responseStatus == HTTP_OK_CODE) {
|
if (mLastSeekOffset > 0 && responseStatus == HTTP_OK_CODE) {
|
||||||
// If we get an OK response but we were seeking, we have to assume
|
// If we get an OK response but we were seeking, we have to assume
|
||||||
// that seeking doesn't work. We also need to tell the cache that
|
// that seeking doesn't work. We also need to tell the cache that
|
||||||
// it's getting data for the start of the stream.
|
// it's getting data for the start of the stream.
|
||||||
mCacheStream.NotifyDataStarted(0);
|
mCacheStream.NotifyDataStarted(0);
|
||||||
} else if (!mSeeking &&
|
} else if (mLastSeekOffset == 0 &&
|
||||||
(responseStatus == HTTP_OK_CODE ||
|
(responseStatus == HTTP_OK_CODE ||
|
||||||
responseStatus == HTTP_PARTIAL_RESPONSE_CODE)) {
|
responseStatus == HTTP_PARTIAL_RESPONSE_CODE)) {
|
||||||
// We weren't seeking and got a valid response status,
|
// We weren't seeking and got a valid response status,
|
||||||
|
@ -243,6 +261,20 @@ nsMediaChannelStream::OnStopRequest(nsIRequest* aRequest, nsresult aStatus)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsMediaChannelStream::OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
|
||||||
|
PRUint32 aFlags)
|
||||||
|
{
|
||||||
|
mChannel = aNew;
|
||||||
|
SetupChannelHeaders();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CopySegmentClosure {
|
||||||
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||||
|
nsMediaChannelStream* mStream;
|
||||||
|
};
|
||||||
|
|
||||||
NS_METHOD
|
NS_METHOD
|
||||||
nsMediaChannelStream::CopySegmentToCache(nsIInputStream *aInStream,
|
nsMediaChannelStream::CopySegmentToCache(nsIInputStream *aInStream,
|
||||||
void *aClosure,
|
void *aClosure,
|
||||||
|
@ -251,8 +283,9 @@ nsMediaChannelStream::CopySegmentToCache(nsIInputStream *aInStream,
|
||||||
PRUint32 aCount,
|
PRUint32 aCount,
|
||||||
PRUint32 *aWriteCount)
|
PRUint32 *aWriteCount)
|
||||||
{
|
{
|
||||||
nsMediaChannelStream* stream = static_cast<nsMediaChannelStream*>(aClosure);
|
CopySegmentClosure* closure = static_cast<CopySegmentClosure*>(aClosure);
|
||||||
stream->mCacheStream.NotifyDataReceived(aCount, aFromSegment);
|
closure->mStream->mCacheStream.NotifyDataReceived(aCount, aFromSegment,
|
||||||
|
closure->mPrincipal);
|
||||||
*aWriteCount = aCount;
|
*aWriteCount = aCount;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -269,10 +302,17 @@ nsMediaChannelStream::OnDataAvailable(nsIRequest* aRequest,
|
||||||
mChannelStatistics.AddBytes(aCount);
|
mChannelStatistics.AddBytes(aCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopySegmentClosure closure;
|
||||||
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||||
|
if (secMan && mChannel) {
|
||||||
|
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(closure.mPrincipal));
|
||||||
|
}
|
||||||
|
closure.mStream = this;
|
||||||
|
|
||||||
PRUint32 count = aCount;
|
PRUint32 count = aCount;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
PRUint32 read;
|
PRUint32 read;
|
||||||
nsresult rv = aStream->ReadSegments(CopySegmentToCache, this, count,
|
nsresult rv = aStream->ReadSegments(CopySegmentToCache, &closure, count,
|
||||||
&read);
|
&read);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -310,7 +350,7 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener,
|
||||||
*aStreamListener = nsnull;
|
*aStreamListener = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSeeking = aOffset != 0;
|
mLastSeekOffset = aOffset;
|
||||||
|
|
||||||
mListener = new Listener(this);
|
mListener = new Listener(this);
|
||||||
NS_ENSURE_TRUE(mListener, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(mListener, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
@ -319,6 +359,8 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener,
|
||||||
*aStreamListener = mListener;
|
*aStreamListener = mListener;
|
||||||
NS_ADDREF(*aStreamListener);
|
NS_ADDREF(*aStreamListener);
|
||||||
} else {
|
} else {
|
||||||
|
mChannel->SetNotificationCallbacks(mListener.get());
|
||||||
|
|
||||||
nsCOMPtr<nsIStreamListener> listener = mListener.get();
|
nsCOMPtr<nsIStreamListener> listener = mListener.get();
|
||||||
|
|
||||||
// Ensure that if we're loading cross domain, that the server is sending
|
// Ensure that if we're loading cross domain, that the server is sending
|
||||||
|
@ -342,18 +384,7 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a byte range request from the start of the resource.
|
SetupChannelHeaders();
|
||||||
// This enables us to detect if the stream supports byte range
|
|
||||||
// requests, and therefore seeking, early.
|
|
||||||
nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel);
|
|
||||||
if (hc) {
|
|
||||||
nsCAutoString rangeString("bytes=");
|
|
||||||
rangeString.AppendInt(aOffset);
|
|
||||||
rangeString.Append("-");
|
|
||||||
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, PR_FALSE);
|
|
||||||
} else {
|
|
||||||
NS_ASSERTION(aOffset == 0, "Don't know how to seek on this channel type");
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mChannel->AsyncOpen(listener, nsnull);
|
nsresult rv = mChannel->AsyncOpen(listener, nsnull);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -362,6 +393,23 @@ nsresult nsMediaChannelStream::OpenChannel(nsIStreamListener** aStreamListener,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsMediaChannelStream::SetupChannelHeaders()
|
||||||
|
{
|
||||||
|
// Always use a byte range request even if we're reading from the start
|
||||||
|
// of the resource.
|
||||||
|
// This enables us to detect if the stream supports byte range
|
||||||
|
// requests, and therefore seeking, early.
|
||||||
|
nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel);
|
||||||
|
if (hc) {
|
||||||
|
nsCAutoString rangeString("bytes=");
|
||||||
|
rangeString.AppendInt(mLastSeekOffset);
|
||||||
|
rangeString.Append("-");
|
||||||
|
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, PR_FALSE);
|
||||||
|
} else {
|
||||||
|
NS_ASSERTION(mLastSeekOffset == 0, "Don't know how to seek on this channel type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsMediaChannelStream::Close()
|
nsresult nsMediaChannelStream::Close()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
@ -371,6 +419,14 @@ nsresult nsMediaChannelStream::Close()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIPrincipal> nsMediaChannelStream::GetCurrentPrincipal()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrincipal> principal = mCacheStream.GetCurrentPrincipal();
|
||||||
|
return principal.forget();
|
||||||
|
}
|
||||||
|
|
||||||
void nsMediaChannelStream::CloseChannel()
|
void nsMediaChannelStream::CloseChannel()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
@ -616,6 +672,7 @@ public:
|
||||||
virtual nsresult Close();
|
virtual nsresult Close();
|
||||||
virtual void Suspend() {}
|
virtual void Suspend() {}
|
||||||
virtual void Resume() {}
|
virtual void Resume() {}
|
||||||
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
||||||
|
|
||||||
// These methods are called off the main thread.
|
// These methods are called off the main thread.
|
||||||
|
|
||||||
|
@ -757,6 +814,18 @@ nsresult nsMediaFileStream::Close()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIPrincipal> nsMediaFileStream::GetCurrentPrincipal()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrincipal> principal;
|
||||||
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||||
|
if (!secMan || !mChannel)
|
||||||
|
return nsnull;
|
||||||
|
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
|
||||||
|
return principal.forget();
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsMediaFileStream::Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes)
|
nsresult nsMediaFileStream::Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes)
|
||||||
{
|
{
|
||||||
nsAutoLock lock(mLock);
|
nsAutoLock lock(mLock);
|
||||||
|
@ -831,18 +900,6 @@ nsMediaStream::Open(nsMediaDecoder* aDecoder, nsIURI* aURI,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIPrincipal> nsMediaStream::GetCurrentPrincipal()
|
|
||||||
{
|
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
|
||||||
|
|
||||||
nsCOMPtr<nsIPrincipal> principal;
|
|
||||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
|
||||||
if (!secMan || !mChannel)
|
|
||||||
return nsnull;
|
|
||||||
secMan->GetChannelPrincipal(mChannel, getter_AddRefs(principal));
|
|
||||||
return principal.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsMediaStream::MoveLoadsToBackground() {
|
void nsMediaStream::MoveLoadsToBackground() {
|
||||||
NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
|
NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
|
||||||
mLoadInBackground = PR_TRUE;
|
mLoadInBackground = PR_TRUE;
|
||||||
|
|
|
@ -157,11 +157,8 @@ public:
|
||||||
// Write the audio data from the frame to the Audio stream.
|
// Write the audio data from the frame to the Audio stream.
|
||||||
void Write(nsAudioStream* aStream)
|
void Write(nsAudioStream* aStream)
|
||||||
{
|
{
|
||||||
PRUint32 length = mAudioData.Length();
|
aStream->Write(mAudioData.Elements(), mAudioData.Length());
|
||||||
if (length == 0)
|
mAudioData.Clear();
|
||||||
return;
|
|
||||||
|
|
||||||
aStream->Write(mAudioData.Elements(), length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetVideoHeader(OggPlayDataHeader* aVideoHeader)
|
void SetVideoHeader(OggPlayDataHeader* aVideoHeader)
|
||||||
|
@ -230,6 +227,20 @@ public:
|
||||||
return !mEmpty && mHead == mTail;
|
return !mEmpty && mHead == mTail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ResetTimes(float aPeriod)
|
||||||
|
{
|
||||||
|
float time = 0.0;
|
||||||
|
if (!mEmpty) {
|
||||||
|
PRInt32 current = mHead;
|
||||||
|
do {
|
||||||
|
mQueue[current]->mTime = time;
|
||||||
|
time += aPeriod;
|
||||||
|
current = (current + 1) % OGGPLAY_BUFFER_SIZE;
|
||||||
|
} while (current != mTail);
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameData* mQueue[OGGPLAY_BUFFER_SIZE];
|
FrameData* mQueue[OGGPLAY_BUFFER_SIZE];
|
||||||
PRInt32 mHead;
|
PRInt32 mHead;
|
||||||
|
@ -292,8 +303,11 @@ public:
|
||||||
// must be locked when calling this method.
|
// must be locked when calling this method.
|
||||||
void PlayVideo(FrameData* aFrame);
|
void PlayVideo(FrameData* aFrame);
|
||||||
|
|
||||||
// Play the audio data from the given frame. The decode monitor must
|
// Plays the audio for the frame, plus any outstanding audio data
|
||||||
// be locked when calling this method.
|
// buffered by nsAudioStream and not yet written to the
|
||||||
|
// hardware. The audio data for the frame is cleared out so
|
||||||
|
// subsequent calls with the same frame do not re-write the data.
|
||||||
|
// The decode monitor must be locked when calling this method.
|
||||||
void PlayAudio(FrameData* aFrame);
|
void PlayAudio(FrameData* aFrame);
|
||||||
|
|
||||||
// Called from the main thread to get the current frame time. The decoder
|
// Called from the main thread to get the current frame time. The decoder
|
||||||
|
@ -365,11 +379,22 @@ protected:
|
||||||
void StopAudio();
|
void StopAudio();
|
||||||
|
|
||||||
// Start playback of media. Must be called with the decode monitor held.
|
// Start playback of media. Must be called with the decode monitor held.
|
||||||
|
// This opens or re-opens the audio stream for playback to start.
|
||||||
void StartPlayback();
|
void StartPlayback();
|
||||||
|
|
||||||
// Stop playback of media. Must be called with the decode monitor held.
|
// Stop playback of media. Must be called with the decode monitor held.
|
||||||
|
// This actually closes the audio stream and releases any OS resources.
|
||||||
void StopPlayback();
|
void StopPlayback();
|
||||||
|
|
||||||
|
// Pause playback of media. Must be called with the decode monitor held.
|
||||||
|
// This does not close the OS based audio stream - it suspends it to be
|
||||||
|
// resumed later.
|
||||||
|
void PausePlayback();
|
||||||
|
|
||||||
|
// Resume playback of media. Must be called with the decode monitor held.
|
||||||
|
// This resumes a paused audio stream.
|
||||||
|
void ResumePlayback();
|
||||||
|
|
||||||
// Update the playback position. This can result in a timeupdate event
|
// Update the playback position. This can result in a timeupdate event
|
||||||
// and an invalidate of the frame being dispatched asynchronously if
|
// and an invalidate of the frame being dispatched asynchronously if
|
||||||
// there is no such event currently queued.
|
// there is no such event currently queued.
|
||||||
|
@ -377,6 +402,11 @@ protected:
|
||||||
// the decode monitor held.
|
// the decode monitor held.
|
||||||
void UpdatePlaybackPosition(float aTime);
|
void UpdatePlaybackPosition(float aTime);
|
||||||
|
|
||||||
|
// Takes decoded frames from liboggplay's internal buffer and
|
||||||
|
// places them in our frame queue. Must be called with the decode
|
||||||
|
// monitor held.
|
||||||
|
void QueueDecodedFrames();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// *****
|
// *****
|
||||||
// The follow fields are only accessed by the decoder thread
|
// The follow fields are only accessed by the decoder thread
|
||||||
|
@ -753,7 +783,7 @@ void nsOggDecodeStateMachine::PlayFrame() {
|
||||||
|
|
||||||
if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
|
if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
|
||||||
if (!mPlaying) {
|
if (!mPlaying) {
|
||||||
StartPlayback();
|
ResumePlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mDecodedFrames.IsEmpty()) {
|
if (!mDecodedFrames.IsEmpty()) {
|
||||||
|
@ -769,7 +799,14 @@ void nsOggDecodeStateMachine::PlayFrame() {
|
||||||
|
|
||||||
double time;
|
double time;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
time = (TimeStamp::Now() - mPlayStartTime - mPauseDuration).ToSeconds();
|
// Even if the frame has had its audio data written we call
|
||||||
|
// PlayAudio to ensure that any data we have buffered in the
|
||||||
|
// nsAudioStream is written to the hardware.
|
||||||
|
PlayAudio(frame);
|
||||||
|
double hwtime = mAudioStream ? mAudioStream->GetPosition() : -1.0;
|
||||||
|
time = hwtime < 0.0 ?
|
||||||
|
(TimeStamp::Now() - mPlayStartTime - mPauseDuration).ToSeconds() :
|
||||||
|
hwtime;
|
||||||
if (time < frame->mTime) {
|
if (time < frame->mTime) {
|
||||||
mon.Wait(PR_MillisecondsToInterval(PRInt64((frame->mTime - time)*1000)));
|
mon.Wait(PR_MillisecondsToInterval(PRInt64((frame->mTime - time)*1000)));
|
||||||
if (mState == DECODER_STATE_SHUTDOWN)
|
if (mState == DECODER_STATE_SHUTDOWN)
|
||||||
|
@ -780,24 +817,33 @@ void nsOggDecodeStateMachine::PlayFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
mDecodedFrames.Pop();
|
mDecodedFrames.Pop();
|
||||||
|
QueueDecodedFrames();
|
||||||
|
|
||||||
// Skip frames up to the one we should be showing.
|
// Skip frames up to the one we should be showing.
|
||||||
while (!mDecodedFrames.IsEmpty() && time >= mDecodedFrames.Peek()->mTime) {
|
while (!mDecodedFrames.IsEmpty() && time >= mDecodedFrames.Peek()->mTime) {
|
||||||
LOG(PR_LOG_DEBUG, ("Skipping frame time %f with audio at time %f", mDecodedFrames.Peek()->mTime, time));
|
LOG(PR_LOG_DEBUG, ("Skipping frame time %f with audio at time %f", mDecodedFrames.Peek()->mTime, time));
|
||||||
|
PlayAudio(frame);
|
||||||
delete frame;
|
delete frame;
|
||||||
frame = mDecodedFrames.Peek();
|
frame = mDecodedFrames.Peek();
|
||||||
mDecodedFrames.Pop();
|
mDecodedFrames.Pop();
|
||||||
}
|
}
|
||||||
PlayAudio(frame);
|
if (time < frame->mTime + mCallbackPeriod) {
|
||||||
PlayVideo(frame);
|
PlayAudio(frame);
|
||||||
mDecoder->mPlaybackPosition = frame->mEndStreamPosition;
|
PlayVideo(frame);
|
||||||
UpdatePlaybackPosition(frame->mDecodedFrameTime);
|
mDecoder->mPlaybackPosition = frame->mEndStreamPosition;
|
||||||
delete frame;
|
UpdatePlaybackPosition(frame->mDecodedFrameTime);
|
||||||
|
delete frame;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PlayAudio(frame);
|
||||||
|
delete frame;
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mPlaying) {
|
if (mPlaying) {
|
||||||
StopPlayback();
|
PausePlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState == DECODER_STATE_DECODING) {
|
if (mState == DECODER_STATE_DECODING) {
|
||||||
|
@ -904,16 +950,52 @@ void nsOggDecodeStateMachine::StartPlayback()
|
||||||
// Null out mPauseStartTime
|
// Null out mPauseStartTime
|
||||||
mPauseStartTime = TimeStamp();
|
mPauseStartTime = TimeStamp();
|
||||||
}
|
}
|
||||||
|
mPlayStartTime = TimeStamp::Now();
|
||||||
|
mPauseDuration = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsOggDecodeStateMachine::StopPlayback()
|
void nsOggDecodeStateMachine::StopPlayback()
|
||||||
{
|
{
|
||||||
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "StopPlayback() called without acquiring decoder monitor");
|
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "StopPlayback() called without acquiring decoder monitor");
|
||||||
|
mLastFrameTime = mDecodedFrames.ResetTimes(mCallbackPeriod);
|
||||||
StopAudio();
|
StopAudio();
|
||||||
mPlaying = PR_FALSE;
|
mPlaying = PR_FALSE;
|
||||||
mPauseStartTime = TimeStamp::Now();
|
mPauseStartTime = TimeStamp::Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsOggDecodeStateMachine::PausePlayback()
|
||||||
|
{
|
||||||
|
if (!mAudioStream) {
|
||||||
|
StopPlayback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAudioStream->Pause();
|
||||||
|
mPlaying = PR_FALSE;
|
||||||
|
mPauseStartTime = TimeStamp::Now();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsOggDecodeStateMachine::ResumePlayback()
|
||||||
|
{
|
||||||
|
if (!mAudioStream) {
|
||||||
|
StartPlayback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAudioStream->Resume();
|
||||||
|
mPlaying = PR_TRUE;
|
||||||
|
|
||||||
|
// Compute duration spent paused
|
||||||
|
if (!mPauseStartTime.IsNull()) {
|
||||||
|
mPauseDuration += TimeStamp::Now() - mPauseStartTime;
|
||||||
|
// Null out mPauseStartTime
|
||||||
|
mPauseStartTime = TimeStamp();
|
||||||
|
}
|
||||||
|
mPlayStartTime = TimeStamp::Now();
|
||||||
|
mPauseDuration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void nsOggDecodeStateMachine::UpdatePlaybackPosition(float aTime)
|
void nsOggDecodeStateMachine::UpdatePlaybackPosition(float aTime)
|
||||||
{
|
{
|
||||||
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "UpdatePlaybackPosition() called without acquiring decoder monitor");
|
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "UpdatePlaybackPosition() called without acquiring decoder monitor");
|
||||||
|
@ -926,6 +1008,15 @@ void nsOggDecodeStateMachine::UpdatePlaybackPosition(float aTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsOggDecodeStateMachine::QueueDecodedFrames()
|
||||||
|
{
|
||||||
|
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "QueueDecodedFrames() called without acquiring decoder monitor");
|
||||||
|
FrameData* frame;
|
||||||
|
while (!mDecodedFrames.IsFull() && (frame = NextFrame())) {
|
||||||
|
mDecodedFrames.Push(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nsOggDecodeStateMachine::ClearPositionChangeFlag()
|
void nsOggDecodeStateMachine::ClearPositionChangeFlag()
|
||||||
{
|
{
|
||||||
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "ClearPositionChangeFlag() called without acquiring decoder monitor");
|
// NS_ASSERTION(PR_InMonitor(mDecoder->GetMonitor()), "ClearPositionChangeFlag() called without acquiring decoder monitor");
|
||||||
|
@ -1096,10 +1187,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
mon.Wait(PR_MillisecondsToInterval(PRInt64(mCallbackPeriod*500)));
|
mon.Wait(PR_MillisecondsToInterval(PRInt64(mCallbackPeriod*500)));
|
||||||
if (mState != DECODER_STATE_DECODING)
|
if (mState != DECODER_STATE_DECODING)
|
||||||
break;
|
break;
|
||||||
FrameData* frame = NextFrame();
|
QueueDecodedFrames();
|
||||||
if (frame) {
|
|
||||||
mDecodedFrames.Push(frame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState != DECODER_STATE_DECODING)
|
if (mState != DECODER_STATE_DECODING)
|
||||||
|
@ -1108,11 +1196,11 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
if (mDecodingCompleted) {
|
if (mDecodingCompleted) {
|
||||||
LOG(PR_LOG_DEBUG, ("Changed state from DECODING to COMPLETED"));
|
LOG(PR_LOG_DEBUG, ("Changed state from DECODING to COMPLETED"));
|
||||||
mState = DECODER_STATE_COMPLETED;
|
mState = DECODER_STATE_COMPLETED;
|
||||||
mStepDecodeThread->Shutdown();
|
|
||||||
mStepDecodeThread = nsnull;
|
|
||||||
mDecodingCompleted = PR_FALSE;
|
mDecodingCompleted = PR_FALSE;
|
||||||
mBufferExhausted = PR_FALSE;
|
mBufferExhausted = PR_FALSE;
|
||||||
mon.NotifyAll();
|
mon.NotifyAll();
|
||||||
|
mStepDecodeThread->Shutdown();
|
||||||
|
mStepDecodeThread = nsnull;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,7 +1218,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
// more data to load. Let's buffer to make sure we can play a
|
// more data to load. Let's buffer to make sure we can play a
|
||||||
// decent amount of video in the future.
|
// decent amount of video in the future.
|
||||||
if (mPlaying) {
|
if (mPlaying) {
|
||||||
StopPlayback();
|
PausePlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to tell the element that buffering has started.
|
// We need to tell the element that buffering has started.
|
||||||
|
@ -1153,7 +1241,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
|
BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
|
||||||
mState = DECODER_STATE_BUFFERING;
|
mState = DECODER_STATE_BUFFERING;
|
||||||
if (mPlaying) {
|
if (mPlaying) {
|
||||||
StopPlayback();
|
PausePlayback();
|
||||||
}
|
}
|
||||||
LOG(PR_LOG_DEBUG, ("Changed state from DECODING to BUFFERING"));
|
LOG(PR_LOG_DEBUG, ("Changed state from DECODING to BUFFERING"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1284,7 +1372,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||||
if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
|
if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
|
||||||
if (!mPlaying) {
|
if (!mPlaying) {
|
||||||
StartPlayback();
|
ResumePlayback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1296,23 +1384,18 @@ nsresult nsOggDecodeStateMachine::Run()
|
||||||
{
|
{
|
||||||
// Get all the remaining decoded frames in the liboggplay buffer and
|
// Get all the remaining decoded frames in the liboggplay buffer and
|
||||||
// place them in the frame queue.
|
// place them in the frame queue.
|
||||||
FrameData* frame;
|
QueueDecodedFrames();
|
||||||
do {
|
|
||||||
frame = NextFrame();
|
|
||||||
if (frame) {
|
|
||||||
mDecodedFrames.Push(frame);
|
|
||||||
}
|
|
||||||
} while (frame);
|
|
||||||
|
|
||||||
// Play the remaining frames in the frame queue
|
// Play the remaining frames in the frame queue
|
||||||
while (mState == DECODER_STATE_COMPLETED &&
|
while (mState == DECODER_STATE_COMPLETED &&
|
||||||
!mDecodedFrames.IsEmpty()) {
|
!mDecodedFrames.IsEmpty()) {
|
||||||
PlayFrame();
|
PlayFrame();
|
||||||
if (mState != DECODER_STATE_SHUTDOWN) {
|
if (mState == DECODER_STATE_COMPLETED) {
|
||||||
// Wait for the time of one frame so we don't tight loop
|
// Wait for the time of one frame so we don't tight loop
|
||||||
// and we need to release the monitor so timeupdate and
|
// and we need to release the monitor so timeupdate and
|
||||||
// invalidate's on the main thread can occur.
|
// invalidate's on the main thread can occur.
|
||||||
mon.Wait(PR_MillisecondsToInterval(PRInt64(mCallbackPeriod*1000)));
|
mon.Wait(PR_MillisecondsToInterval(PRInt64(mCallbackPeriod*1000)));
|
||||||
|
QueueDecodedFrames();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ _TEST_FILES = \
|
||||||
|
|
||||||
ifdef MOZ_OGG
|
ifdef MOZ_OGG
|
||||||
_TEST_FILES += \
|
_TEST_FILES += \
|
||||||
|
dynamic_redirect.sjs \
|
||||||
test_access_control.html \
|
test_access_control.html \
|
||||||
file_access_controls.html \
|
file_access_controls.html \
|
||||||
test_bug448534.html \
|
test_bug448534.html \
|
||||||
|
@ -82,6 +83,7 @@ _TEST_FILES += \
|
||||||
test_info_leak.html \
|
test_info_leak.html \
|
||||||
test_onloadedmetadata.html \
|
test_onloadedmetadata.html \
|
||||||
test_load_candidates.html \
|
test_load_candidates.html \
|
||||||
|
test_mixed_principals.html \
|
||||||
test_play.html \
|
test_play.html \
|
||||||
test_progress1.html \
|
test_progress1.html \
|
||||||
test_progress3.html \
|
test_progress3.html \
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Return seek.ogv file content for the first request with a given key.
|
||||||
|
// All subsequent requests return a redirect to a different-origin resource.
|
||||||
|
function handleRequest(request, response)
|
||||||
|
{
|
||||||
|
var key = request.queryString.match(/^key=(.*)$/);
|
||||||
|
|
||||||
|
if (getState(key[1]) == "redirect") {
|
||||||
|
var origin = request.host == "localhost" ? "example.org" : "localhost:8888";
|
||||||
|
response.setStatusLine(request.httpVersion, 303, "See Other");
|
||||||
|
response.setHeader("Location", "http://" + origin + "/tests/content/media/video/test/seek.ogv");
|
||||||
|
response.setHeader("Content-Type", "text/html");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(key[1], "redirect");
|
||||||
|
|
||||||
|
var file = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||||
|
getService(Components.interfaces.nsIProperties).
|
||||||
|
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||||
|
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
|
||||||
|
createInstance(Components.interfaces.nsIFileInputStream);
|
||||||
|
var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
|
||||||
|
createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||||
|
var paths = "tests/content/media/video/test/seek.ogv";
|
||||||
|
var split = paths.split("/");
|
||||||
|
for(var i = 0; i < split.length; ++i) {
|
||||||
|
file.append(split[i]);
|
||||||
|
}
|
||||||
|
fis.init(file, -1, -1, false);
|
||||||
|
dump("file=" + file + "\n");
|
||||||
|
bis.setInputStream(fis);
|
||||||
|
var bytes = bis.readBytes(bis.available());
|
||||||
|
response.setStatusLine(request.httpVersion, 206, "Partial Content");
|
||||||
|
response.setHeader("Content-Range", "bytes 0-" + (bytes.length - 1) + "/" + bytes.length);
|
||||||
|
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||||
|
response.setHeader("Content-Type", "video/ogg", false);
|
||||||
|
response.write(bytes, bytes.length);
|
||||||
|
bis.close();
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=489415
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 489415</title>
|
||||||
|
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489415">Mozilla Bug 489415</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
|
||||||
|
<video id="v1" autoplay onended="loaded('v1')"></video>
|
||||||
|
<video id="v2" autoplay onended="loaded('v2')"></video>
|
||||||
|
|
||||||
|
<pre id="test">
|
||||||
|
<script type="text/javascript">
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
var v1 = document.getElementById("v1");
|
||||||
|
var v2 = document.getElementById("v2");
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
function loaded(id) {
|
||||||
|
var c = document.createElement("canvas");
|
||||||
|
var ctx = c.getContext("2d");
|
||||||
|
var v = document.getElementById(id);
|
||||||
|
ctx.drawImage(v, 0, 0);
|
||||||
|
try {
|
||||||
|
c.toDataURL();
|
||||||
|
ok(false, "Failed to throw exception in toDataURL for " + id);
|
||||||
|
} catch (ex) {
|
||||||
|
ok(true, "Threw exception in toDataURL for " + id);
|
||||||
|
}
|
||||||
|
if (++count == 2) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random key. The first load with that key will return
|
||||||
|
// data, the second and subsequent loads with that key will return a redirect
|
||||||
|
// to a different origin ('localhost:8888' will be redirected to 'example.org',
|
||||||
|
// and 'example.org' will be redirected to 'localhost:8888'). We rely on the
|
||||||
|
// fact that Ogg will do a seek to the end of the resource, triggering a new
|
||||||
|
// load with the same key which will return a same-origin resource.
|
||||||
|
// Loading data from two different origins should be detected by the media
|
||||||
|
// cache and result in a null principal so that the canvas usage above fails.
|
||||||
|
var key = Math.floor(Math.random()*100000000);
|
||||||
|
|
||||||
|
// In v1, try loading from same-origin first and then getting redirected to
|
||||||
|
// another origin.
|
||||||
|
v1.src = "http://localhost:8888/tests/content/media/video/test/dynamic_redirect.sjs?key=v1_" + key;
|
||||||
|
v1.load();
|
||||||
|
|
||||||
|
// In v2, try loading cross-origin first and then getting redirected to
|
||||||
|
// our origin.
|
||||||
|
v2.src = "http://example.org/tests/content/media/video/test/dynamic_redirect.sjs?key=v2_" + key;
|
||||||
|
v2.load();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -166,16 +166,14 @@ WifiGeoPositionProvider.prototype = {
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Although we aren't using cookies, we should error on the side of not
|
// Although we aren't using cookies, we should err on the side of not
|
||||||
// saving any access tokens if the user asked us not to save cookies or
|
// saving any access tokens if the user asked us not to save cookies or
|
||||||
// has changed the lifetimePolicy. The access token in these cases is
|
// has changed the lifetimePolicy. The access token in these cases is
|
||||||
// used and valid for the life of this object (eg. between startup and
|
// used and valid for the life of this object (eg. between startup and
|
||||||
// shutdown).e
|
// shutdown).e
|
||||||
let prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
let prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||||
if (prefService.getIntPref("network.cookie.lifetimePolicy") != 0) {
|
if (prefBranch.getIntPref("network.cookie.lifetimePolicy") != 0)
|
||||||
let branch = prefService.getBranch("geo.wifi.access_token.");
|
prefBranch.deleteBranch("geo.wifi.access_token.");
|
||||||
branch.deleteBranch("");
|
|
||||||
}
|
|
||||||
|
|
||||||
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||||
os.removeObserver(this, "private-browsing");
|
os.removeObserver(this, "private-browsing");
|
||||||
|
|
|
@ -318,6 +318,8 @@ NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void)
|
||||||
|
|
||||||
if(nsIPrivateTextRange::TEXTRANGE_CARETPOSITION == textRangeType)
|
if(nsIPrivateTextRange::TEXTRANGE_CARETPOSITION == textRangeType)
|
||||||
{
|
{
|
||||||
|
NS_ASSERTION(selectionStart == selectionEnd,
|
||||||
|
"nsEditor doesn't support wide caret");
|
||||||
// Set the caret....
|
// Set the caret....
|
||||||
result = selection->Collapse(mElement,
|
result = selection->Collapse(mElement,
|
||||||
mOffset+selectionStart);
|
mOffset+selectionStart);
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
#include "cairo-analysis-surface-private.h"
|
#include "cairo-analysis-surface-private.h"
|
||||||
#include "cairo-paginated-private.h"
|
#include "cairo-paginated-private.h"
|
||||||
#include "cairo-region-private.h"
|
|
||||||
#include "cairo-meta-surface-private.h"
|
#include "cairo-meta-surface-private.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -215,7 +214,7 @@ _add_operation (cairo_analysis_surface_t *surface,
|
||||||
* region there is no benefit in emitting a native operation as
|
* region there is no benefit in emitting a native operation as
|
||||||
* the fallback image will be painted on top.
|
* the fallback image will be painted on top.
|
||||||
*/
|
*/
|
||||||
if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
|
if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
|
||||||
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
|
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
|
||||||
|
|
||||||
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
|
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
|
||||||
|
@ -226,7 +225,7 @@ _add_operation (cairo_analysis_surface_t *surface,
|
||||||
* natively supported and the backend will blend the
|
* natively supported and the backend will blend the
|
||||||
* transparency into the white background.
|
* transparency into the white background.
|
||||||
*/
|
*/
|
||||||
if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
|
if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
|
||||||
backend_status = CAIRO_STATUS_SUCCESS;
|
backend_status = CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,9 +234,7 @@ _add_operation (cairo_analysis_surface_t *surface,
|
||||||
* this region will be emitted as native operations.
|
* this region will be emitted as native operations.
|
||||||
*/
|
*/
|
||||||
surface->has_supported = TRUE;
|
surface->has_supported = TRUE;
|
||||||
status = _cairo_region_union_rect (&surface->supported_region,
|
status = cairo_region_union_rectangle (&surface->supported_region, rect);
|
||||||
&surface->supported_region,
|
|
||||||
rect);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,9 +243,7 @@ _add_operation (cairo_analysis_surface_t *surface,
|
||||||
* emitted.
|
* emitted.
|
||||||
*/
|
*/
|
||||||
surface->has_unsupported = TRUE;
|
surface->has_unsupported = TRUE;
|
||||||
status = _cairo_region_union_rect (&surface->fallback_region,
|
status = cairo_region_union_rectangle (&surface->fallback_region, rect);
|
||||||
&surface->fallback_region,
|
|
||||||
rect);
|
|
||||||
|
|
||||||
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
|
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
|
||||||
* unsupported operations to the meta surface as using
|
* unsupported operations to the meta surface as using
|
||||||
|
@ -778,14 +773,14 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
|
||||||
surface->has_supported = FALSE;
|
surface->has_supported = FALSE;
|
||||||
surface->has_unsupported = FALSE;
|
surface->has_unsupported = FALSE;
|
||||||
|
|
||||||
|
_cairo_region_init (&surface->supported_region);
|
||||||
|
_cairo_region_init (&surface->fallback_region);
|
||||||
|
|
||||||
surface->page_bbox.p1.x = 0;
|
surface->page_bbox.p1.x = 0;
|
||||||
surface->page_bbox.p1.y = 0;
|
surface->page_bbox.p1.y = 0;
|
||||||
surface->page_bbox.p2.x = 0;
|
surface->page_bbox.p2.x = 0;
|
||||||
surface->page_bbox.p2.y = 0;
|
surface->page_bbox.p2.y = 0;
|
||||||
|
|
||||||
_cairo_region_init (&surface->supported_region);
|
|
||||||
_cairo_region_init (&surface->fallback_region);
|
|
||||||
|
|
||||||
if (width == -1 && height == -1) {
|
if (width == -1 && height == -1) {
|
||||||
surface->current_clip.x = CAIRO_RECT_INT_MIN;
|
surface->current_clip.x = CAIRO_RECT_INT_MIN;
|
||||||
surface->current_clip.y = CAIRO_RECT_INT_MIN;
|
surface->current_clip.y = CAIRO_RECT_INT_MIN;
|
||||||
|
|
|
@ -125,6 +125,9 @@ _cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
|
||||||
if (required_size > INT_MAX || required_size < array->num_elements)
|
if (required_size > INT_MAX || required_size < array->num_elements)
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (required_size <= old_size)
|
if (required_size <= old_size)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -1660,6 +1660,9 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
|
||||||
if (0 == polygon->num_edges)
|
if (0 == polygon->num_edges)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
has_limits = _cairo_traps_get_limit (traps, &limit);
|
has_limits = _cairo_traps_get_limit (traps, &limit);
|
||||||
|
|
||||||
edges = stack_edges;
|
edges = stack_edges;
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include "cairo-compiler-private.h"
|
#include "cairo-compiler-private.h"
|
||||||
#include "cairo-path-fixed-private.h"
|
#include "cairo-path-fixed-private.h"
|
||||||
#include "cairo-reference-count-private.h"
|
#include "cairo-reference-count-private.h"
|
||||||
#include "cairo-region-private.h"
|
|
||||||
|
|
||||||
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
|
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
|
||||||
|
|
||||||
|
@ -78,8 +77,7 @@ struct _cairo_clip {
|
||||||
/*
|
/*
|
||||||
* A clip region that can be placed in the surface
|
* A clip region that can be placed in the surface
|
||||||
*/
|
*/
|
||||||
cairo_region_t region;
|
cairo_region_t *region;
|
||||||
cairo_bool_t has_region;
|
|
||||||
/*
|
/*
|
||||||
* If the surface supports path clipping, we store the list of
|
* If the surface supports path clipping, we store the list of
|
||||||
* clipping paths that has been set here as a linked list.
|
* clipping paths that has been set here as a linked list.
|
||||||
|
|
|
@ -64,8 +64,7 @@ _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
|
||||||
|
|
||||||
clip->serial = 0;
|
clip->serial = 0;
|
||||||
|
|
||||||
_cairo_region_init (&clip->region);
|
clip->region = NULL;
|
||||||
clip->has_region = FALSE;
|
|
||||||
|
|
||||||
clip->path = NULL;
|
clip->path = NULL;
|
||||||
}
|
}
|
||||||
|
@ -76,28 +75,29 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
|
||||||
clip->mode = other->mode;
|
clip->mode = other->mode;
|
||||||
|
|
||||||
clip->all_clipped = other->all_clipped;
|
clip->all_clipped = other->all_clipped;
|
||||||
|
|
||||||
clip->surface = cairo_surface_reference (other->surface);
|
clip->surface = cairo_surface_reference (other->surface);
|
||||||
clip->surface_rect = other->surface_rect;
|
clip->surface_rect = other->surface_rect;
|
||||||
|
|
||||||
clip->serial = other->serial;
|
clip->serial = other->serial;
|
||||||
|
|
||||||
_cairo_region_init (&clip->region);
|
if (other->region) {
|
||||||
|
|
||||||
if (other->has_region) {
|
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
|
clip->region = cairo_region_copy (other->region);
|
||||||
|
|
||||||
status = _cairo_region_copy (&clip->region, &other->region);
|
status = cairo_region_status (clip->region);
|
||||||
if (unlikely (status)) {
|
if (unlikely (status)) {
|
||||||
_cairo_region_fini (&clip->region);
|
|
||||||
cairo_surface_destroy (clip->surface);
|
cairo_surface_destroy (clip->surface);
|
||||||
|
cairo_region_destroy (clip->region);
|
||||||
|
clip->region = NULL;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
clip->has_region = TRUE;
|
|
||||||
} else {
|
} else {
|
||||||
clip->has_region = FALSE;
|
clip->region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
clip->path = _cairo_clip_path_reference (other->path);
|
clip->path = _cairo_clip_path_reference (other->path);
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
@ -114,14 +114,10 @@ _cairo_clip_reset (cairo_clip_t *clip)
|
||||||
|
|
||||||
clip->serial = 0;
|
clip->serial = 0;
|
||||||
|
|
||||||
if (clip->has_region) {
|
if (clip->region) {
|
||||||
/* _cairo_region_fini just releases the resources used but
|
cairo_region_destroy (clip->region);
|
||||||
* doesn't bother with leaving the region in a valid state.
|
|
||||||
* So _cairo_region_init has to be called afterwards. */
|
|
||||||
_cairo_region_fini (&clip->region);
|
|
||||||
_cairo_region_init (&clip->region);
|
|
||||||
|
|
||||||
clip->has_region = FALSE;
|
clip->region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cairo_clip_path_destroy (clip->path);
|
_cairo_clip_path_destroy (clip->path);
|
||||||
|
@ -178,10 +174,10 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->has_region) {
|
if (clip->region) {
|
||||||
cairo_rectangle_int_t extents;
|
cairo_rectangle_int_t extents;
|
||||||
|
|
||||||
_cairo_region_get_extents (&clip->region, &extents);
|
cairo_region_get_extents (clip->region, &extents);
|
||||||
is_empty = _cairo_rectangle_intersect (rectangle, &extents);
|
is_empty = _cairo_rectangle_intersect (rectangle, &extents);
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
@ -194,7 +190,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_status_t
|
cairo_status_t
|
||||||
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
||||||
cairo_region_t *region)
|
cairo_region_t *region)
|
||||||
{
|
{
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
@ -202,40 +198,21 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
||||||
if (!clip)
|
if (!clip)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
if (clip->all_clipped) {
|
if (clip->all_clipped)
|
||||||
cairo_region_t clip_rect;
|
return cairo_region_intersect_rectangle (region, &clip->surface_rect);
|
||||||
|
|
||||||
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
|
|
||||||
|
|
||||||
status = _cairo_region_intersect (region, &clip_rect, region);
|
|
||||||
|
|
||||||
_cairo_region_fini (&clip_rect);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clip->path) {
|
if (clip->path) {
|
||||||
/* Intersect clip path into region. */
|
/* Intersect clip path into region. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->has_region) {
|
if (clip->region) {
|
||||||
status = _cairo_region_intersect (region, &clip->region, region);
|
status = cairo_region_intersect (region, clip->region);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->surface) {
|
if (clip->surface)
|
||||||
cairo_region_t clip_rect;
|
return cairo_region_intersect_rectangle (region, &clip->surface_rect);
|
||||||
|
|
||||||
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
|
|
||||||
|
|
||||||
status = _cairo_region_intersect (region, &clip_rect, region);
|
|
||||||
|
|
||||||
_cairo_region_fini (&clip_rect);
|
|
||||||
|
|
||||||
if (unlikely (status))
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -344,7 +321,7 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
|
||||||
cairo_traps_t *traps,
|
cairo_traps_t *traps,
|
||||||
cairo_surface_t *target)
|
cairo_surface_t *target)
|
||||||
{
|
{
|
||||||
cairo_region_t region;
|
cairo_region_t *region;
|
||||||
cairo_int_status_t status;
|
cairo_int_status_t status;
|
||||||
|
|
||||||
if (clip->all_clipped)
|
if (clip->all_clipped)
|
||||||
|
@ -357,29 +334,21 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (!clip->has_region) {
|
if (clip->region) {
|
||||||
status = _cairo_region_copy (&clip->region, ®ion);
|
status = cairo_region_intersect (clip->region, region);
|
||||||
if (status == CAIRO_STATUS_SUCCESS)
|
|
||||||
clip->has_region = TRUE;
|
|
||||||
} else {
|
} else {
|
||||||
cairo_region_t intersection;
|
clip->region = cairo_region_copy (region);
|
||||||
|
|
||||||
_cairo_region_init (&intersection);
|
assert (clip->region != NULL);
|
||||||
|
|
||||||
status = _cairo_region_intersect (&intersection,
|
if ((status = cairo_region_status (clip->region)))
|
||||||
&clip->region,
|
clip->region = NULL;
|
||||||
®ion);
|
|
||||||
|
|
||||||
if (status == CAIRO_STATUS_SUCCESS)
|
|
||||||
status = _cairo_region_copy (&clip->region, &intersection);
|
|
||||||
|
|
||||||
_cairo_region_fini (&intersection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||||
_cairo_region_fini (®ion);
|
cairo_region_destroy (region);
|
||||||
|
|
||||||
if (! _cairo_region_not_empty (&clip->region))
|
if (!clip->region || cairo_region_is_empty (clip->region))
|
||||||
_cairo_clip_set_all_clipped (clip, target);
|
_cairo_clip_set_all_clipped (clip, target);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -736,10 +705,10 @@ _cairo_clip_translate (cairo_clip_t *clip,
|
||||||
if (clip->all_clipped)
|
if (clip->all_clipped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (clip->has_region) {
|
if (clip->region) {
|
||||||
_cairo_region_translate (&clip->region,
|
cairo_region_translate (clip->region,
|
||||||
_cairo_fixed_integer_part (tx),
|
_cairo_fixed_integer_part (tx),
|
||||||
_cairo_fixed_integer_part (ty));
|
_cairo_fixed_integer_part (ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->surface) {
|
if (clip->surface) {
|
||||||
|
@ -794,12 +763,10 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
|
||||||
/* We should reapply the original clip path in this case, and let
|
/* We should reapply the original clip path in this case, and let
|
||||||
* whatever the right handling is happen */
|
* whatever the right handling is happen */
|
||||||
} else {
|
} else {
|
||||||
if (other->has_region) {
|
if (other->region) {
|
||||||
status = _cairo_region_copy (&clip->region, &other->region);
|
clip->region = cairo_region_copy (other->region);
|
||||||
if (unlikely (status))
|
if (unlikely ((status = cairo_region_status (clip->region))))
|
||||||
goto BAIL;
|
goto BAIL;
|
||||||
|
|
||||||
clip->has_region = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other->surface) {
|
if (other->surface) {
|
||||||
|
@ -831,8 +798,8 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
BAIL:
|
BAIL:
|
||||||
if (clip->has_region)
|
if (clip->region)
|
||||||
_cairo_region_fini (&clip->region);
|
cairo_region_destroy (clip->region);
|
||||||
if (clip->surface)
|
if (clip->surface)
|
||||||
cairo_surface_destroy (clip->surface);
|
cairo_surface_destroy (clip->surface);
|
||||||
|
|
||||||
|
@ -873,7 +840,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
||||||
{
|
{
|
||||||
cairo_rectangle_list_t *list;
|
cairo_rectangle_list_t *list;
|
||||||
cairo_rectangle_t *rectangles = NULL;
|
cairo_rectangle_t *rectangles = NULL;
|
||||||
int n_boxes = 0;
|
int n_rects = 0;
|
||||||
|
|
||||||
if (clip->all_clipped)
|
if (clip->all_clipped)
|
||||||
goto DONE;
|
goto DONE;
|
||||||
|
@ -883,28 +850,22 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
||||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
|
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->has_region) {
|
if (clip->region) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
n_boxes = _cairo_region_num_boxes (&clip->region);
|
n_rects = cairo_region_num_rectangles (clip->region);
|
||||||
|
|
||||||
if (n_boxes) {
|
if (n_rects) {
|
||||||
rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
|
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
|
||||||
if (unlikely (rectangles == NULL)) {
|
if (unlikely (rectangles == NULL)) {
|
||||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_boxes; ++i) {
|
for (i = 0; i < n_rects; ++i) {
|
||||||
cairo_box_int_t box;
|
|
||||||
cairo_rectangle_int_t clip_rect;
|
cairo_rectangle_int_t clip_rect;
|
||||||
|
|
||||||
_cairo_region_get_box (&clip->region, i, &box);
|
cairo_region_get_rectangle (clip->region, i, &clip_rect);
|
||||||
|
|
||||||
clip_rect.x = box.p1.x;
|
|
||||||
clip_rect.y = box.p1.y;
|
|
||||||
clip_rect.width = box.p2.x - box.p1.x;
|
|
||||||
clip_rect.height = box.p2.y - box.p1.y;
|
|
||||||
|
|
||||||
if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
|
if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
|
||||||
_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
|
_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
|
||||||
|
@ -916,7 +877,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
||||||
} else {
|
} else {
|
||||||
cairo_rectangle_int_t extents;
|
cairo_rectangle_int_t extents;
|
||||||
|
|
||||||
n_boxes = 1;
|
n_rects = 1;
|
||||||
|
|
||||||
rectangles = malloc(sizeof (cairo_rectangle_t));
|
rectangles = malloc(sizeof (cairo_rectangle_t));
|
||||||
if (unlikely (rectangles == NULL)) {
|
if (unlikely (rectangles == NULL)) {
|
||||||
|
@ -943,7 +904,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
||||||
|
|
||||||
list->status = CAIRO_STATUS_SUCCESS;
|
list->status = CAIRO_STATUS_SUCCESS;
|
||||||
list->rectangles = rectangles;
|
list->rectangles = rectangles;
|
||||||
list->num_rectangles = n_boxes;
|
list->num_rectangles = n_rects;
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@
|
||||||
#define inline __inline
|
#define inline __inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(WINCE)
|
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||||
/* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
|
/* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
|
||||||
The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
|
The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
|
||||||
will never be folded into another one. Something like this might eventually
|
will never be folded into another one. Something like this might eventually
|
||||||
|
|
|
@ -37,12 +37,11 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "cairoint.h"
|
|
||||||
|
|
||||||
#if CAIRO_HAS_DDRAW_SURFACE
|
#if CAIRO_HAS_DDRAW_SURFACE
|
||||||
|
|
||||||
#include "cairo-clip-private.h"
|
#include "cairo-clip-private.h"
|
||||||
#include "cairo-ddraw-private.h"
|
#include "cairo-ddraw-private.h"
|
||||||
|
#include "cairo-region-private.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <ddraw.h>
|
#include <ddraw.h>
|
||||||
|
|
|
@ -1299,39 +1299,39 @@ _cairo_directfb_surface_set_clip_region (void *abstract_surface,
|
||||||
__FUNCTION__, surface, region);
|
__FUNCTION__, surface, region);
|
||||||
|
|
||||||
if (region) {
|
if (region) {
|
||||||
int n_boxes;
|
int n_rects;
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
surface->has_clip = TRUE;
|
surface->has_clip = TRUE;
|
||||||
|
|
||||||
n_boxes = _cairo_region_num_boxes (region);
|
n_rects = cairo_region_num_rectangles (region);
|
||||||
|
|
||||||
if (n_boxes == 0)
|
if (n_rects == 0)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
if (surface->n_clips != n_boxes) {
|
if (surface->n_clips != n_rects) {
|
||||||
if (surface->clips)
|
if (surface->clips)
|
||||||
free (surface->clips);
|
free (surface->clips);
|
||||||
|
|
||||||
surface->clips = _cairo_malloc_ab (n_boxes, sizeof (DFBRegion));
|
surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion));
|
||||||
if (!surface->clips) {
|
if (!surface->clips) {
|
||||||
surface->n_clips = 0;
|
surface->n_clips = 0;
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
surface->n_clips = n_boxes;
|
surface->n_clips = n_rects;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_boxes; i++) {
|
for (i = 0; i < n_rects; i++) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
_cairo_region_get_box (region, i, &box);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
|
||||||
surface->clips[i].x1 = box.p1.x;
|
surface->clips[i].x1 = rect.x;
|
||||||
surface->clips[i].y1 = box.p1.y;
|
surface->clips[i].y1 = rect.y;
|
||||||
surface->clips[i].x2 = box.p2.x - 1;
|
surface->clips[i].x2 = rect.x + rect.width - 1;
|
||||||
surface->clips[i].y2 = box.p2.y - 1;
|
surface->clips[i].y2 = rect.y + rect.height - 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
surface->has_clip = FALSE;
|
surface->has_clip = FALSE;
|
||||||
|
|
|
@ -418,11 +418,12 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a,
|
||||||
/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
|
/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
|
||||||
* pattern. Returns a new reference to the unscaled font.
|
* pattern. Returns a new reference to the unscaled font.
|
||||||
*/
|
*/
|
||||||
static cairo_ft_unscaled_font_t *
|
static cairo_status_t
|
||||||
_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
|
_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
|
||||||
char *filename,
|
char *filename,
|
||||||
int id,
|
int id,
|
||||||
FT_Face font_face)
|
FT_Face font_face,
|
||||||
|
cairo_ft_unscaled_font_t **out)
|
||||||
{
|
{
|
||||||
cairo_ft_unscaled_font_t key, *unscaled;
|
cairo_ft_unscaled_font_t key, *unscaled;
|
||||||
cairo_ft_unscaled_font_map_t *font_map;
|
cairo_ft_unscaled_font_map_t *font_map;
|
||||||
|
@ -430,7 +431,7 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
|
||||||
|
|
||||||
font_map = _cairo_ft_unscaled_font_map_lock ();
|
font_map = _cairo_ft_unscaled_font_map_lock ();
|
||||||
if (unlikely (font_map == NULL))
|
if (unlikely (font_map == NULL))
|
||||||
goto UNWIND;
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
_cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
|
_cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
|
||||||
|
|
||||||
|
@ -439,14 +440,13 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
|
||||||
&key.base.hash_entry);
|
&key.base.hash_entry);
|
||||||
if (unscaled != NULL) {
|
if (unscaled != NULL) {
|
||||||
_cairo_unscaled_font_reference (&unscaled->base);
|
_cairo_unscaled_font_reference (&unscaled->base);
|
||||||
_cairo_ft_unscaled_font_map_unlock ();
|
goto DONE;
|
||||||
return unscaled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise create it and insert into hash table. */
|
/* Otherwise create it and insert into hash table. */
|
||||||
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
|
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
|
||||||
if (unlikely (unscaled == NULL)) {
|
if (unlikely (unscaled == NULL)) {
|
||||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
goto UNWIND_FONT_MAP_LOCK;
|
goto UNWIND_FONT_MAP_LOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,9 +460,10 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto UNWIND_UNSCALED_FONT_INIT;
|
goto UNWIND_UNSCALED_FONT_INIT;
|
||||||
|
|
||||||
|
DONE:
|
||||||
_cairo_ft_unscaled_font_map_unlock ();
|
_cairo_ft_unscaled_font_map_unlock ();
|
||||||
|
*out = unscaled;
|
||||||
return unscaled;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
UNWIND_UNSCALED_FONT_INIT:
|
UNWIND_UNSCALED_FONT_INIT:
|
||||||
_cairo_ft_unscaled_font_fini (unscaled);
|
_cairo_ft_unscaled_font_fini (unscaled);
|
||||||
|
@ -470,39 +471,52 @@ UNWIND_UNSCALED_MALLOC:
|
||||||
free (unscaled);
|
free (unscaled);
|
||||||
UNWIND_FONT_MAP_LOCK:
|
UNWIND_FONT_MAP_LOCK:
|
||||||
_cairo_ft_unscaled_font_map_unlock ();
|
_cairo_ft_unscaled_font_map_unlock ();
|
||||||
UNWIND:
|
return status;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if CAIRO_HAS_FC_FONT
|
#if CAIRO_HAS_FC_FONT
|
||||||
static cairo_ft_unscaled_font_t *
|
static cairo_status_t
|
||||||
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
|
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern,
|
||||||
|
cairo_ft_unscaled_font_t **out)
|
||||||
{
|
{
|
||||||
FT_Face font_face = NULL;
|
FT_Face font_face = NULL;
|
||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
int id = 0;
|
int id = 0;
|
||||||
|
FcResult ret;
|
||||||
|
|
||||||
if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) == FcResultMatch)
|
ret = FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face);
|
||||||
goto DONE;
|
switch ((int) ret) {
|
||||||
|
case FcResultMatch:
|
||||||
if (FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &filename) == FcResultMatch) {
|
|
||||||
/* If FC_INDEX is not set, we just use 0 */
|
|
||||||
FcPatternGetInteger (pattern, FC_INDEX, 0, &id);
|
|
||||||
goto DONE;
|
goto DONE;
|
||||||
|
case FcResultOutOfMemory:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (FcPatternGetString (pattern, FC_FILE, 0,
|
||||||
|
(FcChar8 **) &filename) == FcResultMatch)
|
||||||
|
{
|
||||||
|
/* If FC_INDEX is not set, we just use 0 */
|
||||||
|
if (FcPatternGetInteger (pattern,
|
||||||
|
FC_INDEX, 0, &id) != FcResultOutOfMemory)
|
||||||
|
goto DONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
DONE:
|
DONE:
|
||||||
return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face);
|
return _cairo_ft_unscaled_font_create_internal (font_face != NULL,
|
||||||
|
filename, id, font_face,
|
||||||
|
out);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static cairo_ft_unscaled_font_t *
|
static cairo_status_t
|
||||||
_cairo_ft_unscaled_font_create_from_face (FT_Face face)
|
_cairo_ft_unscaled_font_create_from_face (FT_Face face,
|
||||||
|
cairo_ft_unscaled_font_t **out)
|
||||||
{
|
{
|
||||||
return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face);
|
return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2317,7 +2331,6 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
|
||||||
*scaled_font = _cairo_scaled_font_create_in_error (status);
|
*scaled_font = _cairo_scaled_font_create_in_error (status);
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -2325,11 +2338,11 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
|
||||||
ft_options = font_face->ft_options;
|
ft_options = font_face->ft_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _cairo_ft_scaled_font_create (unscaled,
|
return _cairo_ft_scaled_font_create (unscaled,
|
||||||
&font_face->base,
|
&font_face->base,
|
||||||
font_matrix, ctm,
|
font_matrix, ctm,
|
||||||
options, ft_options,
|
options, ft_options,
|
||||||
scaled_font);
|
scaled_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
|
const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
|
||||||
|
@ -2358,7 +2371,7 @@ _cairo_ft_font_face_create_for_pattern (FcPattern *pattern,
|
||||||
font_face->next = NULL;
|
font_face->next = NULL;
|
||||||
|
|
||||||
font_face->pattern = FcPatternDuplicate (pattern);
|
font_face->pattern = FcPatternDuplicate (pattern);
|
||||||
if (unlikely (pattern == NULL)) {
|
if (unlikely (font_face->pattern == NULL)) {
|
||||||
free (font_face);
|
free (font_face);
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
}
|
}
|
||||||
|
@ -2564,6 +2577,8 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
pattern = FcPatternDuplicate (pattern);
|
pattern = FcPatternDuplicate (pattern);
|
||||||
|
if (pattern == NULL)
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
|
if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
|
||||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
@ -2587,11 +2602,9 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
|
||||||
goto FREE_PATTERN;
|
goto FREE_PATTERN;
|
||||||
}
|
}
|
||||||
|
|
||||||
*unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved);
|
status = _cairo_ft_unscaled_font_create_for_pattern (resolved, unscaled);
|
||||||
if (!*unscaled) {
|
if (unlikely (status))
|
||||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
goto FREE_RESOLVED;
|
goto FREE_RESOLVED;
|
||||||
}
|
|
||||||
|
|
||||||
_get_pattern_ft_options (resolved, ft_options);
|
_get_pattern_ft_options (resolved, ft_options);
|
||||||
|
|
||||||
|
@ -2647,10 +2660,12 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
|
||||||
cairo_ft_unscaled_font_t *unscaled;
|
cairo_ft_unscaled_font_t *unscaled;
|
||||||
cairo_font_face_t *font_face;
|
cairo_font_face_t *font_face;
|
||||||
cairo_ft_options_t ft_options;
|
cairo_ft_options_t ft_options;
|
||||||
|
cairo_status_t status;
|
||||||
|
|
||||||
unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern);
|
status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled);
|
||||||
|
if (unlikely (status))
|
||||||
|
return (cairo_font_face_t *) &_cairo_font_face_nil;
|
||||||
if (unlikely (unscaled == NULL)) {
|
if (unlikely (unscaled == NULL)) {
|
||||||
cairo_status_t status;
|
|
||||||
/* Store the pattern. We will resolve it and create unscaled
|
/* Store the pattern. We will resolve it and create unscaled
|
||||||
* font when creating scaled fonts */
|
* font when creating scaled fonts */
|
||||||
status = _cairo_ft_font_face_create_for_pattern (pattern,
|
status = _cairo_ft_font_face_create_for_pattern (pattern,
|
||||||
|
@ -2722,12 +2737,11 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
|
||||||
cairo_ft_unscaled_font_t *unscaled;
|
cairo_ft_unscaled_font_t *unscaled;
|
||||||
cairo_font_face_t *font_face;
|
cairo_font_face_t *font_face;
|
||||||
cairo_ft_options_t ft_options;
|
cairo_ft_options_t ft_options;
|
||||||
|
cairo_status_t status;
|
||||||
|
|
||||||
unscaled = _cairo_ft_unscaled_font_create_from_face (face);
|
status = _cairo_ft_unscaled_font_create_from_face (face, &unscaled);
|
||||||
if (unlikely (unscaled == NULL)) {
|
if (unlikely (status))
|
||||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
return (cairo_font_face_t *)&_cairo_font_face_nil;
|
return (cairo_font_face_t *)&_cairo_font_face_nil;
|
||||||
}
|
|
||||||
|
|
||||||
ft_options.load_flags = load_flags;
|
ft_options.load_flags = load_flags;
|
||||||
ft_options.extra_flags = 0;
|
ft_options.extra_flags = 0;
|
||||||
|
|
|
@ -222,6 +222,9 @@ _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
|
||||||
cairo_gstate_t *top;
|
cairo_gstate_t *top;
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
top = *freelist;
|
top = *freelist;
|
||||||
if (top == NULL) {
|
if (top == NULL) {
|
||||||
top = malloc (sizeof (cairo_gstate_t));
|
top = malloc (sizeof (cairo_gstate_t));
|
||||||
|
|
|
@ -198,6 +198,9 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
|
||||||
cairo_hull_t *hull;
|
cairo_hull_t *hull;
|
||||||
int num_hull = *num_vertices;
|
int num_hull = *num_vertices;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (num_hull > ARRAY_LENGTH (hull_stack)) {
|
if (num_hull > ARRAY_LENGTH (hull_stack)) {
|
||||||
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
|
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
|
||||||
if (unlikely (hull == NULL))
|
if (unlikely (hull == NULL))
|
||||||
|
|
|
@ -1044,6 +1044,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
|
||||||
|
|
||||||
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
|
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
pixman_color.red = color->red_short;
|
pixman_color.red = color->red_short;
|
||||||
pixman_color.green = color->green_short;
|
pixman_color.green = color->green_short;
|
||||||
pixman_color.blue = color->blue_short;
|
pixman_color.blue = color->blue_short;
|
||||||
|
@ -1112,6 +1115,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
|
||||||
if (height == 0 || width == 0)
|
if (height == 0 || width == 0)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
/* Convert traps to pixman traps */
|
/* Convert traps to pixman traps */
|
||||||
if (num_traps > ARRAY_LENGTH (stack_traps)) {
|
if (num_traps > ARRAY_LENGTH (stack_traps)) {
|
||||||
pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
|
pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
|
||||||
|
@ -1427,7 +1433,7 @@ _cairo_image_surface_set_clip_region (void *abstract_surface,
|
||||||
{
|
{
|
||||||
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
|
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
|
||||||
|
|
||||||
if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->rgn))
|
if (! pixman_image_set_clip_region32 (surface->pixman_image, region? ®ion->rgn : NULL))
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
surface->has_clip = region != NULL;
|
surface->has_clip = region != NULL;
|
||||||
|
|
|
@ -39,6 +39,13 @@
|
||||||
|
|
||||||
#include "cairo-wideint-private.h"
|
#include "cairo-wideint-private.h"
|
||||||
|
|
||||||
|
#if HAVE_MEMFAULT
|
||||||
|
#include <memfault.h>
|
||||||
|
#define CAIRO_INJECT_FAULT() VALGRIND_INJECT_FAULT()
|
||||||
|
#else
|
||||||
|
#define CAIRO_INJECT_FAULT() 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _cairo_malloc:
|
* _cairo_malloc:
|
||||||
* @size: size in bytes
|
* @size: size in bytes
|
||||||
|
|
|
@ -123,9 +123,10 @@ cairo_status_to_string (cairo_status_t status)
|
||||||
return "invalid value for an input #cairo_font_weight_t";
|
return "invalid value for an input #cairo_font_weight_t";
|
||||||
case CAIRO_STATUS_INVALID_SIZE:
|
case CAIRO_STATUS_INVALID_SIZE:
|
||||||
return "invalid value for the size of the input (surface, pattern, etc.)";
|
return "invalid value for the size of the input (surface, pattern, etc.)";
|
||||||
|
default:
|
||||||
|
case CAIRO_STATUS_LAST_STATUS:
|
||||||
|
return "<unknown error status>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<unknown error status>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -610,7 +611,7 @@ _cairo_lround (double d)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
|
||||||
#if !WINCE
|
#if !_WIN32_WCE
|
||||||
/* tmpfile() replacement for Windows.
|
/* tmpfile() replacement for Windows.
|
||||||
*
|
*
|
||||||
* On Windows tmpfile() creates the file in the root directory. This
|
* On Windows tmpfile() creates the file in the root directory. This
|
||||||
|
@ -660,7 +661,7 @@ _cairo_win32_tmpfile (void)
|
||||||
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
#endif /* !WINCE */
|
#endif /* !_WIN32_WCE */
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
@ -703,6 +704,9 @@ _cairo_intern_string (const char **str_inout, int len)
|
||||||
cairo_intern_string_t tmpl, *istring;
|
cairo_intern_string_t tmpl, *istring;
|
||||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = strlen (str);
|
len = strlen (str);
|
||||||
tmpl.hash_entry.hash = _intern_string_hash (str, len);
|
tmpl.hash_entry.hash = _intern_string_hash (str, len);
|
||||||
|
|
|
@ -244,7 +244,7 @@ _cairo_paginated_surface_release_source_image (void *abstract_surface,
|
||||||
|
|
||||||
static cairo_int_status_t
|
static cairo_int_status_t
|
||||||
_paint_fallback_image (cairo_paginated_surface_t *surface,
|
_paint_fallback_image (cairo_paginated_surface_t *surface,
|
||||||
cairo_box_int_t *box)
|
cairo_rectangle_int_t *rect)
|
||||||
{
|
{
|
||||||
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
|
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
|
||||||
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
|
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
|
||||||
|
@ -254,10 +254,10 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
|
||||||
cairo_surface_t *image;
|
cairo_surface_t *image;
|
||||||
cairo_surface_pattern_t pattern;
|
cairo_surface_pattern_t pattern;
|
||||||
|
|
||||||
x = box->p1.x;
|
x = rect->x;
|
||||||
y = box->p1.y;
|
y = rect->y;
|
||||||
width = box->p2.x - x;
|
width = rect->width;
|
||||||
height = box->p2.y - y;
|
height = rect->height;
|
||||||
image = _cairo_paginated_surface_create_image_surface (surface,
|
image = _cairo_paginated_surface_create_image_surface (surface,
|
||||||
ceil (width * x_scale),
|
ceil (width * x_scale),
|
||||||
ceil (height * y_scale));
|
ceil (height * y_scale));
|
||||||
|
@ -365,23 +365,23 @@ _paint_page (cairo_paginated_surface_t *surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_page_fallback) {
|
if (has_page_fallback) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
surface->backend->set_paginated_mode (surface->target,
|
surface->backend->set_paginated_mode (surface->target,
|
||||||
CAIRO_PAGINATED_MODE_FALLBACK);
|
CAIRO_PAGINATED_MODE_FALLBACK);
|
||||||
|
|
||||||
box.p1.x = 0;
|
rect.x = 0;
|
||||||
box.p1.y = 0;
|
rect.y = 0;
|
||||||
box.p2.x = surface->width;
|
rect.width = surface->width;
|
||||||
box.p2.y = surface->height;
|
rect.height = surface->height;
|
||||||
status = _paint_fallback_image (surface, &box);
|
status = _paint_fallback_image (surface, &rect);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_finegrained_fallback) {
|
if (has_finegrained_fallback) {
|
||||||
cairo_region_t *region;
|
cairo_region_t *region;
|
||||||
int num_boxes, i;
|
int num_rects, i;
|
||||||
|
|
||||||
surface->backend->set_paginated_mode (surface->target,
|
surface->backend->set_paginated_mode (surface->target,
|
||||||
CAIRO_PAGINATED_MODE_FALLBACK);
|
CAIRO_PAGINATED_MODE_FALLBACK);
|
||||||
|
@ -397,13 +397,13 @@ _paint_page (cairo_paginated_surface_t *surface)
|
||||||
|
|
||||||
region = _cairo_analysis_surface_get_unsupported (analysis);
|
region = _cairo_analysis_surface_get_unsupported (analysis);
|
||||||
|
|
||||||
num_boxes = _cairo_region_num_boxes (region);
|
num_rects = cairo_region_num_rectangles (region);
|
||||||
for (i = 0; i < num_boxes; i++) {
|
for (i = 0; i < num_rects; i++) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
_cairo_region_get_box (region, i, &box);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
|
||||||
status = _paint_fallback_image (surface, &box);
|
status = _paint_fallback_image (surface, &rect);
|
||||||
|
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
|
|
|
@ -201,15 +201,19 @@ _cairo_in_fill_curve_to (void *closure,
|
||||||
if (c->y > bot) bot = c->y;
|
if (c->y > bot) bot = c->y;
|
||||||
if (d->y < top) top = d->y;
|
if (d->y < top) top = d->y;
|
||||||
if (d->y > bot) bot = d->y;
|
if (d->y > bot) bot = d->y;
|
||||||
if (bot < in_fill->y || top > in_fill->y)
|
if (bot < in_fill->y || top > in_fill->y) {
|
||||||
|
in_fill->current_point = *d;
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
left = in_fill->current_point.x;
|
left = in_fill->current_point.x;
|
||||||
if (b->x < left) left = b->x;
|
if (b->x < left) left = b->x;
|
||||||
if (c->x < left) left = c->x;
|
if (c->x < left) left = c->x;
|
||||||
if (d->x < left) left = d->x;
|
if (d->x < left) left = d->x;
|
||||||
if (left > in_fill->x)
|
if (left > in_fill->x) {
|
||||||
|
in_fill->current_point = *d;
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX Investigate direct inspection of the inflections? */
|
/* XXX Investigate direct inspection of the inflections? */
|
||||||
if (! _cairo_spline_init (&spline,
|
if (! _cairo_spline_init (&spline,
|
||||||
|
|
|
@ -1278,6 +1278,8 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
|
||||||
cairo_bool_t is_horizontal,
|
cairo_bool_t is_horizontal,
|
||||||
cairo_bool_t has_join)
|
cairo_bool_t has_join)
|
||||||
{
|
{
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (stroker->num_segments == stroker->segments_size) {
|
if (stroker->num_segments == stroker->segments_size) {
|
||||||
int new_size = stroker->segments_size * 2;
|
int new_size = stroker->segments_size * 2;
|
||||||
|
|
|
@ -119,6 +119,9 @@ static cairo_status_t
|
||||||
_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
|
_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
|
||||||
const cairo_gradient_pattern_t *other)
|
const cairo_gradient_pattern_t *other)
|
||||||
{
|
{
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
|
if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
|
||||||
{
|
{
|
||||||
cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
|
cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
|
||||||
|
@ -250,9 +253,10 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_status_t
|
cairo_status_t
|
||||||
_cairo_pattern_create_copy (cairo_pattern_t **pattern,
|
_cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
|
||||||
const cairo_pattern_t *other)
|
const cairo_pattern_t *other)
|
||||||
{
|
{
|
||||||
|
cairo_pattern_t *pattern;
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
if (other->status)
|
if (other->status)
|
||||||
|
@ -260,29 +264,32 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern,
|
||||||
|
|
||||||
switch (other->type) {
|
switch (other->type) {
|
||||||
case CAIRO_PATTERN_TYPE_SOLID:
|
case CAIRO_PATTERN_TYPE_SOLID:
|
||||||
*pattern = malloc (sizeof (cairo_solid_pattern_t));
|
pattern = malloc (sizeof (cairo_solid_pattern_t));
|
||||||
break;
|
break;
|
||||||
case CAIRO_PATTERN_TYPE_SURFACE:
|
case CAIRO_PATTERN_TYPE_SURFACE:
|
||||||
*pattern = malloc (sizeof (cairo_surface_pattern_t));
|
pattern = malloc (sizeof (cairo_surface_pattern_t));
|
||||||
break;
|
break;
|
||||||
case CAIRO_PATTERN_TYPE_LINEAR:
|
case CAIRO_PATTERN_TYPE_LINEAR:
|
||||||
*pattern = malloc (sizeof (cairo_linear_pattern_t));
|
pattern = malloc (sizeof (cairo_linear_pattern_t));
|
||||||
break;
|
break;
|
||||||
case CAIRO_PATTERN_TYPE_RADIAL:
|
case CAIRO_PATTERN_TYPE_RADIAL:
|
||||||
*pattern = malloc (sizeof (cairo_radial_pattern_t));
|
pattern = malloc (sizeof (cairo_radial_pattern_t));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED;
|
||||||
|
return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
|
||||||
}
|
}
|
||||||
if (unlikely (*pattern == NULL))
|
if (unlikely (pattern == NULL))
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
status = _cairo_pattern_init_copy (*pattern, other);
|
status = _cairo_pattern_init_copy (pattern, other);
|
||||||
if (unlikely (status)) {
|
if (unlikely (status)) {
|
||||||
free (*pattern);
|
free (pattern);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAIRO_REFERENCE_COUNT_INIT (&(*pattern)->ref_count, 1);
|
CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
|
||||||
|
*pattern_out = pattern;
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,6 +844,9 @@ _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
assert (pattern->n_stops <= pattern->stops_size);
|
assert (pattern->n_stops <= pattern->stops_size);
|
||||||
|
|
||||||
if (pattern->stops == pattern->stops_embedded) {
|
if (pattern->stops == pattern->stops_embedded) {
|
||||||
|
@ -1253,6 +1263,9 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
|
||||||
int clone_offset_x, clone_offset_y;
|
int clone_offset_x, clone_offset_y;
|
||||||
cairo_matrix_t matrix = pattern->base.matrix;
|
cairo_matrix_t matrix = pattern->base.matrix;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
|
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
|
||||||
pixman_stops = _cairo_malloc_ab (pattern->n_stops,
|
pixman_stops = _cairo_malloc_ab (pattern->n_stops,
|
||||||
sizeof(pixman_gradient_stop_t));
|
sizeof(pixman_gradient_stop_t));
|
||||||
|
|
|
@ -1015,18 +1015,21 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
|
||||||
static cairo_status_t
|
static cairo_status_t
|
||||||
_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
|
_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
|
||||||
{
|
{
|
||||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
cairo_status_t status;
|
||||||
long length;
|
long length;
|
||||||
|
|
||||||
if (! surface->pdf_stream.active)
|
if (! surface->pdf_stream.active)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
|
||||||
if (unlikely (status))
|
|
||||||
return status;
|
|
||||||
|
|
||||||
if (surface->pdf_stream.compressed) {
|
if (surface->pdf_stream.compressed) {
|
||||||
status = _cairo_output_stream_destroy (surface->output);
|
cairo_status_t status2;
|
||||||
|
|
||||||
|
status2 = _cairo_output_stream_destroy (surface->output);
|
||||||
|
if (likely (status == CAIRO_STATUS_SUCCESS))
|
||||||
|
status = status2;
|
||||||
|
|
||||||
surface->output = surface->pdf_stream.old_output;
|
surface->output = surface->pdf_stream.old_output;
|
||||||
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
_cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output);
|
||||||
surface->pdf_stream.old_output = NULL;
|
surface->pdf_stream.old_output = NULL;
|
||||||
|
@ -1051,7 +1054,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
|
||||||
|
|
||||||
surface->pdf_stream.active = FALSE;
|
surface->pdf_stream.active = FALSE;
|
||||||
|
|
||||||
if (status == CAIRO_STATUS_SUCCESS)
|
if (likely (status == CAIRO_STATUS_SUCCESS))
|
||||||
status = _cairo_output_stream_get_status (surface->output);
|
status = _cairo_output_stream_get_status (surface->output);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -1324,10 +1327,12 @@ _cairo_pdf_surface_finish (void *abstract_surface)
|
||||||
"%%%%EOF\n",
|
"%%%%EOF\n",
|
||||||
offset);
|
offset);
|
||||||
|
|
||||||
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
|
|
||||||
/* pdf_operators has already been flushed when the last stream was
|
/* pdf_operators has already been flushed when the last stream was
|
||||||
* closed so we should never be writing anything here. */
|
* closed so we should never be writing anything here - however,
|
||||||
assert(status2 == CAIRO_STATUS_SUCCESS);
|
* the stream may itself be in an error state. */
|
||||||
|
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
|
||||||
|
if (status == CAIRO_STATUS_SUCCESS)
|
||||||
|
status = status2;
|
||||||
|
|
||||||
/* close any active streams still open due to fatal errors */
|
/* close any active streams still open due to fatal errors */
|
||||||
status2 = _cairo_pdf_surface_close_stream (surface);
|
status2 = _cairo_pdf_surface_close_stream (surface);
|
||||||
|
@ -1723,6 +1728,8 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
|
||||||
|
|
||||||
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
|
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
|
||||||
&mime_data, &mime_data_length);
|
&mime_data, &mime_data_length);
|
||||||
|
if (unlikely (source->status))
|
||||||
|
return source->status;
|
||||||
if (mime_data == NULL)
|
if (mime_data == NULL)
|
||||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
@ -1790,7 +1797,7 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
|
||||||
|
|
||||||
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
|
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto BAIL;
|
return status;
|
||||||
|
|
||||||
pad_image = &image->base;
|
pad_image = &image->base;
|
||||||
if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
|
if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
|
||||||
|
@ -1840,10 +1847,10 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
|
||||||
*origin_x = x;
|
*origin_x = x;
|
||||||
*origin_y = y;
|
*origin_y = y;
|
||||||
|
|
||||||
|
BAIL:
|
||||||
if (pad_image != &image->base)
|
if (pad_image != &image->base)
|
||||||
cairo_surface_destroy (pad_image);
|
cairo_surface_destroy (pad_image);
|
||||||
|
|
||||||
BAIL:
|
|
||||||
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
|
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -3927,6 +3934,11 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su
|
||||||
null_stream,
|
null_stream,
|
||||||
_cairo_pdf_emit_imagemask,
|
_cairo_pdf_emit_imagemask,
|
||||||
surface->font_subsets);
|
surface->font_subsets);
|
||||||
|
if (unlikely (type3_surface->status)) {
|
||||||
|
status2 = _cairo_output_stream_destroy (null_stream);
|
||||||
|
return type3_surface->status;
|
||||||
|
}
|
||||||
|
|
||||||
_cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
|
_cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
|
||||||
_cairo_pdf_surface_add_font,
|
_cairo_pdf_surface_add_font,
|
||||||
surface);
|
surface);
|
||||||
|
@ -3983,6 +3995,12 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
|
||||||
NULL,
|
NULL,
|
||||||
_cairo_pdf_emit_imagemask,
|
_cairo_pdf_emit_imagemask,
|
||||||
surface->font_subsets);
|
surface->font_subsets);
|
||||||
|
if (unlikely (type3_surface->status)) {
|
||||||
|
free (glyphs);
|
||||||
|
free (widths);
|
||||||
|
return type3_surface->status;
|
||||||
|
}
|
||||||
|
|
||||||
_cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
|
_cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
|
||||||
_cairo_pdf_surface_add_font,
|
_cairo_pdf_surface_add_font,
|
||||||
surface);
|
surface);
|
||||||
|
|
|
@ -55,6 +55,9 @@ _cairo_pen_init (cairo_pen_t *pen,
|
||||||
int i;
|
int i;
|
||||||
int reflect;
|
int reflect;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
pen->radius = radius;
|
pen->radius = radius;
|
||||||
pen->tolerance = tolerance;
|
pen->tolerance = tolerance;
|
||||||
|
|
||||||
|
@ -109,6 +112,9 @@ _cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other)
|
||||||
{
|
{
|
||||||
*pen = *other;
|
*pen = *other;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
pen->vertices = pen->vertices_embedded;
|
pen->vertices = pen->vertices_embedded;
|
||||||
if (pen->num_vertices) {
|
if (pen->num_vertices) {
|
||||||
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
|
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
|
||||||
|
@ -132,6 +138,9 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
|
||||||
int num_vertices;
|
int num_vertices;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
num_vertices = pen->num_vertices + num_points;
|
num_vertices = pen->num_vertices + num_points;
|
||||||
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
|
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
|
||||||
pen->vertices != pen->vertices_embedded)
|
pen->vertices != pen->vertices_embedded)
|
||||||
|
|
|
@ -64,6 +64,11 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
|
||||||
int old_size = polygon->edges_size;
|
int old_size = polygon->edges_size;
|
||||||
int new_size = 4 * old_size;
|
int new_size = 4 * old_size;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ()) {
|
||||||
|
polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (polygon->edges == polygon->edges_embedded) {
|
if (polygon->edges == polygon->edges_embedded) {
|
||||||
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
|
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
|
||||||
if (new_edges != NULL)
|
if (new_edges != NULL)
|
||||||
|
|
|
@ -2138,6 +2138,8 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
|
||||||
|
|
||||||
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
|
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
|
||||||
&mime_data, &mime_data_length);
|
&mime_data, &mime_data_length);
|
||||||
|
if (unlikely (source->status))
|
||||||
|
return source->status;
|
||||||
if (mime_data == NULL)
|
if (mime_data == NULL)
|
||||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
@ -3315,6 +3317,9 @@ _cairo_ps_surface_stroke (void *abstract_surface,
|
||||||
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (unlikely (status))
|
||||||
|
return status;
|
||||||
|
|
||||||
return _cairo_pdf_operators_stroke (&surface->pdf_operators,
|
return _cairo_pdf_operators_stroke (&surface->pdf_operators,
|
||||||
path,
|
path,
|
||||||
style,
|
style,
|
||||||
|
|
|
@ -33,55 +33,64 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Owen Taylor <otaylor@redhat.com>
|
* Owen Taylor <otaylor@redhat.com>
|
||||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||||
|
* Søren Sandmann <sandmann@daimi.au.dk>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cairoint.h"
|
#include "cairoint.h"
|
||||||
|
|
||||||
|
static const cairo_region_t _cairo_region_nil = {
|
||||||
|
CAIRO_STATUS_NO_MEMORY, /* status */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _cairo_region_set_error:
|
||||||
|
* @region: a region
|
||||||
|
* @status: a status value indicating an error
|
||||||
|
*
|
||||||
|
* Atomically sets region->status to @status and calls _cairo_error;
|
||||||
|
* Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
|
||||||
|
* status values.
|
||||||
|
*
|
||||||
|
* All assignments of an error status to region->status should happen
|
||||||
|
* through _cairo_region_set_error(). Note that due to the nature of
|
||||||
|
* the atomic operation, it is not safe to call this function on the
|
||||||
|
* nil objects.
|
||||||
|
*
|
||||||
|
* The purpose of this function is to allow the user to set a
|
||||||
|
* breakpoint in _cairo_error() to generate a stack trace for when the
|
||||||
|
* user causes cairo to detect an error.
|
||||||
|
*
|
||||||
|
* Return value: the error status.
|
||||||
|
**/
|
||||||
|
static cairo_status_t
|
||||||
|
_cairo_region_set_error (cairo_region_t *region,
|
||||||
|
cairo_status_t status)
|
||||||
|
{
|
||||||
|
if (! _cairo_status_is_error (status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
/* Don't overwrite an existing error. This preserves the first
|
||||||
|
* error, which is the most significant. */
|
||||||
|
_cairo_status_set_error (®ion->status, status);
|
||||||
|
|
||||||
|
return _cairo_error (status);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_cairo_region_init (cairo_region_t *region)
|
_cairo_region_init (cairo_region_t *region)
|
||||||
{
|
{
|
||||||
|
region->status = CAIRO_STATUS_SUCCESS;
|
||||||
pixman_region32_init (®ion->rgn);
|
pixman_region32_init (®ion->rgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_cairo_region_init_rect (cairo_region_t *region,
|
_cairo_region_init_rectangle (cairo_region_t *region,
|
||||||
cairo_rectangle_int_t *rect)
|
const cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
|
region->status = CAIRO_STATUS_SUCCESS;
|
||||||
pixman_region32_init_rect (®ion->rgn,
|
pixman_region32_init_rect (®ion->rgn,
|
||||||
rect->x, rect->y,
|
rectangle->x, rectangle->y,
|
||||||
rect->width, rect->height);
|
rectangle->width, rectangle->height);
|
||||||
}
|
|
||||||
|
|
||||||
cairo_int_status_t
|
|
||||||
_cairo_region_init_boxes (cairo_region_t *region,
|
|
||||||
cairo_box_int_t *boxes,
|
|
||||||
int count)
|
|
||||||
{
|
|
||||||
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
|
|
||||||
pixman_box32_t *pboxes = stack_pboxes;
|
|
||||||
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (count > ARRAY_LENGTH (stack_pboxes)) {
|
|
||||||
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
|
|
||||||
if (unlikely (pboxes == NULL))
|
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
pboxes[i].x1 = boxes[i].p1.x;
|
|
||||||
pboxes[i].y1 = boxes[i].p1.y;
|
|
||||||
pboxes[i].x2 = boxes[i].p2.x;
|
|
||||||
pboxes[i].y2 = boxes[i].p2.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! pixman_region32_init_rects (®ion->rgn, pboxes, count))
|
|
||||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
|
|
||||||
if (pboxes != stack_pboxes)
|
|
||||||
free (pboxes);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -90,108 +99,512 @@ _cairo_region_fini (cairo_region_t *region)
|
||||||
pixman_region32_fini (®ion->rgn);
|
pixman_region32_fini (®ion->rgn);
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_int_status_t
|
/**
|
||||||
_cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
|
* cairo_region_create:
|
||||||
|
*
|
||||||
|
* Allocates a new empty region object.
|
||||||
|
*
|
||||||
|
* Return value: A newly allocated #cairo_region_t. Free with
|
||||||
|
* cairo_region_destroy(). This function always returns a
|
||||||
|
* valid pointer; if memory cannot be allocated, then a special
|
||||||
|
* error object is returned where all operations on the object do nothing.
|
||||||
|
* You can check for this with cairo_region_status().
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_region_t *
|
||||||
|
cairo_region_create (void)
|
||||||
{
|
{
|
||||||
if (!pixman_region32_copy (&dst->rgn, &src->rgn))
|
cairo_region_t *region;
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
region = _cairo_malloc (sizeof (cairo_region_t));
|
||||||
|
if (region == NULL)
|
||||||
|
return (cairo_region_t *) &_cairo_region_nil;
|
||||||
|
|
||||||
|
region->status = CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
pixman_region32_init (®ion->rgn);
|
||||||
|
|
||||||
|
return region;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_create);
|
||||||
|
|
||||||
int
|
/**
|
||||||
_cairo_region_num_boxes (cairo_region_t *region)
|
* cairo_region_create_rectangle:
|
||||||
|
* @rectangle: a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Allocates a new region object containing @rectangle.
|
||||||
|
*
|
||||||
|
* Return value: A newly allocated #cairo_region_t. Free with
|
||||||
|
* cairo_region_destroy(). This function always returns a
|
||||||
|
* valid pointer; if memory cannot be allocated, then a special
|
||||||
|
* error object is returned where all operations on the object do nothing.
|
||||||
|
* You can check for this with cairo_region_status().
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_region_t *
|
||||||
|
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
|
cairo_region_t *region;
|
||||||
|
|
||||||
|
region = _cairo_malloc (sizeof (cairo_region_t));
|
||||||
|
if (region == NULL)
|
||||||
|
return (cairo_region_t *) &_cairo_region_nil;
|
||||||
|
|
||||||
|
region->status = CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
pixman_region32_init_rect (®ion->rgn,
|
||||||
|
rectangle->x, rectangle->y,
|
||||||
|
rectangle->width, rectangle->height);
|
||||||
|
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_create_rectangle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_copy:
|
||||||
|
* @original: a #cairo_region_t
|
||||||
|
*
|
||||||
|
* Allocates a new region object copying the area from @original.
|
||||||
|
*
|
||||||
|
* Return value: A newly allocated #cairo_region_t. Free with
|
||||||
|
* cairo_region_destroy(). This function always returns a
|
||||||
|
* valid pointer; if memory cannot be allocated, then a special
|
||||||
|
* error object is returned where all operations on the object do nothing.
|
||||||
|
* You can check for this with cairo_region_status().
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_region_t *
|
||||||
|
cairo_region_copy (cairo_region_t *original)
|
||||||
|
{
|
||||||
|
cairo_region_t *copy;
|
||||||
|
|
||||||
|
if (original->status)
|
||||||
|
return (cairo_region_t *) &_cairo_region_nil;
|
||||||
|
|
||||||
|
copy = cairo_region_create ();
|
||||||
|
if (copy->status)
|
||||||
|
return copy;
|
||||||
|
|
||||||
|
if (! pixman_region32_copy (©->rgn, &original->rgn)) {
|
||||||
|
cairo_region_destroy (copy);
|
||||||
|
return (cairo_region_t *) &_cairo_region_nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_copy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_destroy:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
*
|
||||||
|
* Destroys a #cairo_region_t object created with
|
||||||
|
* cairo_region_create(), cairo_region_copy(), or
|
||||||
|
* or cairo_region_create_rectangle().
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
cairo_region_destroy (cairo_region_t *region)
|
||||||
|
{
|
||||||
|
if (region == (cairo_region_t *) &_cairo_region_nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pixman_region32_fini (®ion->rgn);
|
||||||
|
free (region);
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_destroy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_num_rectangles:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
*
|
||||||
|
* Returns the number of rectangles contained in @region.
|
||||||
|
*
|
||||||
|
* Return value: The number of rectangles contained in @region.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
cairo_region_num_rectangles (cairo_region_t *region)
|
||||||
|
{
|
||||||
|
if (region->status)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return pixman_region32_n_rects (®ion->rgn);
|
return pixman_region32_n_rects (®ion->rgn);
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_num_rectangles);
|
||||||
|
|
||||||
cairo_private void
|
/**
|
||||||
_cairo_region_get_box (cairo_region_t *region,
|
* cairo_region_get_rectangle:
|
||||||
int nth_box,
|
* @region: a #cairo_region_t
|
||||||
cairo_box_int_t *box)
|
* @nth: a number indicating which rectangle should be returned
|
||||||
|
* @rectangle: return location for a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Stores the @nth rectangle from the region in @rectangle.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
cairo_region_get_rectangle (cairo_region_t *region,
|
||||||
|
int nth,
|
||||||
|
cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
pixman_box32_t *pbox;
|
pixman_box32_t *pbox;
|
||||||
|
|
||||||
pbox = pixman_region32_rectangles (®ion->rgn, NULL) + nth_box;
|
if (region->status) {
|
||||||
|
rectangle->x = rectangle->y = 0;
|
||||||
|
rectangle->width = rectangle->height = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
box->p1.x = pbox->x1;
|
pbox = pixman_region32_rectangles (®ion->rgn, NULL) + nth;
|
||||||
box->p1.y = pbox->y1;
|
|
||||||
box->p2.x = pbox->x2;
|
rectangle->x = pbox->x1;
|
||||||
box->p2.y = pbox->y2;
|
rectangle->y = pbox->y1;
|
||||||
|
rectangle->width = pbox->x2 - pbox->x1;
|
||||||
|
rectangle->height = pbox->y2 - pbox->y1;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_get_rectangle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _cairo_region_get_extents:
|
* cairo_region_get_extents:
|
||||||
* @region: a #cairo_region_t
|
* @region: a #cairo_region_t
|
||||||
* @rect: rectangle into which to store the extents
|
* @rectangle: rectangle into which to store the extents
|
||||||
*
|
*
|
||||||
* Gets the bounding box of a region as a #cairo_rectangle_int_t
|
* Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
_cairo_region_get_extents (cairo_region_t *region, cairo_rectangle_int_t *extents)
|
cairo_region_get_extents (cairo_region_t *region,
|
||||||
|
cairo_rectangle_int_t *extents)
|
||||||
{
|
{
|
||||||
pixman_box32_t *pextents = pixman_region32_extents (®ion->rgn);
|
pixman_box32_t *pextents;
|
||||||
|
|
||||||
|
if (region->status) {
|
||||||
|
extents->x = extents->y = 0;
|
||||||
|
extents->width = extents->height = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pextents = pixman_region32_extents (®ion->rgn);
|
||||||
|
|
||||||
extents->x = pextents->x1;
|
extents->x = pextents->x1;
|
||||||
extents->y = pextents->y1;
|
extents->y = pextents->y1;
|
||||||
extents->width = pextents->x2 - pextents->x1;
|
extents->width = pextents->x2 - pextents->x1;
|
||||||
extents->height = pextents->y2 - pextents->y1;
|
extents->height = pextents->y2 - pextents->y1;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_get_extents);
|
||||||
|
|
||||||
cairo_int_status_t
|
/**
|
||||||
_cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
|
* cairo_region_status:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
*
|
||||||
|
* Checks whether an error has previous occured for this
|
||||||
|
* region object.
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_status (cairo_region_t *region)
|
||||||
{
|
{
|
||||||
if (!pixman_region32_subtract (&dst->rgn, &a->rgn, &b->rgn))
|
return region->status;
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
}
|
||||||
|
slim_hidden_def (cairo_region_status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_subtract:
|
||||||
|
* @dst: a #cairo_region_t
|
||||||
|
* @other: another #cairo_region_t
|
||||||
|
*
|
||||||
|
* Subtracts @other from @dst and places the result in @dst
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other)
|
||||||
|
{
|
||||||
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
if (other->status)
|
||||||
|
return _cairo_region_set_error (dst, other->status);
|
||||||
|
|
||||||
|
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &other->rgn))
|
||||||
|
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_subtract);
|
||||||
|
|
||||||
cairo_int_status_t
|
/**
|
||||||
_cairo_region_intersect (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
|
* cairo_region_subtract_rectangle:
|
||||||
|
* @dst: a #cairo_region_t
|
||||||
|
* @rectangle: a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Subtracts @rectangle from @dst and places the result in @dst
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_subtract_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
if (!pixman_region32_intersect (&dst->rgn, &a->rgn, &b->rgn))
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
pixman_region32_t region;
|
||||||
|
|
||||||
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
pixman_region32_init_rect (®ion,
|
||||||
|
rectangle->x, rectangle->y,
|
||||||
|
rectangle->width, rectangle->height);
|
||||||
|
|
||||||
|
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion))
|
||||||
|
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
|
pixman_region32_fini (®ion);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_subtract_rectangle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_intersect:
|
||||||
|
* @dst: a #cairo_region_t
|
||||||
|
* @other: another #cairo_region_t
|
||||||
|
*
|
||||||
|
* Computes the intersection of @dst with @other and places the result in @dst
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_intersect (cairo_region_t *dst, cairo_region_t *other)
|
||||||
|
{
|
||||||
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
if (other->status)
|
||||||
|
return _cairo_region_set_error (dst, other->status);
|
||||||
|
|
||||||
|
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &other->rgn))
|
||||||
|
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_intersect);
|
||||||
|
|
||||||
cairo_int_status_t
|
/**
|
||||||
_cairo_region_union_rect (cairo_region_t *dst,
|
* cairo_region_intersect_rectangle:
|
||||||
cairo_region_t *src,
|
* @dst: a #cairo_region_t
|
||||||
cairo_rectangle_int_t *rect)
|
* @rectangle: a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Computes the intersection of @dst with @rectangle and places the
|
||||||
|
* result in @dst
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_intersect_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
if (!pixman_region32_union_rect (&dst->rgn, &src->rgn,
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
rect->x, rect->y,
|
pixman_region32_t region;
|
||||||
rect->width, rect->height))
|
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
pixman_region32_init_rect (®ion,
|
||||||
|
rectangle->x, rectangle->y,
|
||||||
|
rectangle->width, rectangle->height);
|
||||||
|
|
||||||
|
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion))
|
||||||
|
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
|
pixman_region32_fini (®ion);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_intersect_rectangle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_union:
|
||||||
|
* @dst: a #cairo_region_t
|
||||||
|
* @other: another #cairo_region_t
|
||||||
|
*
|
||||||
|
* Computes the union of @dst with @other and places the result in @dst
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_union (cairo_region_t *dst,
|
||||||
|
cairo_region_t *other)
|
||||||
|
{
|
||||||
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
if (other->status)
|
||||||
|
return _cairo_region_set_error (dst, other->status);
|
||||||
|
|
||||||
|
if (! pixman_region32_union (&dst->rgn, &dst->rgn, &other->rgn))
|
||||||
|
return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_union);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_union_rectangle:
|
||||||
|
* @dst: a #cairo_region_t
|
||||||
|
* @rectangle: a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Computes the union of @dst with @rectangle and places the result in @dst.
|
||||||
|
*
|
||||||
|
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_status_t
|
||||||
|
cairo_region_union_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle)
|
||||||
|
{
|
||||||
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
|
pixman_region32_t region;
|
||||||
|
|
||||||
|
if (dst->status)
|
||||||
|
return dst->status;
|
||||||
|
|
||||||
|
pixman_region32_init_rect (®ion,
|
||||||
|
rectangle->x, rectangle->y,
|
||||||
|
rectangle->width, rectangle->height);
|
||||||
|
|
||||||
|
if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion))
|
||||||
|
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
|
pixman_region32_fini (®ion);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_union_rectangle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_is_empty:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
*
|
||||||
|
* Checks whether @region is empty.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if @region is empty, %FALSE if it isn't.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
cairo_bool_t
|
cairo_bool_t
|
||||||
_cairo_region_not_empty (cairo_region_t *region)
|
cairo_region_is_empty (cairo_region_t *region)
|
||||||
{
|
{
|
||||||
return (cairo_bool_t) pixman_region32_not_empty (®ion->rgn);
|
if (region->status)
|
||||||
}
|
return TRUE;
|
||||||
|
|
||||||
|
return ! pixman_region32_not_empty (®ion->rgn);
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_is_empty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_translate:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
* @dx: Amount to translate in the x direction
|
||||||
|
* @dy: Amount to translate in the y direction
|
||||||
|
*
|
||||||
|
* Translates @region by (@dx, @dy).
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
void
|
void
|
||||||
_cairo_region_translate (cairo_region_t *region,
|
cairo_region_translate (cairo_region_t *region,
|
||||||
int x, int y)
|
int dx, int dy)
|
||||||
{
|
{
|
||||||
pixman_region32_translate (®ion->rgn, x, y);
|
if (region->status)
|
||||||
}
|
return;
|
||||||
|
|
||||||
pixman_region_overlap_t
|
pixman_region32_translate (®ion->rgn, dx, dy);
|
||||||
_cairo_region_contains_rectangle (cairo_region_t *region,
|
}
|
||||||
const cairo_rectangle_int_t *rect)
|
slim_hidden_def (cairo_region_translate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_contains_rectangle:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
* @rectangle: a #cairo_rectangle_int_t
|
||||||
|
*
|
||||||
|
* Checks whether @rectangle is inside, outside or partially contained
|
||||||
|
* in @region
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
|
||||||
|
* %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
|
||||||
|
* %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_region_overlap_t
|
||||||
|
cairo_region_contains_rectangle (cairo_region_t *region,
|
||||||
|
const cairo_rectangle_int_t *rectangle)
|
||||||
{
|
{
|
||||||
pixman_box32_t pbox;
|
pixman_box32_t pbox;
|
||||||
|
pixman_region_overlap_t poverlap;
|
||||||
|
|
||||||
pbox.x1 = rect->x;
|
if (region->status)
|
||||||
pbox.y1 = rect->y;
|
return CAIRO_REGION_OVERLAP_OUT;
|
||||||
pbox.x2 = rect->x + rect->width;
|
|
||||||
pbox.y2 = rect->y + rect->height;
|
|
||||||
|
|
||||||
return pixman_region32_contains_rectangle (®ion->rgn, &pbox);
|
pbox.x1 = rectangle->x;
|
||||||
|
pbox.y1 = rectangle->y;
|
||||||
|
pbox.x2 = rectangle->x + rectangle->width;
|
||||||
|
pbox.y2 = rectangle->y + rectangle->height;
|
||||||
|
|
||||||
|
poverlap = pixman_region32_contains_rectangle (®ion->rgn, &pbox);
|
||||||
|
switch (poverlap) {
|
||||||
|
default:
|
||||||
|
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
|
||||||
|
case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN;
|
||||||
|
case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
slim_hidden_def (cairo_region_contains_rectangle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cairo_region_contains_point:
|
||||||
|
* @region: a #cairo_region_t
|
||||||
|
* @x: the x coordinate of a point
|
||||||
|
* @y: the y coordinate of a point
|
||||||
|
*
|
||||||
|
* Checks whether (@x, @y) is contained in @region.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
**/
|
||||||
|
cairo_bool_t
|
||||||
|
cairo_region_contains_point (cairo_region_t *region,
|
||||||
|
int x, int y)
|
||||||
|
{
|
||||||
|
pixman_box32_t box;
|
||||||
|
|
||||||
|
if (region->status)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return pixman_region32_contains_point (®ion->rgn, x, y, &box);
|
||||||
|
}
|
||||||
|
slim_hidden_def (cairo_region_contains_point);
|
||||||
|
|
|
@ -372,13 +372,16 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_bool_t
|
static cairo_status_t
|
||||||
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
|
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
|
||||||
const char *utf8,
|
const char *utf8,
|
||||||
int utf8_len)
|
int utf8_len,
|
||||||
|
cairo_bool_t *is_mapped)
|
||||||
{
|
{
|
||||||
|
*is_mapped = FALSE;
|
||||||
|
|
||||||
if (utf8_len < 0)
|
if (utf8_len < 0)
|
||||||
return FALSE;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
|
if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
|
||||||
utf8_len--;
|
utf8_len--;
|
||||||
|
@ -389,28 +392,25 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
|
||||||
memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
|
memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
|
||||||
{
|
{
|
||||||
/* Requested utf8 mapping matches the existing mapping */
|
/* Requested utf8 mapping matches the existing mapping */
|
||||||
return TRUE;
|
*is_mapped = TRUE;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Requested utf8 mapping does not match the existing mapping */
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No existing mapping. Use the requested mapping */
|
/* No existing mapping. Use the requested mapping */
|
||||||
sub_font_glyph->utf8 = malloc (utf8_len + 1);
|
sub_font_glyph->utf8 = malloc (utf8_len + 1);
|
||||||
|
if (unlikely (sub_font_glyph->utf8 == NULL))
|
||||||
|
return CAIRO_STATUS_NO_MEMORY;
|
||||||
|
|
||||||
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
|
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
|
||||||
sub_font_glyph->utf8[utf8_len] = 0;
|
sub_font_glyph->utf8[utf8_len] = 0;
|
||||||
sub_font_glyph->utf8_len = utf8_len;
|
sub_font_glyph->utf8_len = utf8_len;
|
||||||
return TRUE;
|
*is_mapped = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No mapping was requested. */
|
return CAIRO_STATUS_SUCCESS;
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_bool_t
|
static cairo_int_status_t
|
||||||
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
|
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
|
||||||
unsigned long scaled_font_glyph_index,
|
unsigned long scaled_font_glyph_index,
|
||||||
const char *utf8,
|
const char *utf8,
|
||||||
|
@ -418,6 +418,7 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
|
||||||
cairo_scaled_font_subsets_glyph_t *subset_glyph)
|
cairo_scaled_font_subsets_glyph_t *subset_glyph)
|
||||||
{
|
{
|
||||||
cairo_sub_font_glyph_t key, *sub_font_glyph;
|
cairo_sub_font_glyph_t key, *sub_font_glyph;
|
||||||
|
cairo_int_status_t status;
|
||||||
|
|
||||||
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
|
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
|
||||||
sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
|
sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
|
||||||
|
@ -430,13 +431,15 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
|
||||||
subset_glyph->is_composite = sub_font->is_composite;
|
subset_glyph->is_composite = sub_font->is_composite;
|
||||||
subset_glyph->x_advance = sub_font_glyph->x_advance;
|
subset_glyph->x_advance = sub_font_glyph->x_advance;
|
||||||
subset_glyph->y_advance = sub_font_glyph->y_advance;
|
subset_glyph->y_advance = sub_font_glyph->y_advance;
|
||||||
subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
|
status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
|
||||||
|
utf8, utf8_len,
|
||||||
|
&subset_glyph->utf8_is_mapped);
|
||||||
subset_glyph->unicode = sub_font_glyph->unicode;
|
subset_glyph->unicode = sub_font_glyph->unicode;
|
||||||
|
|
||||||
return TRUE;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_status_t
|
static cairo_status_t
|
||||||
|
@ -524,10 +527,12 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
|
||||||
subset_glyph->is_composite = sub_font->is_composite;
|
subset_glyph->is_composite = sub_font->is_composite;
|
||||||
subset_glyph->x_advance = sub_font_glyph->x_advance;
|
subset_glyph->x_advance = sub_font_glyph->x_advance;
|
||||||
subset_glyph->y_advance = sub_font_glyph->y_advance;
|
subset_glyph->y_advance = sub_font_glyph->y_advance;
|
||||||
subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
|
status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
|
||||||
|
utf8, utf8_len,
|
||||||
|
&subset_glyph->utf8_is_mapped);
|
||||||
subset_glyph->unicode = sub_font_glyph->unicode;
|
subset_glyph->unicode = sub_font_glyph->unicode;
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -539,6 +544,10 @@ _cairo_sub_font_collect (void *entry, void *closure)
|
||||||
int i;
|
int i;
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
|
||||||
|
if (collection->status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
collection->status = sub_font->scaled_font->status;
|
||||||
if (collection->status)
|
if (collection->status)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -682,11 +691,12 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
|
||||||
sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
|
sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
|
||||||
&key.base);
|
&key.base);
|
||||||
if (sub_font != NULL) {
|
if (sub_font != NULL) {
|
||||||
if (_cairo_sub_font_lookup_glyph (sub_font,
|
status = _cairo_sub_font_lookup_glyph (sub_font,
|
||||||
scaled_font_glyph_index,
|
scaled_font_glyph_index,
|
||||||
utf8, utf8_len,
|
utf8, utf8_len,
|
||||||
subset_glyph))
|
subset_glyph);
|
||||||
return CAIRO_STATUS_SUCCESS;
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,11 +706,12 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
|
||||||
sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
|
sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
|
||||||
&key.base);
|
&key.base);
|
||||||
if (sub_font != NULL) {
|
if (sub_font != NULL) {
|
||||||
if (_cairo_sub_font_lookup_glyph (sub_font,
|
status = _cairo_sub_font_lookup_glyph (sub_font,
|
||||||
scaled_font_glyph_index,
|
scaled_font_glyph_index,
|
||||||
utf8, utf8_len,
|
utf8, utf8_len,
|
||||||
subset_glyph))
|
subset_glyph);
|
||||||
return CAIRO_STATUS_SUCCESS;
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Glyph not found. Determine whether the glyph is outline or
|
/* Glyph not found. Determine whether the glyph is outline or
|
||||||
|
@ -1021,7 +1032,7 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
|
||||||
if (utf8 && *utf8) {
|
if (utf8 && *utf8) {
|
||||||
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
|
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
return status; /* FIXME */
|
goto CLEANUP_HASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utf16_len == 1) {
|
if (utf16_len == 1) {
|
||||||
|
|
|
@ -2558,6 +2558,9 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
|
||||||
if (unlikely (scaled_font->status))
|
if (unlikely (scaled_font->status))
|
||||||
return scaled_font->status;
|
return scaled_font->status;
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check cache for glyph
|
* Check cache for glyph
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -255,6 +255,7 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
|
||||||
}
|
}
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case CAIRO_STATUS_SUCCESS:
|
case CAIRO_STATUS_SUCCESS:
|
||||||
|
case CAIRO_STATUS_LAST_STATUS:
|
||||||
ASSERT_NOT_REACHED;
|
ASSERT_NOT_REACHED;
|
||||||
break;
|
break;
|
||||||
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
|
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
|
||||||
|
@ -359,6 +360,7 @@ _cairo_span_renderer_create_in_error (cairo_status_t status)
|
||||||
}
|
}
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case CAIRO_STATUS_SUCCESS:
|
case CAIRO_STATUS_SUCCESS:
|
||||||
|
case CAIRO_STATUS_LAST_STATUS:
|
||||||
ASSERT_NOT_REACHED;
|
ASSERT_NOT_REACHED;
|
||||||
break;
|
break;
|
||||||
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
|
case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
|
||||||
|
|
|
@ -289,7 +289,7 @@ _cairo_spline_bound (cairo_spline_add_point_func_t add_point_func,
|
||||||
* 0 < (-b±√delta)/a < 1 \
|
* 0 < (-b±√delta)/a < 1 \
|
||||||
*/ \
|
*/ \
|
||||||
if (_2ab >= 0) \
|
if (_2ab >= 0) \
|
||||||
feasible = delta > b2 && delta < a*a + b2 - _2ab; \
|
feasible = delta > b2 && delta < a*a + b2 + _2ab; \
|
||||||
else if (-b / a >= 1) \
|
else if (-b / a >= 1) \
|
||||||
feasible = delta < b2 && delta > a*a + b2 + _2ab; \
|
feasible = delta < b2 && delta > a*a + b2 + _2ab; \
|
||||||
else \
|
else \
|
||||||
|
|
|
@ -52,6 +52,9 @@ cairo_status_t
|
||||||
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
|
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
|
||||||
cairo_stroke_style_t *other)
|
cairo_stroke_style_t *other)
|
||||||
{
|
{
|
||||||
|
if (CAIRO_INJECT_FAULT ())
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
|
||||||
style->line_width = other->line_width;
|
style->line_width = other->line_width;
|
||||||
style->line_cap = other->line_cap;
|
style->line_cap = other->line_cap;
|
||||||
style->line_join = other->line_join;
|
style->line_join = other->line_join;
|
||||||
|
|
|
@ -417,7 +417,7 @@ _composite_trap_region (cairo_clip_t *clip,
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
cairo_solid_pattern_t solid_pattern;
|
cairo_solid_pattern_t solid_pattern;
|
||||||
cairo_surface_pattern_t mask;
|
cairo_surface_pattern_t mask;
|
||||||
int num_rects = _cairo_region_num_boxes (trap_region);
|
int num_rects = cairo_region_num_rectangles (trap_region);
|
||||||
unsigned int clip_serial;
|
unsigned int clip_serial;
|
||||||
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
||||||
|
|
||||||
|
@ -520,10 +520,8 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
cairo_antialias_t antialias)
|
cairo_antialias_t antialias)
|
||||||
{
|
{
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
cairo_region_t trap_region;
|
cairo_region_t *trap_region = NULL;
|
||||||
cairo_region_t clear_region;
|
cairo_region_t *clear_region = NULL;
|
||||||
cairo_bool_t has_trap_region = FALSE;
|
|
||||||
cairo_bool_t has_clear_region = FALSE;
|
|
||||||
cairo_rectangle_int_t extents;
|
cairo_rectangle_int_t extents;
|
||||||
cairo_composite_traps_info_t traps_info;
|
cairo_composite_traps_info_t traps_info;
|
||||||
|
|
||||||
|
@ -535,23 +533,18 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = _cairo_traps_extract_region (traps, &trap_region);
|
status = _cairo_traps_extract_region (traps, &trap_region);
|
||||||
if (CAIRO_INT_STATUS_UNSUPPORTED == status) {
|
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||||
has_trap_region = FALSE;
|
return status;
|
||||||
} else if (status) {
|
|
||||||
return status;
|
|
||||||
} else {
|
|
||||||
has_trap_region = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_cairo_operator_bounded_by_mask (op)) {
|
if (_cairo_operator_bounded_by_mask (op)) {
|
||||||
cairo_rectangle_int_t trap_extents;
|
cairo_rectangle_int_t trap_extents;
|
||||||
|
|
||||||
if (has_trap_region) {
|
if (trap_region) {
|
||||||
status = _cairo_clip_intersect_to_region (clip, &trap_region);
|
status = _cairo_clip_intersect_to_region (clip, trap_region);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
_cairo_region_get_extents (&trap_region, &trap_extents);
|
cairo_region_get_extents (trap_region, &trap_extents);
|
||||||
} else {
|
} else {
|
||||||
cairo_box_t trap_box;
|
cairo_box_t trap_box;
|
||||||
_cairo_traps_extents (traps, &trap_box);
|
_cairo_traps_extents (traps, &trap_box);
|
||||||
|
@ -569,27 +562,30 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
} else {
|
} else {
|
||||||
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
||||||
|
|
||||||
if (has_trap_region && !clip_surface) {
|
if (trap_region && !clip_surface) {
|
||||||
/* If we optimize drawing with an unbounded operator to
|
/* If we optimize drawing with an unbounded operator to
|
||||||
* _cairo_surface_fill_rectangles() or to drawing with a
|
* _cairo_surface_fill_rectangles() or to drawing with a
|
||||||
* clip region, then we have an additional region to clear.
|
* clip region, then we have an additional region to clear.
|
||||||
*/
|
*/
|
||||||
_cairo_region_init_rect (&clear_region, &extents);
|
clear_region = cairo_region_create_rectangle (&extents);
|
||||||
|
|
||||||
has_clear_region = TRUE;
|
status = cairo_region_status (clear_region);
|
||||||
status = _cairo_clip_intersect_to_region (clip, &clear_region);
|
if (unlikely (status))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
status = _cairo_clip_intersect_to_region (clip, clear_region);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
_cairo_region_get_extents (&clear_region, &extents);
|
cairo_region_get_extents (clear_region, &extents);
|
||||||
|
|
||||||
status = _cairo_region_subtract (&clear_region, &clear_region, &trap_region);
|
status = cairo_region_subtract (clear_region, trap_region);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!_cairo_region_not_empty (&clear_region)) {
|
if (cairo_region_is_empty (clear_region)) {
|
||||||
_cairo_region_fini (&clear_region);
|
cairo_region_destroy (clear_region);
|
||||||
has_clear_region = FALSE;
|
clear_region = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = _cairo_clip_intersect_to_rectangle (clip, &extents);
|
status = _cairo_clip_intersect_to_rectangle (clip, &extents);
|
||||||
|
@ -599,7 +595,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (has_trap_region) {
|
if (trap_region) {
|
||||||
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
|
||||||
|
|
||||||
if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
|
if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
|
||||||
|
@ -613,12 +609,13 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Solid rectangles special case */
|
/* Solid rectangles special case */
|
||||||
status = _cairo_surface_fill_region (dst, op, color, &trap_region);
|
status = _cairo_surface_fill_region (dst, op, color, trap_region);
|
||||||
|
|
||||||
if (!status && has_clear_region)
|
if (!status && clear_region) {
|
||||||
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
|
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
|
||||||
CAIRO_COLOR_TRANSPARENT,
|
CAIRO_COLOR_TRANSPARENT,
|
||||||
&clear_region);
|
clear_region);
|
||||||
|
}
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -641,13 +638,13 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
* regions. In that case, we fall through.
|
* regions. In that case, we fall through.
|
||||||
*/
|
*/
|
||||||
status = _composite_trap_region (clip, src, op, dst,
|
status = _composite_trap_region (clip, src, op, dst,
|
||||||
&trap_region, &extents);
|
trap_region, &extents);
|
||||||
|
|
||||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||||
if (!status && has_clear_region)
|
if (!status && clear_region)
|
||||||
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
|
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
|
||||||
CAIRO_COLOR_TRANSPARENT,
|
CAIRO_COLOR_TRANSPARENT,
|
||||||
&clear_region);
|
clear_region);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,10 +658,10 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
||||||
&traps_info, dst, &extents);
|
&traps_info, dst, &extents);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (has_trap_region)
|
if (trap_region)
|
||||||
_cairo_region_fini (&trap_region);
|
cairo_region_destroy (trap_region);
|
||||||
if (has_clear_region)
|
if (clear_region)
|
||||||
_cairo_region_fini (&clear_region);
|
cairo_region_destroy (clear_region);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1319,7 +1319,7 @@ _wrap_image (cairo_surface_t *src,
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_image_set_component_alpha (surface->pixman_image,
|
pixman_image_set_component_alpha (surface->pixman_image,
|
||||||
pixman_image_get_component_alpha (surface->pixman_image));
|
pixman_image_get_component_alpha (image->pixman_image));
|
||||||
|
|
||||||
*out = surface;
|
*out = surface;
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
@ -1637,14 +1637,13 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
|
||||||
*
|
*
|
||||||
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
|
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
|
||||||
**/
|
**/
|
||||||
COMPILE_TIME_ASSERT (sizeof (cairo_box_int_t) <= sizeof (cairo_rectangle_int_t));
|
|
||||||
cairo_status_t
|
cairo_status_t
|
||||||
_cairo_surface_fill_region (cairo_surface_t *surface,
|
_cairo_surface_fill_region (cairo_surface_t *surface,
|
||||||
cairo_operator_t op,
|
cairo_operator_t op,
|
||||||
const cairo_color_t *color,
|
const cairo_color_t *color,
|
||||||
cairo_region_t *region)
|
cairo_region_t *region)
|
||||||
{
|
{
|
||||||
int num_boxes;
|
int num_rects;
|
||||||
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
|
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
|
||||||
cairo_rectangle_int_t *rects = stack_rects;
|
cairo_rectangle_int_t *rects = stack_rects;
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
@ -1655,12 +1654,12 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
|
||||||
|
|
||||||
assert (! surface->is_snapshot);
|
assert (! surface->is_snapshot);
|
||||||
|
|
||||||
num_boxes = _cairo_region_num_boxes (region);
|
num_rects = cairo_region_num_rectangles (region);
|
||||||
if (num_boxes == 0)
|
if (num_rects == 0)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
|
||||||
if (num_boxes > ARRAY_LENGTH (stack_rects)) {
|
if (num_rects > ARRAY_LENGTH (stack_rects)) {
|
||||||
rects = _cairo_malloc_ab (num_boxes,
|
rects = _cairo_malloc_ab (num_rects,
|
||||||
sizeof (cairo_rectangle_int_t));
|
sizeof (cairo_rectangle_int_t));
|
||||||
if (rects == NULL) {
|
if (rects == NULL) {
|
||||||
return _cairo_surface_set_error (surface,
|
return _cairo_surface_set_error (surface,
|
||||||
|
@ -1668,19 +1667,11 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_boxes; i++) {
|
for (i = 0; i < num_rects; i++)
|
||||||
cairo_box_int_t box;
|
cairo_region_get_rectangle (region, i, &rects[i]);
|
||||||
|
|
||||||
_cairo_region_get_box (region, i, &box);
|
|
||||||
|
|
||||||
rects[i].x = box.p1.x;
|
|
||||||
rects[i].y = box.p1.y;
|
|
||||||
rects[i].width = box.p2.x - rects[i].x;
|
|
||||||
rects[i].height = box.p2.y - rects[i].y;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = _cairo_surface_fill_rectangles (surface, op,
|
status = _cairo_surface_fill_rectangles (surface, op,
|
||||||
color, rects, num_boxes);
|
color, rects, num_rects);
|
||||||
|
|
||||||
if (rects != stack_rects)
|
if (rects != stack_rects)
|
||||||
free (rects);
|
free (rects);
|
||||||
|
@ -2268,10 +2259,10 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
|
||||||
cairo_status_t
|
cairo_status_t
|
||||||
_cairo_surface_set_clip_region (cairo_surface_t *surface,
|
_cairo_surface_set_clip_region (cairo_surface_t *surface,
|
||||||
cairo_region_t *region,
|
cairo_region_t *region,
|
||||||
unsigned int serial)
|
unsigned int serial)
|
||||||
{
|
{
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
if (surface->status)
|
if (surface->status)
|
||||||
return surface->status;
|
return surface->status;
|
||||||
|
|
||||||
|
@ -2448,7 +2439,7 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
|
||||||
|
|
||||||
if (surface->backend->set_clip_region != NULL)
|
if (surface->backend->set_clip_region != NULL)
|
||||||
return _cairo_surface_set_clip_region (surface,
|
return _cairo_surface_set_clip_region (surface,
|
||||||
&clip->region,
|
clip->region,
|
||||||
clip->serial);
|
clip->serial);
|
||||||
} else {
|
} else {
|
||||||
if (clip->path)
|
if (clip->path)
|
||||||
|
@ -2456,9 +2447,9 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
|
||||||
clip->path,
|
clip->path,
|
||||||
clip->serial);
|
clip->serial);
|
||||||
|
|
||||||
if (clip->has_region)
|
if (clip->region)
|
||||||
return _cairo_surface_set_clip_region (surface,
|
return _cairo_surface_set_clip_region (surface,
|
||||||
&clip->region,
|
clip->region,
|
||||||
clip->serial);
|
clip->serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2754,53 +2745,44 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
|
||||||
unsigned int height)
|
unsigned int height)
|
||||||
{
|
{
|
||||||
cairo_rectangle_int_t dst_rectangle;
|
cairo_rectangle_int_t dst_rectangle;
|
||||||
cairo_rectangle_int_t drawn_rectangle;
|
cairo_region_t *clear_region;
|
||||||
cairo_bool_t has_drawn_region = FALSE;
|
|
||||||
cairo_region_t drawn_region;
|
|
||||||
cairo_region_t clear_region;
|
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
/* The area that was drawn is the area in the destination rectangle but not within
|
/* The area that was drawn is the area in the destination rectangle but
|
||||||
* the source or the mask.
|
* not within the source or the mask.
|
||||||
*/
|
*/
|
||||||
dst_rectangle.x = dst_x;
|
dst_rectangle.x = dst_x;
|
||||||
dst_rectangle.y = dst_y;
|
dst_rectangle.y = dst_y;
|
||||||
dst_rectangle.width = width;
|
dst_rectangle.width = width;
|
||||||
dst_rectangle.height = height;
|
dst_rectangle.height = height;
|
||||||
_cairo_region_init_rect (&clear_region, &dst_rectangle);
|
|
||||||
|
|
||||||
drawn_rectangle = dst_rectangle;
|
clear_region = cairo_region_create_rectangle (&dst_rectangle);
|
||||||
|
status = clear_region->status;
|
||||||
|
if (unlikely (status))
|
||||||
|
goto CLEANUP_REGIONS;
|
||||||
|
|
||||||
if (src_rectangle) {
|
if (src_rectangle) {
|
||||||
if (! _cairo_rectangle_intersect (&drawn_rectangle, src_rectangle))
|
if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle))
|
||||||
goto EMPTY;
|
goto EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask_rectangle) {
|
if (mask_rectangle) {
|
||||||
if (! _cairo_rectangle_intersect (&drawn_rectangle, mask_rectangle))
|
if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle))
|
||||||
goto EMPTY;
|
goto EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now compute the area that is in dst_rectangle but not in drawn_rectangle
|
/* Now compute the area that is in dst but not drawn */
|
||||||
*/
|
status = cairo_region_subtract_rectangle (clear_region, &dst_rectangle);
|
||||||
_cairo_region_init_rect (&drawn_region, &drawn_rectangle);
|
|
||||||
has_drawn_region = TRUE;
|
|
||||||
|
|
||||||
status = _cairo_region_subtract (&clear_region,
|
|
||||||
&clear_region,
|
|
||||||
&drawn_region);
|
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto CLEANUP_REGIONS;
|
goto CLEANUP_REGIONS;
|
||||||
|
|
||||||
EMPTY:
|
EMPTY:
|
||||||
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
|
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
|
||||||
CAIRO_COLOR_TRANSPARENT,
|
CAIRO_COLOR_TRANSPARENT,
|
||||||
&clear_region);
|
clear_region);
|
||||||
|
|
||||||
CLEANUP_REGIONS:
|
CLEANUP_REGIONS:
|
||||||
if (has_drawn_region)
|
cairo_region_destroy (clear_region);
|
||||||
_cairo_region_fini (&drawn_region);
|
|
||||||
_cairo_region_fini (&clear_region);
|
|
||||||
|
|
||||||
return _cairo_surface_set_error (dst, status);
|
return _cairo_surface_set_error (dst, status);
|
||||||
}
|
}
|
||||||
|
@ -3034,6 +3016,7 @@ _cairo_surface_create_in_error (cairo_status_t status)
|
||||||
case CAIRO_STATUS_INVALID_STRIDE:
|
case CAIRO_STATUS_INVALID_STRIDE:
|
||||||
return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride;
|
return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride;
|
||||||
case CAIRO_STATUS_SUCCESS:
|
case CAIRO_STATUS_SUCCESS:
|
||||||
|
case CAIRO_STATUS_LAST_STATUS:
|
||||||
ASSERT_NOT_REACHED;
|
ASSERT_NOT_REACHED;
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
case CAIRO_STATUS_INVALID_RESTORE:
|
case CAIRO_STATUS_INVALID_RESTORE:
|
||||||
|
|
|
@ -1025,6 +1025,8 @@ _cairo_surface_base64_encode_png (cairo_surface_t *surface,
|
||||||
|
|
||||||
cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG,
|
cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG,
|
||||||
&mime_data, &mime_data_length);
|
&mime_data, &mime_data_length);
|
||||||
|
if (unlikely (surface->status))
|
||||||
|
return surface->status;
|
||||||
if (mime_data == NULL)
|
if (mime_data == NULL)
|
||||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,11 @@ _cairo_traps_grow (cairo_traps_t *traps)
|
||||||
cairo_trapezoid_t *new_traps;
|
cairo_trapezoid_t *new_traps;
|
||||||
int new_size = 2 * MAX (traps->traps_size, 16);
|
int new_size = 2 * MAX (traps->traps_size, 16);
|
||||||
|
|
||||||
|
if (CAIRO_INJECT_FAULT ()) {
|
||||||
|
traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (traps->traps == traps->traps_embedded) {
|
if (traps->traps == traps->traps_embedded) {
|
||||||
new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
|
new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
|
||||||
if (new_traps != NULL)
|
if (new_traps != NULL)
|
||||||
|
@ -600,7 +605,7 @@ _cairo_traps_extents (const cairo_traps_t *traps,
|
||||||
* Determines if a set of trapezoids are exactly representable as a
|
* Determines if a set of trapezoids are exactly representable as a
|
||||||
* cairo region. If so, the passed-in region is initialized to
|
* cairo region. If so, the passed-in region is initialized to
|
||||||
* the area representing the given traps. It should be finalized
|
* the area representing the given traps. It should be finalized
|
||||||
* with _cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED
|
* with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED
|
||||||
* is returned.
|
* is returned.
|
||||||
*
|
*
|
||||||
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
|
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED
|
||||||
|
@ -608,17 +613,11 @@ _cairo_traps_extents (const cairo_traps_t *traps,
|
||||||
**/
|
**/
|
||||||
cairo_int_status_t
|
cairo_int_status_t
|
||||||
_cairo_traps_extract_region (const cairo_traps_t *traps,
|
_cairo_traps_extract_region (const cairo_traps_t *traps,
|
||||||
cairo_region_t *region)
|
cairo_region_t **region)
|
||||||
{
|
{
|
||||||
cairo_box_int_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_int_t)];
|
|
||||||
cairo_box_int_t *boxes = stack_boxes;
|
|
||||||
int i, box_count;
|
|
||||||
cairo_int_status_t status;
|
cairo_int_status_t status;
|
||||||
|
cairo_region_t *r;
|
||||||
if (traps->num_traps == 0) {
|
int i;
|
||||||
_cairo_region_init (region);
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < traps->num_traps; i++) {
|
for (i = 0; i < traps->num_traps; i++) {
|
||||||
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
|
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
|
||||||
|
@ -632,16 +631,13 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (traps->num_traps > ARRAY_LENGTH (stack_boxes)) {
|
r = cairo_region_create ();
|
||||||
boxes = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_box_int_t));
|
if (unlikely (r->status))
|
||||||
|
return r->status;
|
||||||
if (unlikely (boxes == NULL))
|
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
box_count = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < traps->num_traps; i++) {
|
for (i = 0; i < traps->num_traps; i++) {
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
|
int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
|
||||||
int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
|
int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
|
||||||
int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
|
int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
|
||||||
|
@ -653,23 +649,20 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
|
||||||
if (x1 == x2 || y1 == y2)
|
if (x1 == x2 || y1 == y2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
boxes[box_count].p1.x = x1;
|
rect.x = x1;
|
||||||
boxes[box_count].p1.y = y1;
|
rect.y = y1;
|
||||||
boxes[box_count].p2.x = x2;
|
rect.width = x2 - x1;
|
||||||
boxes[box_count].p2.y = y2;
|
rect.height = y2 - y1;
|
||||||
|
|
||||||
box_count++;
|
status = cairo_region_union_rectangle (r, &rect);
|
||||||
|
if (unlikely (status)) {
|
||||||
|
cairo_region_destroy (r);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _cairo_region_init_boxes (region, boxes, box_count);
|
*region = r;
|
||||||
|
return CAIRO_STATUS_SUCCESS;
|
||||||
if (boxes != stack_boxes)
|
|
||||||
free (boxes);
|
|
||||||
|
|
||||||
if (unlikely (status))
|
|
||||||
_cairo_region_fini (region);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* moves trap points such that they become the actual corners of the trapezoid */
|
/* moves trap points such that they become the actual corners of the trapezoid */
|
||||||
|
|
|
@ -185,7 +185,7 @@ typedef struct _tt_name {
|
||||||
typedef struct _tt_composite_glyph {
|
typedef struct _tt_composite_glyph {
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
uint16_t args[7]; /* 1 to 7 arguments depending on value of flags */
|
uint16_t args[6]; /* 1 to 6 arguments depending on value of flags */
|
||||||
} tt_composite_glyph_t;
|
} tt_composite_glyph_t;
|
||||||
|
|
||||||
typedef struct _tt_glyph_data {
|
typedef struct _tt_glyph_data {
|
||||||
|
|
|
@ -105,8 +105,8 @@ check (tt_maxp_t, 32);
|
||||||
check (tt_name_record_t, 12);
|
check (tt_name_record_t, 12);
|
||||||
check (tt_name_t, 18);
|
check (tt_name_t, 18);
|
||||||
check (tt_name_t, 18);
|
check (tt_name_t, 18);
|
||||||
check (tt_composite_glyph_t, 18);
|
check (tt_composite_glyph_t, 16);
|
||||||
check (tt_glyph_data_t, 28);
|
check (tt_glyph_data_t, 26);
|
||||||
#undef check
|
#undef check
|
||||||
|
|
||||||
static cairo_status_t
|
static cairo_status_t
|
||||||
|
@ -495,7 +495,7 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
|
||||||
|
|
||||||
composite_glyph = &glyph_data->glyph;
|
composite_glyph = &glyph_data->glyph;
|
||||||
do {
|
do {
|
||||||
if ((unsigned char *)(&composite_glyph->args[1]) >= end)
|
if ((unsigned char *)(&composite_glyph->args[1]) > end)
|
||||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
flags = be16_to_cpu (composite_glyph->flags);
|
flags = be16_to_cpu (composite_glyph->flags);
|
||||||
|
@ -508,13 +508,15 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
|
||||||
num_args = 1;
|
num_args = 1;
|
||||||
if (flags & TT_ARG_1_AND_2_ARE_WORDS)
|
if (flags & TT_ARG_1_AND_2_ARE_WORDS)
|
||||||
num_args += 1;
|
num_args += 1;
|
||||||
if (flags & TT_WE_HAVE_A_SCALE)
|
|
||||||
|
if (flags & TT_WE_HAVE_A_SCALE)
|
||||||
num_args += 1;
|
num_args += 1;
|
||||||
else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE)
|
else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE)
|
||||||
num_args += 2;
|
num_args += 2;
|
||||||
else if (flags & TT_WE_HAVE_A_TWO_BY_TWO)
|
else if (flags & TT_WE_HAVE_A_TWO_BY_TWO)
|
||||||
num_args += 3;
|
num_args += 4;
|
||||||
composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]);
|
|
||||||
|
composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]);
|
||||||
} while (has_more_components);
|
} while (has_more_components);
|
||||||
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
@ -1329,8 +1331,8 @@ _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font,
|
||||||
tt_name_record_t *record;
|
tt_name_record_t *record;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
int i, j;
|
int i, j;
|
||||||
char *ps_name;
|
char *ps_name = NULL;
|
||||||
char *font_name;
|
char *font_name = NULL;
|
||||||
|
|
||||||
backend = scaled_font->backend;
|
backend = scaled_font->backend;
|
||||||
if (!backend->load_truetype_table)
|
if (!backend->load_truetype_table)
|
||||||
|
@ -1360,8 +1362,6 @@ _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font,
|
||||||
* name. It should be extended to use any suitable font name in
|
* name. It should be extended to use any suitable font name in
|
||||||
* the name table.
|
* the name table.
|
||||||
*/
|
*/
|
||||||
ps_name = NULL;
|
|
||||||
font_name = NULL;
|
|
||||||
for (i = 0; i < be16_to_cpu(name->num_records); i++) {
|
for (i = 0; i < be16_to_cpu(name->num_records); i++) {
|
||||||
record = &(name->records[i]);
|
record = &(name->records[i]);
|
||||||
if ((be16_to_cpu (record->platform) == 1) &&
|
if ((be16_to_cpu (record->platform) == 1) &&
|
||||||
|
@ -1415,6 +1415,13 @@ _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font,
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
free (name);
|
free (name);
|
||||||
|
|
||||||
|
if (ps_name != NULL)
|
||||||
|
free (ps_name);
|
||||||
|
|
||||||
|
if (font_name != NULL)
|
||||||
|
free (font_name);
|
||||||
|
|
||||||
*ps_name_out = NULL;
|
*ps_name_out = NULL;
|
||||||
*font_name_out = NULL;
|
*font_name_out = NULL;
|
||||||
|
|
||||||
|
|
|
@ -449,14 +449,14 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
|
||||||
/* four "random" bytes required by encryption algorithm */
|
/* four "random" bytes required by encryption algorithm */
|
||||||
status = _cairo_array_append_multiple (&data, zeros, 4);
|
status = _cairo_array_append_multiple (&data, zeros, 4);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto fail;
|
break;
|
||||||
|
|
||||||
status = cairo_type1_font_create_charstring (font, i,
|
status = cairo_type1_font_create_charstring (font, i,
|
||||||
font->scaled_font_subset->glyphs[i],
|
font->scaled_font_subset->glyphs[i],
|
||||||
CAIRO_CHARSTRING_TYPE1,
|
CAIRO_CHARSTRING_TYPE1,
|
||||||
&data);
|
&data);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
goto fail;
|
break;
|
||||||
|
|
||||||
charstring_encrypt (&data);
|
charstring_encrypt (&data);
|
||||||
length = _cairo_array_num_elements (&data);
|
length = _cairo_array_num_elements (&data);
|
||||||
|
@ -474,9 +474,9 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
|
||||||
length);
|
length);
|
||||||
_cairo_output_stream_printf (encrypted_output, " ND\n");
|
_cairo_output_stream_printf (encrypted_output, " ND\n");
|
||||||
}
|
}
|
||||||
|
_cairo_scaled_font_thaw_cache (font->type1_scaled_font);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
_cairo_scaled_font_thaw_cache (font->type1_scaled_font);
|
|
||||||
_cairo_array_fini (&data);
|
_cairo_array_fini (&data);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,17 @@
|
||||||
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
|
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
|
||||||
|
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
|
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
|
||||||
cairo_output_stream_t *stream,
|
cairo_output_stream_t *stream,
|
||||||
cairo_type3_glyph_surface_emit_image_t emit_image,
|
cairo_type3_glyph_surface_emit_image_t emit_image,
|
||||||
cairo_scaled_font_subsets_t *font_subsets)
|
cairo_scaled_font_subsets_t *font_subsets)
|
||||||
{
|
{
|
||||||
cairo_type3_glyph_surface_t *surface;
|
cairo_type3_glyph_surface_t *surface;
|
||||||
cairo_matrix_t invert_y_axis;
|
cairo_matrix_t invert_y_axis;
|
||||||
|
|
||||||
|
if (unlikely (stream != NULL && stream->status))
|
||||||
|
return _cairo_surface_create_in_error (stream->status);
|
||||||
|
|
||||||
surface = malloc (sizeof (cairo_type3_glyph_surface_t));
|
surface = malloc (sizeof (cairo_type3_glyph_surface_t));
|
||||||
if (unlikely (surface == NULL))
|
if (unlikely (surface == NULL))
|
||||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||||
|
@ -88,6 +91,12 @@ _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface,
|
||||||
{
|
{
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
|
|
||||||
|
/* The only image type supported by Type 3 fonts are 1-bit masks */
|
||||||
|
image = _cairo_image_surface_coerce (image, CAIRO_FORMAT_A1);
|
||||||
|
status = image->base.status;
|
||||||
|
if (unlikely (status))
|
||||||
|
return status;
|
||||||
|
|
||||||
_cairo_output_stream_printf (surface->stream,
|
_cairo_output_stream_printf (surface->stream,
|
||||||
"q %f %f %f %f %f %f cm\n",
|
"q %f %f %f %f %f %f cm\n",
|
||||||
image_matrix->xx,
|
image_matrix->xx,
|
||||||
|
@ -97,8 +106,6 @@ _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface,
|
||||||
image_matrix->x0,
|
image_matrix->x0,
|
||||||
image_matrix->y0);
|
image_matrix->y0);
|
||||||
|
|
||||||
/* The only image type supported by Type 3 fonts are 1-bit masks */
|
|
||||||
image = _cairo_image_surface_coerce (image, CAIRO_FORMAT_A1);
|
|
||||||
status = surface->emit_image (image, surface->stream);
|
status = surface->emit_image (image, surface->stream);
|
||||||
cairo_surface_destroy (&image->base);
|
cairo_surface_destroy (&image->base);
|
||||||
|
|
||||||
|
@ -278,6 +285,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
|
||||||
&scaled_font->font_matrix,
|
&scaled_font->font_matrix,
|
||||||
&new_ctm,
|
&new_ctm,
|
||||||
&scaled_font->options);
|
&scaled_font->options);
|
||||||
|
if (unlikely (font->status))
|
||||||
|
return font->status;
|
||||||
|
|
||||||
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
|
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
|
@ -375,6 +384,9 @@ _cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract
|
||||||
{
|
{
|
||||||
cairo_type3_glyph_surface_t *surface = abstract_surface;
|
cairo_type3_glyph_surface_t *surface = abstract_surface;
|
||||||
|
|
||||||
|
if (unlikely (surface->base.status))
|
||||||
|
return;
|
||||||
|
|
||||||
_cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
|
_cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
|
||||||
use_font_subset,
|
use_font_subset,
|
||||||
closure);
|
closure);
|
||||||
|
@ -389,7 +401,13 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface,
|
||||||
cairo_status_t status, status2;
|
cairo_status_t status, status2;
|
||||||
cairo_output_stream_t *null_stream;
|
cairo_output_stream_t *null_stream;
|
||||||
|
|
||||||
|
if (unlikely (surface->base.status))
|
||||||
|
return surface->base.status;
|
||||||
|
|
||||||
null_stream = _cairo_null_stream_create ();
|
null_stream = _cairo_null_stream_create ();
|
||||||
|
if (unlikely (null_stream->status))
|
||||||
|
return null_stream->status;
|
||||||
|
|
||||||
_cairo_type3_glyph_surface_set_stream (surface, null_stream);
|
_cairo_type3_glyph_surface_set_stream (surface, null_stream);
|
||||||
|
|
||||||
_cairo_scaled_font_freeze_cache (surface->scaled_font);
|
_cairo_scaled_font_freeze_cache (surface->scaled_font);
|
||||||
|
@ -442,6 +460,9 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
|
||||||
double x_advance, y_advance;
|
double x_advance, y_advance;
|
||||||
cairo_matrix_t font_matrix_inverse;
|
cairo_matrix_t font_matrix_inverse;
|
||||||
|
|
||||||
|
if (unlikely (surface->base.status))
|
||||||
|
return surface->base.status;
|
||||||
|
|
||||||
_cairo_type3_glyph_surface_set_stream (surface, stream);
|
_cairo_type3_glyph_surface_set_stream (surface, stream);
|
||||||
|
|
||||||
_cairo_scaled_font_freeze_cache (surface->scaled_font);
|
_cairo_scaled_font_freeze_cache (surface->scaled_font);
|
||||||
|
@ -492,6 +513,10 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
|
||||||
cairo_output_stream_t *mem_stream;
|
cairo_output_stream_t *mem_stream;
|
||||||
|
|
||||||
mem_stream = _cairo_memory_stream_create ();
|
mem_stream = _cairo_memory_stream_create ();
|
||||||
|
status = mem_stream->status;
|
||||||
|
if (unlikely (status))
|
||||||
|
goto FAIL;
|
||||||
|
|
||||||
_cairo_type3_glyph_surface_set_stream (surface, mem_stream);
|
_cairo_type3_glyph_surface_set_stream (surface, mem_stream);
|
||||||
|
|
||||||
_cairo_output_stream_printf (surface->stream, "q\n");
|
_cairo_output_stream_printf (surface->stream, "q\n");
|
||||||
|
@ -516,6 +541,7 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
|
||||||
if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
|
if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
|
||||||
status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);
|
status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);
|
||||||
|
|
||||||
|
FAIL:
|
||||||
_cairo_scaled_font_thaw_cache (surface->scaled_font);
|
_cairo_scaled_font_thaw_cache (surface->scaled_font);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -59,7 +59,6 @@ typedef struct _cairo_output_stream cairo_output_stream_t;
|
||||||
typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
|
typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
|
||||||
typedef struct _cairo_path_fixed cairo_path_fixed_t;
|
typedef struct _cairo_path_fixed cairo_path_fixed_t;
|
||||||
typedef struct _cairo_rectangle_int16 cairo_glyph_size_t;
|
typedef struct _cairo_rectangle_int16 cairo_glyph_size_t;
|
||||||
typedef struct _cairo_region cairo_region_t;
|
|
||||||
typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
|
typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
|
||||||
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
|
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
|
||||||
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
|
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
|
||||||
|
@ -218,43 +217,12 @@ typedef struct _cairo_trapezoid {
|
||||||
cairo_line_t left, right;
|
cairo_line_t left, right;
|
||||||
} cairo_trapezoid_t;
|
} cairo_trapezoid_t;
|
||||||
|
|
||||||
struct _cairo_rectangle_int16 {
|
typedef struct _cairo_point_int {
|
||||||
int16_t x, y;
|
int x, y;
|
||||||
uint16_t width, height;
|
} cairo_point_int_t;
|
||||||
};
|
|
||||||
|
|
||||||
struct _cairo_rectangle_int32 {
|
|
||||||
int32_t x, y;
|
|
||||||
uint32_t width, height;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _cairo_point_int16 {
|
|
||||||
int16_t x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _cairo_point_int32 {
|
|
||||||
int32_t x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if CAIRO_FIXED_BITS == 32 && CAIRO_FIXED_FRAC_BITS >= 16
|
|
||||||
typedef struct _cairo_rectangle_int16 cairo_rectangle_int_t;
|
|
||||||
typedef struct _cairo_point_int16 cairo_point_int_t;
|
|
||||||
#define CAIRO_RECT_INT_MIN (INT16_MIN >> (CAIRO_FIXED_FRAC_BITS - 16))
|
|
||||||
#define CAIRO_RECT_INT_MAX (INT16_MAX >> (CAIRO_FIXED_FRAC_BITS - 16))
|
|
||||||
#elif CAIRO_FIXED_BITS == 32
|
|
||||||
typedef struct _cairo_rectangle_int32 cairo_rectangle_int_t;
|
|
||||||
typedef struct _cairo_point_int32 cairo_point_int_t;
|
|
||||||
#define CAIRO_RECT_INT_MIN (INT32_MIN >> CAIRO_FIXED_FRAC_BITS)
|
|
||||||
#define CAIRO_RECT_INT_MAX (INT32_MAX >> CAIRO_FIXED_FRAC_BITS)
|
|
||||||
#else
|
|
||||||
#error Not sure how to pick a cairo_rectangle_int_t and cairo_point_int_t for your CAIRO_FIXED_BITS!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _cairo_box_int {
|
|
||||||
cairo_point_int_t p1;
|
|
||||||
cairo_point_int_t p2;
|
|
||||||
} cairo_box_int_t;
|
|
||||||
|
|
||||||
|
#define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS)
|
||||||
|
#define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS)
|
||||||
|
|
||||||
/* Rectangles that take part in a composite operation.
|
/* Rectangles that take part in a composite operation.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1522,36 +1522,36 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
|
||||||
/* Then combine any new region with it */
|
/* Then combine any new region with it */
|
||||||
if (region) {
|
if (region) {
|
||||||
cairo_rectangle_int_t extents;
|
cairo_rectangle_int_t extents;
|
||||||
int num_boxes;
|
int num_rects;
|
||||||
RGNDATA *data;
|
RGNDATA *data;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
RECT *rects;
|
RECT *rects;
|
||||||
int i;
|
int i;
|
||||||
HRGN gdi_region;
|
HRGN gdi_region;
|
||||||
cairo_box_int_t box0;
|
cairo_rectangle_int_t rect0;
|
||||||
|
|
||||||
/* Create a GDI region for the cairo region */
|
/* Create a GDI region for the cairo region */
|
||||||
|
|
||||||
_cairo_region_get_extents (region, &extents);
|
cairo_region_get_extents (region, &extents);
|
||||||
num_boxes = _cairo_region_num_boxes (region);
|
num_rects = cairo_region_num_rectangles (region);
|
||||||
|
|
||||||
if (num_boxes == 1)
|
if (num_rects == 1)
|
||||||
_cairo_region_get_box (region, 0, &box0);
|
cairo_region_get_rectangle (region, 0, &rect0);
|
||||||
|
|
||||||
if (num_boxes == 1 &&
|
if (num_rects == 1 &&
|
||||||
box0.p1.x == 0 &&
|
rect0.x == 0 &&
|
||||||
box0.p1.y == 0 &&
|
rect0.y == 0 &&
|
||||||
box0.p2.x == surface->extents.width &&
|
rect0.width == surface->extents.width &&
|
||||||
box0.p2.y == surface->extents.height)
|
rect0.width == surface->extents.height)
|
||||||
{
|
{
|
||||||
gdi_region = NULL;
|
gdi_region = NULL;
|
||||||
|
|
||||||
SelectClipRgn (surface->dc, NULL);
|
SelectClipRgn (surface->dc, NULL);
|
||||||
IntersectClipRect (surface->dc,
|
IntersectClipRect (surface->dc,
|
||||||
box0.p1.x,
|
rect0.x,
|
||||||
box0.p1.y,
|
rect0.y,
|
||||||
box0.p2.x,
|
rect0.x + rect0.width,
|
||||||
box0.p2.y);
|
rect0.y + rect0.height);
|
||||||
} else {
|
} else {
|
||||||
/* XXX see notes in _cairo_win32_save_initial_clip --
|
/* XXX see notes in _cairo_win32_save_initial_clip --
|
||||||
* this code will interact badly with a HDC which had an initial
|
* this code will interact badly with a HDC which had an initial
|
||||||
|
@ -1560,7 +1560,7 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
|
||||||
* logical units (unlike IntersectClipRect).
|
* logical units (unlike IntersectClipRect).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
|
data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
|
||||||
data = malloc (data_size);
|
data = malloc (data_size);
|
||||||
if (!data)
|
if (!data)
|
||||||
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
|
||||||
|
@ -1568,22 +1568,22 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
|
||||||
|
|
||||||
data->rdh.dwSize = sizeof (RGNDATAHEADER);
|
data->rdh.dwSize = sizeof (RGNDATAHEADER);
|
||||||
data->rdh.iType = RDH_RECTANGLES;
|
data->rdh.iType = RDH_RECTANGLES;
|
||||||
data->rdh.nCount = num_boxes;
|
data->rdh.nCount = num_rects;
|
||||||
data->rdh.nRgnSize = num_boxes * sizeof (RECT);
|
data->rdh.nRgnSize = num_rects * sizeof (RECT);
|
||||||
data->rdh.rcBound.left = extents.x;
|
data->rdh.rcBound.left = extents.x;
|
||||||
data->rdh.rcBound.top = extents.y;
|
data->rdh.rcBound.top = extents.y;
|
||||||
data->rdh.rcBound.right = extents.x + extents.width;
|
data->rdh.rcBound.right = extents.x + extents.width;
|
||||||
data->rdh.rcBound.bottom = extents.y + extents.height;
|
data->rdh.rcBound.bottom = extents.y + extents.height;
|
||||||
|
|
||||||
for (i = 0; i < num_boxes; i++) {
|
for (i = 0; i < num_rects; i++) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
_cairo_region_get_box (region, i, &box);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
|
||||||
rects[i].left = box.p1.x;
|
rects[i].left = rect.x;
|
||||||
rects[i].top = box.p1.y;
|
rects[i].top = rect.y;
|
||||||
rects[i].right = box.p2.x;
|
rects[i].right = rect.x + rect.width;
|
||||||
rects[i].bottom = box.p2.y;
|
rects[i].bottom = rect.y + rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdi_region = ExtCreateRegion (NULL, data_size, data);
|
gdi_region = ExtCreateRegion (NULL, data_size, data);
|
||||||
|
|
|
@ -1557,32 +1557,32 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
|
||||||
} else {
|
} else {
|
||||||
cairo_status_t status;
|
cairo_status_t status;
|
||||||
xcb_rectangle_t *rects = NULL;
|
xcb_rectangle_t *rects = NULL;
|
||||||
int n_boxes, i;
|
int n_rects, i;
|
||||||
|
|
||||||
n_boxes = _cairo_region_num_boxes (region);
|
n_rects = cairo_region_num_rectangles (region);
|
||||||
|
|
||||||
if (n_boxes > 0) {
|
if (n_rects > 0) {
|
||||||
rects = _cairo_malloc_ab (n_boxes, sizeof(xcb_rectangle_t));
|
rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
|
||||||
if (rects == NULL)
|
if (rects == NULL)
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
} else {
|
} else {
|
||||||
rects = NULL;
|
rects = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_boxes; i++) {
|
for (i = 0; i < n_rects; i++) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
_cairo_region_get_box (region, i, &box);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
|
||||||
rects[i].x = box.p1.x;
|
rects[i].x = rect.x;
|
||||||
rects[i].y = box.p1.y;
|
rects[i].y = rect.y;
|
||||||
rects[i].width = box.p2.x - box.p1.x;
|
rects[i].width = rect.width;
|
||||||
rects[i].height = box.p2.y - box.p1.y;
|
rects[i].height = rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
surface->have_clip_rects = TRUE;
|
surface->have_clip_rects = TRUE;
|
||||||
surface->clip_rects = rects;
|
surface->clip_rects = rects;
|
||||||
surface->num_clip_rects = n_boxes;
|
surface->num_clip_rects = n_rects;
|
||||||
|
|
||||||
if (surface->gc)
|
if (surface->gc)
|
||||||
_cairo_xcb_surface_set_gc_clip_rects (surface);
|
_cairo_xcb_surface_set_gc_clip_rects (surface);
|
||||||
|
|
|
@ -2271,7 +2271,32 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMPILE_TIME_ASSERT (sizeof (XRectangle) <= sizeof (cairo_box_int_t));
|
static cairo_region_t *
|
||||||
|
_surface_maybe_clip_region (cairo_xlib_surface_t *surface,
|
||||||
|
cairo_region_t *clip,
|
||||||
|
cairo_region_t *bounded)
|
||||||
|
{
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
|
cairo_region_get_extents (clip, &rect);
|
||||||
|
if (rect.x >= 0 &&
|
||||||
|
rect.y >= 0 &&
|
||||||
|
rect.x + rect.width <= surface->width &&
|
||||||
|
rect.y + rect.height <= surface->height)
|
||||||
|
{
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.x = rect.y = 0;
|
||||||
|
rect.width = surface->width;
|
||||||
|
rect.height = surface->height;
|
||||||
|
_cairo_region_init_rectangle (bounded, &rect);
|
||||||
|
|
||||||
|
bounded->status = cairo_region_intersect (bounded, clip);
|
||||||
|
|
||||||
|
return bounded;
|
||||||
|
}
|
||||||
|
|
||||||
static cairo_int_status_t
|
static cairo_int_status_t
|
||||||
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
||||||
cairo_region_t *region)
|
cairo_region_t *region)
|
||||||
|
@ -2291,58 +2316,50 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
||||||
surface->num_clip_rects = 0;
|
surface->num_clip_rects = 0;
|
||||||
|
|
||||||
if (region != NULL) {
|
if (region != NULL) {
|
||||||
cairo_status_t status;
|
|
||||||
XRectangle *rects = NULL;
|
XRectangle *rects = NULL;
|
||||||
int n_boxes, i;
|
int n_rects, i;
|
||||||
cairo_rectangle_int_t rect;
|
|
||||||
cairo_region_t bounded;
|
cairo_region_t bounded;
|
||||||
|
|
||||||
rect.x = rect.y = 0;
|
|
||||||
rect.width = surface->width;
|
|
||||||
rect.height = surface->height;
|
|
||||||
|
|
||||||
/* Intersect the region with the bounds of the surface. This
|
/* Intersect the region with the bounds of the surface. This
|
||||||
* is necessary so we don't wrap around when we convert cairo's
|
* is necessary so we don't wrap around when we convert cairo's
|
||||||
* 32 bit region into 16 bit rectangles.
|
* 32 bit region into 16 bit rectangles.
|
||||||
*/
|
*/
|
||||||
_cairo_region_init_rect (&bounded, &rect);
|
region = _surface_maybe_clip_region (surface, region, &bounded);
|
||||||
status = _cairo_region_intersect (&bounded, &bounded, region);
|
if (unlikely (region->status))
|
||||||
if (unlikely (status)) {
|
return region->status;
|
||||||
_cairo_region_fini (&bounded);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
n_boxes = _cairo_region_num_boxes (&bounded);
|
n_rects = cairo_region_num_rectangles (region);
|
||||||
|
if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
|
||||||
if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) {
|
rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
|
||||||
rects = _cairo_malloc_ab (n_boxes, sizeof (XRectangle));
|
|
||||||
if (unlikely (rects == NULL)) {
|
if (unlikely (rects == NULL)) {
|
||||||
_cairo_region_fini (&bounded);
|
if (unlikely (region == &bounded))
|
||||||
|
_cairo_region_fini (&bounded);
|
||||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rects = surface->embedded_clip_rects;
|
rects = surface->embedded_clip_rects;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_boxes; i++) {
|
for (i = 0; i < n_rects; i++) {
|
||||||
cairo_box_int_t box;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
_cairo_region_get_box (&bounded, i, &box);
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
|
||||||
rects[i].x = box.p1.x;
|
rects[i].x = rect.x;
|
||||||
rects[i].y = box.p1.y;
|
rects[i].y = rect.y;
|
||||||
rects[i].width = box.p2.x - rects[i].x;
|
rects[i].width = rect.width;
|
||||||
rects[i].height = box.p2.y - rects[i].y;
|
rects[i].height = rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cairo_region_fini (&bounded);
|
if (unlikely (region == &bounded))
|
||||||
|
_cairo_region_fini (&bounded);
|
||||||
|
|
||||||
surface->have_clip_rects = TRUE;
|
surface->have_clip_rects = TRUE;
|
||||||
surface->clip_rects = rects;
|
surface->clip_rects = rects;
|
||||||
surface->num_clip_rects = n_boxes;
|
surface->num_clip_rects = n_rects;
|
||||||
|
|
||||||
/* Discard the trivial clip rectangle that covers the entire surface */
|
/* Discard the trivial clip rectangle that covers the entire surface */
|
||||||
if (n_boxes == 1 &&
|
if (n_rects == 1 &&
|
||||||
rects[0].x == 0 &&
|
rects[0].x == 0 &&
|
||||||
rects[0].y == 0 &&
|
rects[0].y == 0 &&
|
||||||
rects[0].width == surface->width &&
|
rects[0].width == surface->width &&
|
||||||
|
|
|
@ -2353,10 +2353,88 @@ cairo_public void
|
||||||
cairo_matrix_transform_point (const cairo_matrix_t *matrix,
|
cairo_matrix_transform_point (const cairo_matrix_t *matrix,
|
||||||
double *x, double *y);
|
double *x, double *y);
|
||||||
|
|
||||||
|
/* Region functions */
|
||||||
|
|
||||||
|
typedef struct _cairo_region cairo_region_t;
|
||||||
|
|
||||||
|
typedef struct _cairo_rectangle_int {
|
||||||
|
int x, y;
|
||||||
|
int width, height;
|
||||||
|
} cairo_rectangle_int_t;
|
||||||
|
|
||||||
|
typedef enum _cairo_region_overlap {
|
||||||
|
CAIRO_REGION_OVERLAP_IN, /* completely inside region */
|
||||||
|
CAIRO_REGION_OVERLAP_OUT, /* completely outside region */
|
||||||
|
CAIRO_REGION_OVERLAP_PART /* partly inside region */
|
||||||
|
} cairo_region_overlap_t;
|
||||||
|
|
||||||
|
cairo_public cairo_region_t *
|
||||||
|
cairo_region_create (void);
|
||||||
|
|
||||||
|
cairo_public cairo_region_t *
|
||||||
|
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_public cairo_region_t *
|
||||||
|
cairo_region_copy (cairo_region_t *original);
|
||||||
|
|
||||||
|
cairo_public void
|
||||||
|
cairo_region_destroy (cairo_region_t *region);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_status (cairo_region_t *region);
|
||||||
|
|
||||||
|
cairo_public void
|
||||||
|
cairo_region_get_extents (cairo_region_t *region,
|
||||||
|
cairo_rectangle_int_t *extents);
|
||||||
|
|
||||||
|
cairo_public int
|
||||||
|
cairo_region_num_rectangles (cairo_region_t *region);
|
||||||
|
|
||||||
|
cairo_public void
|
||||||
|
cairo_region_get_rectangle (cairo_region_t *region,
|
||||||
|
int nth_rectangle,
|
||||||
|
cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_public cairo_bool_t
|
||||||
|
cairo_region_is_empty (cairo_region_t *region);
|
||||||
|
|
||||||
|
cairo_public cairo_region_overlap_t
|
||||||
|
cairo_region_contains_rectangle (cairo_region_t *region,
|
||||||
|
const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_public cairo_bool_t
|
||||||
|
cairo_region_contains_point (cairo_region_t *region, int x, int y);
|
||||||
|
|
||||||
|
cairo_public void
|
||||||
|
cairo_region_translate (cairo_region_t *region, int dx, int dy);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_subtract_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_intersect (cairo_region_t *dst, cairo_region_t *other);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_intersect_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_union (cairo_region_t *dst, cairo_region_t *other);
|
||||||
|
|
||||||
|
cairo_public cairo_status_t
|
||||||
|
cairo_region_union_rectangle (cairo_region_t *dst,
|
||||||
|
const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
|
||||||
/* Functions to be used while debugging (not intended for use in production code) */
|
/* Functions to be used while debugging (not intended for use in production code) */
|
||||||
cairo_public void
|
cairo_public void
|
||||||
cairo_debug_reset_static_data (void);
|
cairo_debug_reset_static_data (void);
|
||||||
|
|
||||||
|
|
||||||
CAIRO_END_DECLS
|
CAIRO_END_DECLS
|
||||||
|
|
||||||
#endif /* CAIRO_H */
|
#endif /* CAIRO_H */
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
|
|
||||||
CAIRO_BEGIN_DECLS
|
CAIRO_BEGIN_DECLS
|
||||||
|
|
||||||
#if _WIN32 && !WINCE // we don't have to worry about permissions on WINCE
|
#if _WIN32 && !_WIN32_WCE // we don't have to worry about permissions on WinCE
|
||||||
cairo_private FILE *
|
cairo_private FILE *
|
||||||
_cairo_win32_tmpfile (void);
|
_cairo_win32_tmpfile (void);
|
||||||
#define tmpfile() _cairo_win32_tmpfile()
|
#define tmpfile() _cairo_win32_tmpfile()
|
||||||
|
@ -2418,7 +2418,7 @@ _cairo_traps_extents (const cairo_traps_t *traps,
|
||||||
|
|
||||||
cairo_private cairo_int_status_t
|
cairo_private cairo_int_status_t
|
||||||
_cairo_traps_extract_region (const cairo_traps_t *tr,
|
_cairo_traps_extract_region (const cairo_traps_t *tr,
|
||||||
cairo_region_t *region);
|
cairo_region_t **region);
|
||||||
|
|
||||||
cairo_private cairo_status_t
|
cairo_private cairo_status_t
|
||||||
_cairo_traps_path (const cairo_traps_t *traps,
|
_cairo_traps_path (const cairo_traps_t *traps,
|
||||||
|
@ -2538,7 +2538,21 @@ _cairo_pattern_reset_static_data (void);
|
||||||
|
|
||||||
/* cairo-region.c */
|
/* cairo-region.c */
|
||||||
|
|
||||||
#include "cairo-region-private.h"
|
struct _cairo_region {
|
||||||
|
cairo_status_t status;
|
||||||
|
|
||||||
|
pixman_region32_t rgn;
|
||||||
|
};
|
||||||
|
|
||||||
|
cairo_private void
|
||||||
|
_cairo_region_init (cairo_region_t *region);
|
||||||
|
|
||||||
|
cairo_private void
|
||||||
|
_cairo_region_init_rectangle (cairo_region_t *region,
|
||||||
|
const cairo_rectangle_int_t *rectangle);
|
||||||
|
|
||||||
|
cairo_private void
|
||||||
|
_cairo_region_fini (cairo_region_t *region);
|
||||||
|
|
||||||
/* cairo-unicode.c */
|
/* cairo-unicode.c */
|
||||||
|
|
||||||
|
@ -2700,6 +2714,24 @@ slim_hidden_proto (cairo_user_font_face_set_unicode_to_glyph_func);
|
||||||
slim_hidden_proto (cairo_user_to_device);
|
slim_hidden_proto (cairo_user_to_device);
|
||||||
slim_hidden_proto (cairo_user_to_device_distance);
|
slim_hidden_proto (cairo_user_to_device_distance);
|
||||||
slim_hidden_proto (cairo_version_string);
|
slim_hidden_proto (cairo_version_string);
|
||||||
|
slim_hidden_proto (cairo_region_create);
|
||||||
|
slim_hidden_proto (cairo_region_create_rectangle);
|
||||||
|
slim_hidden_proto (cairo_region_copy);
|
||||||
|
slim_hidden_proto (cairo_region_destroy);
|
||||||
|
slim_hidden_proto (cairo_region_status);
|
||||||
|
slim_hidden_proto (cairo_region_get_extents);
|
||||||
|
slim_hidden_proto (cairo_region_num_rectangles);
|
||||||
|
slim_hidden_proto (cairo_region_get_rectangle);
|
||||||
|
slim_hidden_proto (cairo_region_is_empty);
|
||||||
|
slim_hidden_proto (cairo_region_contains_rectangle);
|
||||||
|
slim_hidden_proto (cairo_region_contains_point);
|
||||||
|
slim_hidden_proto (cairo_region_translate);
|
||||||
|
slim_hidden_proto (cairo_region_subtract);
|
||||||
|
slim_hidden_proto (cairo_region_subtract_rectangle);
|
||||||
|
slim_hidden_proto (cairo_region_intersect);
|
||||||
|
slim_hidden_proto (cairo_region_intersect_rectangle);
|
||||||
|
slim_hidden_proto (cairo_region_union);
|
||||||
|
slim_hidden_proto (cairo_region_union_rectangle);
|
||||||
|
|
||||||
#if CAIRO_HAS_PNG_FUNCTIONS
|
#if CAIRO_HAS_PNG_FUNCTIONS
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ else
|
||||||
USE_MMX=1
|
USE_MMX=1
|
||||||
USE_SSE2=1
|
USE_SSE2=1
|
||||||
MMX_CFLAGS=
|
MMX_CFLAGS=
|
||||||
|
SSE2_CFLAGS=
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
ifeq (arm,$(findstring arm,$(OS_TEST)))
|
ifeq (arm,$(findstring arm,$(OS_TEST)))
|
||||||
|
@ -81,11 +82,11 @@ ifdef GNU_CC
|
||||||
ifeq (86,$(findstring 86,$(OS_TEST)))
|
ifeq (86,$(findstring 86,$(OS_TEST)))
|
||||||
USE_MMX=1
|
USE_MMX=1
|
||||||
MMX_CFLAGS=-mmmx -Winline
|
MMX_CFLAGS=-mmmx -Winline
|
||||||
# See bug 410509 why we can't use SSE2 yet on linux
|
USE_SSE2=1
|
||||||
#USE_SSE2=1
|
SSE2_CFLAGS=-msse2 -Winline
|
||||||
#MMX_CFLAGS+=-msse -msse2
|
|
||||||
ifneq ($(MOZ_WIDGET_TOOLKIT),os2)
|
ifneq ($(MOZ_WIDGET_TOOLKIT),os2)
|
||||||
MMX_CFLAGS+=--param inline-unit-growth=10000 --param large-function-growth=10000
|
MMX_CFLAGS+=--param inline-unit-growth=10000 --param large-function-growth=10000
|
||||||
|
SSE2_CFLAGS+=--param inline-unit-growth=10000 --param large-function-growth=10000
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
ifeq (arm,$(findstring arm,$(OS_TEST)))
|
ifeq (arm,$(findstring arm,$(OS_TEST)))
|
||||||
|
@ -177,7 +178,7 @@ pixman-mmx.$(OBJ_SUFFIX): pixman-mmx.c Makefile Makefile.in
|
||||||
pixman-sse2.$(OBJ_SUFFIX): pixman-sse2.c Makefile Makefile.in
|
pixman-sse2.$(OBJ_SUFFIX): pixman-sse2.c Makefile Makefile.in
|
||||||
$(REPORT_BUILD)
|
$(REPORT_BUILD)
|
||||||
@$(MAKE_DEPS_AUTO_CC)
|
@$(MAKE_DEPS_AUTO_CC)
|
||||||
$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(MMX_CFLAGS) $(_VPATH_SRCS)
|
$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE2_CFLAGS) $(_VPATH_SRCS)
|
||||||
|
|
||||||
pixman-arm-neon.$(OBJ_SUFFIX): pixman-arm-neon.c Makefile Makefile.in
|
pixman-arm-neon.$(OBJ_SUFFIX): pixman-arm-neon.c Makefile Makefile.in
|
||||||
$(REPORT_BUILD)
|
$(REPORT_BUILD)
|
||||||
|
|
|
@ -84,7 +84,7 @@ NS_IMETHODIMP nsTextToSubURI::ConvertAndEscape(
|
||||||
if(NS_SUCCEEDED(rv = encoder->GetMaxLength(text, ulen, &outlen)))
|
if(NS_SUCCEEDED(rv = encoder->GetMaxLength(text, ulen, &outlen)))
|
||||||
{
|
{
|
||||||
if(outlen >= 256) {
|
if(outlen >= 256) {
|
||||||
pBuf = (char*)PR_Malloc(outlen+1);
|
pBuf = (char*)NS_Alloc(outlen+1);
|
||||||
}
|
}
|
||||||
if(nsnull == pBuf) {
|
if(nsnull == pBuf) {
|
||||||
outlen = 255;
|
outlen = 255;
|
||||||
|
@ -105,7 +105,7 @@ NS_IMETHODIMP nsTextToSubURI::ConvertAndEscape(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pBuf != buf)
|
if(pBuf != buf)
|
||||||
PR_Free(pBuf);
|
NS_Free(pBuf);
|
||||||
}
|
}
|
||||||
NS_RELEASE(encoder);
|
NS_RELEASE(encoder);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ NS_IMETHODIMP nsTextToSubURI::UnEscapeAndConvert(
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
// unescape the string, unescape changes the input
|
// unescape the string, unescape changes the input
|
||||||
char *unescaped = nsCRT::strdup((char *) text);
|
char *unescaped = NS_strdup(text);
|
||||||
if (nsnull == unescaped)
|
if (nsnull == unescaped)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
unescaped = nsUnescape(unescaped);
|
unescaped = nsUnescape(unescaped);
|
||||||
|
@ -140,7 +140,7 @@ NS_IMETHODIMP nsTextToSubURI::UnEscapeAndConvert(
|
||||||
PRInt32 len = strlen(unescaped);
|
PRInt32 len = strlen(unescaped);
|
||||||
PRInt32 outlen = 0;
|
PRInt32 outlen = 0;
|
||||||
if (NS_SUCCEEDED(rv = decoder->GetMaxLength(unescaped, len, &outlen))) {
|
if (NS_SUCCEEDED(rv = decoder->GetMaxLength(unescaped, len, &outlen))) {
|
||||||
pBuf = (PRUnichar *) PR_Malloc((outlen+1)*sizeof(PRUnichar*));
|
pBuf = (PRUnichar *) NS_Alloc((outlen+1)*sizeof(PRUnichar*));
|
||||||
if (nsnull == pBuf)
|
if (nsnull == pBuf)
|
||||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||||
else {
|
else {
|
||||||
|
@ -149,13 +149,13 @@ NS_IMETHODIMP nsTextToSubURI::UnEscapeAndConvert(
|
||||||
*_retval = pBuf;
|
*_retval = pBuf;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PR_Free(pBuf);
|
NS_Free(pBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NS_RELEASE(decoder);
|
NS_RELEASE(decoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PR_Free(unescaped);
|
NS_Free(unescaped);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ nsresult nsTextToSubURI::convertURItoUnicode(const nsAFlatCString &aCharset,
|
||||||
rv = unicodeDecoder->GetMaxLength(aURI.get(), srcLen, &dstLen);
|
rv = unicodeDecoder->GetMaxLength(aURI.get(), srcLen, &dstLen);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PRUnichar *ustr = (PRUnichar *) nsMemory::Alloc(dstLen * sizeof(PRUnichar));
|
PRUnichar *ustr = (PRUnichar *) NS_Alloc(dstLen * sizeof(PRUnichar));
|
||||||
NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
rv = unicodeDecoder->Convert(aURI.get(), &srcLen, ustr, &dstLen);
|
rv = unicodeDecoder->Convert(aURI.get(), &srcLen, ustr, &dstLen);
|
||||||
|
@ -218,7 +218,7 @@ nsresult nsTextToSubURI::convertURItoUnicode(const nsAFlatCString &aCharset,
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
_retval.Assign(ustr, dstLen);
|
_retval.Assign(ustr, dstLen);
|
||||||
|
|
||||||
nsMemory::Free(ustr);
|
NS_Free(ustr);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2953,7 +2953,7 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
/* Walk slots in obj and if any value is a non-null object, seal it. */
|
/* Walk slots in obj and if any value is a non-null object, seal it. */
|
||||||
nslots = scope->map.freeslot;
|
nslots = scope->freeslot;
|
||||||
for (i = 0; i != nslots; ++i) {
|
for (i = 0; i != nslots; ++i) {
|
||||||
v = STOBJ_GET_SLOT(obj, i);
|
v = STOBJ_GET_SLOT(obj, i);
|
||||||
if (JSVAL_IS_PRIMITIVE(v))
|
if (JSVAL_IS_PRIMITIVE(v))
|
||||||
|
|
|
@ -1199,35 +1199,12 @@ array_trace(JSTracer *trc, JSObject *obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSObjectMap *
|
extern JSObjectOps js_ArrayObjectOps;
|
||||||
array_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
extern JSClass js_ArrayClass;
|
|
||||||
extern JSObjectOps js_ArrayObjectOps;
|
|
||||||
#endif
|
|
||||||
JSObjectMap *map = (JSObjectMap *) JS_malloc(cx, sizeof(*map));
|
|
||||||
if (!map)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
map->nrefs = nrefs;
|
static const JSObjectMap SharedArrayMap = { &js_ArrayObjectOps };
|
||||||
JS_ASSERT(ops == &js_ArrayObjectOps);
|
|
||||||
map->ops = ops;
|
|
||||||
JS_ASSERT(clasp == &js_ArrayClass);
|
|
||||||
map->freeslot = JSSLOT_FREE(clasp);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
array_destroyObjectMap(JSContext *cx, JSObjectMap *map)
|
|
||||||
{
|
|
||||||
JS_free(cx, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectOps js_ArrayObjectOps = {
|
JSObjectOps js_ArrayObjectOps = {
|
||||||
array_newObjectMap, array_destroyObjectMap,
|
&SharedArrayMap,
|
||||||
array_lookupProperty, array_defineProperty,
|
array_lookupProperty, array_defineProperty,
|
||||||
array_getProperty, array_setProperty,
|
array_getProperty, array_setProperty,
|
||||||
array_getAttributes, array_setAttributes,
|
array_getAttributes, array_setAttributes,
|
||||||
|
@ -1271,27 +1248,24 @@ JSClass js_SlowArrayClass = {
|
||||||
JSBool
|
JSBool
|
||||||
js_MakeArraySlow(JSContext *cx, JSObject *obj)
|
js_MakeArraySlow(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
JSObjectMap *map, *oldmap;
|
|
||||||
uint32 i, capacity;
|
|
||||||
|
|
||||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
|
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
|
||||||
|
|
||||||
/* Create a native scope. */
|
/* Create a native scope. */
|
||||||
map = js_NewObjectMap(cx, obj->map->nrefs, &js_SlowArrayObjectOps,
|
JSScope *scope = js_NewScope(cx, &js_SlowArrayObjectOps,
|
||||||
&js_SlowArrayClass, obj);
|
&js_SlowArrayClass, obj);
|
||||||
if (!map)
|
if (!scope)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
capacity = js_DenseArrayCapacity(obj);
|
uint32 capacity = js_DenseArrayCapacity(obj);
|
||||||
if (capacity) {
|
if (capacity) {
|
||||||
map->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS;
|
scope->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS;
|
||||||
obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity;
|
obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity;
|
||||||
} else {
|
} else {
|
||||||
map->freeslot = STOBJ_NSLOTS(obj);
|
scope->freeslot = STOBJ_NSLOTS(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create new properties pointing to existing values in dslots */
|
/* Create new properties pointing to existing values in dslots */
|
||||||
for (i = 0; i < capacity; i++) {
|
for (uint32 i = 0; i < capacity; i++) {
|
||||||
jsid id;
|
jsid id;
|
||||||
JSScopeProperty *sprop;
|
JSScopeProperty *sprop;
|
||||||
|
|
||||||
|
@ -1303,7 +1277,7 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprop = js_AddScopeProperty(cx, (JSScope *)map, id, NULL, NULL,
|
sprop = js_AddScopeProperty(cx, scope, id, NULL, NULL,
|
||||||
i + JS_INITIAL_NSLOTS, JSPROP_ENUMERATE,
|
i + JS_INITIAL_NSLOTS, JSPROP_ENUMERATE,
|
||||||
0, 0);
|
0, 0);
|
||||||
if (!sprop)
|
if (!sprop)
|
||||||
|
@ -1327,15 +1301,11 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
|
||||||
obj->classword ^= (jsuword) &js_ArrayClass;
|
obj->classword ^= (jsuword) &js_ArrayClass;
|
||||||
obj->classword |= (jsuword) &js_SlowArrayClass;
|
obj->classword |= (jsuword) &js_SlowArrayClass;
|
||||||
|
|
||||||
/* Swap in our new map. */
|
obj->map = &scope->map;
|
||||||
oldmap = obj->map;
|
|
||||||
obj->map = map;
|
|
||||||
array_destroyObjectMap(cx, oldmap);
|
|
||||||
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
out_bad:
|
out_bad:
|
||||||
js_DestroyObjectMap(cx, map);
|
js_DestroyScope(cx, scope);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3387,9 +3357,9 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JSClass* clasp = &js_ArrayClass;
|
/* Initialize all fields of JSObject. */
|
||||||
obj->classword = jsuword(clasp);
|
obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
|
||||||
|
obj->classword = jsuword(&js_ArrayClass);
|
||||||
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||||
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
|
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
|
||||||
|
|
||||||
|
@ -3397,11 +3367,6 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
|
||||||
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
|
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
|
||||||
for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i)
|
for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i)
|
||||||
obj->fslots[i] = JSVAL_VOID;
|
obj->fslots[i] = JSVAL_VOID;
|
||||||
|
|
||||||
JSObjectOps* ops = clasp->getObjectOps(cx, clasp);
|
|
||||||
obj->map = ops->newObjectMap(cx, 1, ops, clasp, obj);
|
|
||||||
if (!obj->map)
|
|
||||||
return NULL;
|
|
||||||
obj->dslots = NULL;
|
obj->dslots = NULL;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,10 +258,10 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = sprop->slot;
|
slot = sprop->slot;
|
||||||
if (!scope->table && sprop->parent == scope->lastProp && slot == scope->map.freeslot) {
|
if (!scope->table && sprop->parent == scope->lastProp && slot == scope->freeslot) {
|
||||||
if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
|
if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
|
||||||
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->map.freeslot)));
|
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
|
||||||
++scope->map.freeslot;
|
++scope->freeslot;
|
||||||
} else {
|
} else {
|
||||||
if (!js_AllocSlot(cx, obj, &slot))
|
if (!js_AllocSlot(cx, obj, &slot))
|
||||||
goto exit_trace;
|
goto exit_trace;
|
||||||
|
@ -398,26 +398,27 @@ js_Arguments(JSContext* cx)
|
||||||
JS_DEFINE_CALLINFO_1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
|
JS_DEFINE_CALLINFO_1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
|
||||||
|
|
||||||
JSObject* FASTCALL
|
JSObject* FASTCALL
|
||||||
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject *parent)
|
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent)
|
||||||
{
|
{
|
||||||
JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
|
JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
|
||||||
|
JS_ASSERT(HAS_FUNCTION_CLASS(proto));
|
||||||
|
JS_ASSERT(JS_ON_TRACE(cx));
|
||||||
|
|
||||||
JSFunction *fun = (JSFunction*) funobj;
|
JSFunction *fun = (JSFunction*) funobj;
|
||||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
||||||
|
|
||||||
JS_ASSERT(JS_ON_TRACE(cx));
|
|
||||||
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
||||||
if (!closure)
|
if (!closure)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
js_HoldScope(OBJ_SCOPE(proto));
|
||||||
|
closure->map = proto->map;
|
||||||
closure->classword = jsuword(&js_FunctionClass);
|
closure->classword = jsuword(&js_FunctionClass);
|
||||||
closure->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
closure->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||||
closure->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
closure->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
||||||
closure->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
|
closure->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
|
||||||
for (unsigned i = JSSLOT_PRIVATE + 1; i != JS_INITIAL_NSLOTS; ++i)
|
for (unsigned i = JSSLOT_PRIVATE + 1; i != JS_INITIAL_NSLOTS; ++i)
|
||||||
closure->fslots[i] = JSVAL_VOID;
|
closure->fslots[i] = JSVAL_VOID;
|
||||||
|
|
||||||
closure->map = js_HoldObjectMap(cx, proto->map);
|
|
||||||
closure->dslots = NULL;
|
closure->dslots = NULL;
|
||||||
return closure;
|
return closure;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1821,7 +1821,7 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
blockObj->map->freeslot = JSSLOT_FREE(&js_BlockClass);
|
OBJ_SCOPE(blockObj)->freeslot = JSSLOT_FREE(&js_BlockClass);
|
||||||
js_ReallocSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass), JS_TRUE);
|
js_ReallocSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass), JS_TRUE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,8 +718,8 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
|
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
|
||||||
memcpy(callobj->dslots + fun->nargs, fp->slots,
|
memcpy(callobj->dslots + fun->nargs, fp->slots,
|
||||||
fun->u.i.nvars * sizeof(jsval));
|
fun->u.i.nvars * sizeof(jsval));
|
||||||
if (scope->object == callobj && n > scope->map.freeslot)
|
if (scope->object == callobj && n > scope->freeslot)
|
||||||
scope->map.freeslot = n;
|
scope->freeslot = n;
|
||||||
}
|
}
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4164,7 +4164,7 @@ js_Interpret(JSContext *cx)
|
||||||
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
|
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
|
||||||
if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) {
|
if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) {
|
||||||
slot = PCVAL_TO_SLOT(entry->vword);
|
slot = PCVAL_TO_SLOT(entry->vword);
|
||||||
JS_ASSERT(slot < obj->map->freeslot);
|
JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot);
|
||||||
rval = LOCKED_OBJ_GET_SLOT(obj, slot);
|
rval = LOCKED_OBJ_GET_SLOT(obj, slot);
|
||||||
if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
|
if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
|
||||||
rtmp = rval;
|
rtmp = rval;
|
||||||
|
@ -4420,7 +4420,7 @@ js_Interpret(JSContext *cx)
|
||||||
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
|
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
|
||||||
} else if (PCVAL_IS_SLOT(entry->vword)) {
|
} else if (PCVAL_IS_SLOT(entry->vword)) {
|
||||||
slot = PCVAL_TO_SLOT(entry->vword);
|
slot = PCVAL_TO_SLOT(entry->vword);
|
||||||
JS_ASSERT(slot < obj2->map->freeslot);
|
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
|
||||||
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||||
|
@ -4511,7 +4511,7 @@ js_Interpret(JSContext *cx)
|
||||||
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
|
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
|
||||||
} else if (PCVAL_IS_SLOT(entry->vword)) {
|
} else if (PCVAL_IS_SLOT(entry->vword)) {
|
||||||
slot = PCVAL_TO_SLOT(entry->vword);
|
slot = PCVAL_TO_SLOT(entry->vword);
|
||||||
JS_ASSERT(slot < obj2->map->freeslot);
|
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
|
||||||
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||||
|
@ -4656,7 +4656,7 @@ js_Interpret(JSContext *cx)
|
||||||
|
|
||||||
if (checkForAdd &&
|
if (checkForAdd &&
|
||||||
SPROP_HAS_STUB_SETTER(sprop) &&
|
SPROP_HAS_STUB_SETTER(sprop) &&
|
||||||
(slot = sprop->slot) == scope->map.freeslot) {
|
(slot = sprop->slot) == scope->freeslot) {
|
||||||
/*
|
/*
|
||||||
* Fast path: adding a plain old property that
|
* Fast path: adding a plain old property that
|
||||||
* was once at the frontier of the property
|
* was once at the frontier of the property
|
||||||
|
@ -4681,7 +4681,7 @@ js_Interpret(JSContext *cx)
|
||||||
*/
|
*/
|
||||||
if (slot < STOBJ_NSLOTS(obj) &&
|
if (slot < STOBJ_NSLOTS(obj) &&
|
||||||
!OBJ_GET_CLASS(cx, obj)->reserveSlots) {
|
!OBJ_GET_CLASS(cx, obj)->reserveSlots) {
|
||||||
++scope->map.freeslot;
|
++scope->freeslot;
|
||||||
} else {
|
} else {
|
||||||
if (!js_AllocSlot(cx, obj, &slot)) {
|
if (!js_AllocSlot(cx, obj, &slot)) {
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
|
@ -5262,7 +5262,7 @@ js_Interpret(JSContext *cx)
|
||||||
|
|
||||||
if (PCVAL_IS_SLOT(entry->vword)) {
|
if (PCVAL_IS_SLOT(entry->vword)) {
|
||||||
slot = PCVAL_TO_SLOT(entry->vword);
|
slot = PCVAL_TO_SLOT(entry->vword);
|
||||||
JS_ASSERT(slot < obj2->map->freeslot);
|
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
|
||||||
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
|
||||||
JS_UNLOCK_OBJ(cx, obj2);
|
JS_UNLOCK_OBJ(cx, obj2);
|
||||||
goto do_push_rval;
|
goto do_push_rval;
|
||||||
|
@ -5742,7 +5742,7 @@ js_Interpret(JSContext *cx)
|
||||||
index = GET_UINT16(regs.pc);
|
index = GET_UINT16(regs.pc);
|
||||||
JS_ASSERT(JS_INITIAL_NSLOTS + index < jsatomid(obj->dslots[-1]));
|
JS_ASSERT(JS_INITIAL_NSLOTS + index < jsatomid(obj->dslots[-1]));
|
||||||
JS_ASSERT_IF(OBJ_SCOPE(obj)->object == obj,
|
JS_ASSERT_IF(OBJ_SCOPE(obj)->object == obj,
|
||||||
JS_INITIAL_NSLOTS + index < obj->map->freeslot);
|
JS_INITIAL_NSLOTS + index < OBJ_SCOPE(obj)->freeslot);
|
||||||
|
|
||||||
PUSH_OPND(obj->dslots[index]);
|
PUSH_OPND(obj->dslots[index]);
|
||||||
if (op == JSOP_CALLDSLOT)
|
if (op == JSOP_CALLDSLOT)
|
||||||
|
@ -6371,9 +6371,9 @@ js_Interpret(JSContext *cx)
|
||||||
!SCOPE_HAS_PROPERTY(scope, sprop));
|
!SCOPE_HAS_PROPERTY(scope, sprop));
|
||||||
|
|
||||||
slot = sprop->slot;
|
slot = sprop->slot;
|
||||||
JS_ASSERT(slot == scope->map.freeslot);
|
JS_ASSERT(slot == scope->freeslot);
|
||||||
if (slot < STOBJ_NSLOTS(obj)) {
|
if (slot < STOBJ_NSLOTS(obj)) {
|
||||||
++scope->map.freeslot;
|
++scope->freeslot;
|
||||||
} else {
|
} else {
|
||||||
if (!js_AllocSlot(cx, obj, &slot)) {
|
if (!js_AllocSlot(cx, obj, &slot)) {
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
|
|
|
@ -57,11 +57,6 @@
|
||||||
#include "jsscope.h"
|
#include "jsscope.h"
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Check that we can cast the data after JSObjectMap as JSTitle.
|
|
||||||
*/
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
|
|
||||||
|
|
||||||
#define ReadWord(W) (W)
|
#define ReadWord(W) (W)
|
||||||
|
|
||||||
/* Implement NativeCompareAndSwap. */
|
/* Implement NativeCompareAndSwap. */
|
||||||
|
@ -456,7 +451,6 @@ ShareTitle(JSContext *cx, JSTitle *title)
|
||||||
static void
|
static void
|
||||||
FinishSharingTitle(JSContext *cx, JSTitle *title)
|
FinishSharingTitle(JSContext *cx, JSTitle *title)
|
||||||
{
|
{
|
||||||
JSObjectMap *map;
|
|
||||||
JSScope *scope;
|
JSScope *scope;
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
uint32 nslots, i;
|
uint32 nslots, i;
|
||||||
|
@ -464,14 +458,10 @@ FinishSharingTitle(JSContext *cx, JSTitle *title)
|
||||||
|
|
||||||
js_InitLock(&title->lock);
|
js_InitLock(&title->lock);
|
||||||
title->u.count = 0; /* NULL may not pun as 0 */
|
title->u.count = 0; /* NULL may not pun as 0 */
|
||||||
map = TITLE_TO_MAP(title);
|
scope = TITLE_TO_SCOPE(title);
|
||||||
if (!MAP_IS_NATIVE(map))
|
|
||||||
return;
|
|
||||||
scope = (JSScope *)map;
|
|
||||||
|
|
||||||
obj = scope->object;
|
obj = scope->object;
|
||||||
if (obj) {
|
if (obj) {
|
||||||
nslots = scope->map.freeslot;
|
nslots = scope->freeslot;
|
||||||
for (i = 0; i != nslots; ++i) {
|
for (i = 0; i != nslots; ++i) {
|
||||||
v = STOBJ_GET_SLOT(obj, i);
|
v = STOBJ_GET_SLOT(obj, i);
|
||||||
if (JSVAL_IS_STRING(v) &&
|
if (JSVAL_IS_STRING(v) &&
|
||||||
|
@ -617,9 +607,9 @@ ClaimTitle(JSTitle *title, JSContext *cx)
|
||||||
* non-null test, and avoid double-insertion bugs.
|
* non-null test, and avoid double-insertion bugs.
|
||||||
*/
|
*/
|
||||||
if (!title->u.link) {
|
if (!title->u.link) {
|
||||||
|
js_HoldScope(TITLE_TO_SCOPE(title));
|
||||||
title->u.link = rt->titleSharingTodo;
|
title->u.link = rt->titleSharingTodo;
|
||||||
rt->titleSharingTodo = title;
|
rt->titleSharingTodo = title;
|
||||||
js_HoldObjectMap(cx, TITLE_TO_MAP(title));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -693,13 +683,13 @@ js_ShareWaitingTitles(JSContext *cx)
|
||||||
title->u.link = NULL; /* null u.link for sanity ASAP */
|
title->u.link = NULL; /* null u.link for sanity ASAP */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If js_DropObjectMap returns null, we held the last ref to scope.
|
* If js_DropScope returns false, we held the last ref to scope. The
|
||||||
* The waiting thread(s) must have been killed, after which the GC
|
* waiting thread(s) must have been killed, after which the GC
|
||||||
* collected the object that held this scope. Unlikely, because it
|
* collected the object that held this scope. Unlikely, because it
|
||||||
* requires that the GC ran (e.g., from an operation callback)
|
* requires that the GC ran (e.g., from an operation callback)
|
||||||
* during this request, but possible.
|
* during this request, but possible.
|
||||||
*/
|
*/
|
||||||
if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
|
if (js_DropScope(cx, TITLE_TO_SCOPE(title), NULL)) {
|
||||||
FinishSharingTitle(cx, title); /* set ownercx = NULL */
|
FinishSharingTitle(cx, title); /* set ownercx = NULL */
|
||||||
shared = true;
|
shared = true;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +730,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
|
||||||
scope = OBJ_SCOPE(obj);
|
scope = OBJ_SCOPE(obj);
|
||||||
title = &scope->title;
|
title = &scope->title;
|
||||||
JS_ASSERT(title->ownercx != cx);
|
JS_ASSERT(title->ownercx != cx);
|
||||||
JS_ASSERT(slot < obj->map->freeslot);
|
JS_ASSERT(slot < scope->freeslot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Avoid locking if called from the GC. Also avoid locking an object
|
* Avoid locking if called from the GC. Also avoid locking an object
|
||||||
|
@ -835,7 +825,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||||
scope = OBJ_SCOPE(obj);
|
scope = OBJ_SCOPE(obj);
|
||||||
title = &scope->title;
|
title = &scope->title;
|
||||||
JS_ASSERT(title->ownercx != cx);
|
JS_ASSERT(title->ownercx != cx);
|
||||||
JS_ASSERT(slot < obj->map->freeslot);
|
JS_ASSERT(slot < scope->freeslot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Avoid locking if called from the GC. Also avoid locking an object
|
* Avoid locking if called from the GC. Also avoid locking an object
|
||||||
|
@ -1478,9 +1468,7 @@ js_IsRuntimeLocked(JSRuntime *rt)
|
||||||
JSBool
|
JSBool
|
||||||
js_IsObjLocked(JSContext *cx, JSObject *obj)
|
js_IsObjLocked(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
JSScope *scope = OBJ_SCOPE(obj);
|
return js_IsTitleLocked(cx, &OBJ_SCOPE(obj)->title);
|
||||||
|
|
||||||
return MAP_IS_NATIVE(&scope->map) && js_IsTitleLocked(cx, &scope->title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
|
|
@ -103,14 +103,10 @@ struct JSTitle {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Title structures must be immediately preceded by JSObjectMap structures for
|
* Title structure is always allocated as a field of JSScope.
|
||||||
* maps that use titles for threadsafety. This is enforced by assertion in
|
|
||||||
* jsscope.h; see bug 408416 for future remedies to this somewhat fragile
|
|
||||||
* architecture.
|
|
||||||
*/
|
*/
|
||||||
|
#define TITLE_TO_SCOPE(title) \
|
||||||
#define TITLE_TO_MAP(title) \
|
((JSScope *)((uint8 *) (title) - offsetof(JSScope, title)))
|
||||||
((JSObjectMap *)((char *)(title) - sizeof(JSObjectMap)))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Atomic increment and decrement for a reference counter, given jsrefcount *p.
|
* Atomic increment and decrement for a reference counter, given jsrefcount *p.
|
||||||
|
|
259
js/src/jsobj.cpp
259
js/src/jsobj.cpp
|
@ -102,7 +102,7 @@ js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
|
JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
|
||||||
js_NewObjectMap, js_DestroyObjectMap,
|
NULL,
|
||||||
js_LookupProperty, js_DefineProperty,
|
js_LookupProperty, js_DefineProperty,
|
||||||
js_GetProperty, js_SetProperty,
|
js_GetProperty, js_SetProperty,
|
||||||
js_GetAttributes, js_SetAttributes,
|
js_GetAttributes, js_SetAttributes,
|
||||||
|
@ -2033,9 +2033,12 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* ops)
|
InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
|
||||||
|
JSObjectOps* ops)
|
||||||
{
|
{
|
||||||
JSObjectMap* map;
|
JS_ASSERT(OPS_IS_NATIVE(ops));
|
||||||
|
JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
|
||||||
|
|
||||||
JSClass* protoclasp;
|
JSClass* protoclasp;
|
||||||
JSClass* clasp = OBJ_GET_CLASS(cx, obj);
|
JSClass* clasp = OBJ_GET_CLASS(cx, obj);
|
||||||
|
|
||||||
|
@ -2048,33 +2051,36 @@ CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* o
|
||||||
* object classes must have the same (null or not) reserveSlots hook.
|
* object classes must have the same (null or not) reserveSlots hook.
|
||||||
*/
|
*/
|
||||||
if (proto &&
|
if (proto &&
|
||||||
((map = proto->map)->ops == ops &&
|
proto->map->ops == ops &&
|
||||||
((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
|
((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
|
||||||
(!((protoclasp->flags ^ clasp->flags) &
|
(!((protoclasp->flags ^ clasp->flags) &
|
||||||
(JSCLASS_HAS_PRIVATE |
|
(JSCLASS_HAS_PRIVATE |
|
||||||
(JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
|
(JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
|
||||||
protoclasp->reserveSlots == clasp->reserveSlots))))
|
protoclasp->reserveSlots == clasp->reserveSlots)))
|
||||||
{
|
{
|
||||||
/* Share the given prototype's map. */
|
js_HoldScope(OBJ_SCOPE(proto));
|
||||||
obj->map = js_HoldObjectMap(cx, map);
|
obj->map = proto->map;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = ops->newObjectMap(cx, 1, ops, clasp, obj);
|
JSScope *scope = js_NewScope(cx, ops, clasp, obj);
|
||||||
if (!map)
|
if (!scope)
|
||||||
return false;
|
goto bad;
|
||||||
obj->map = map;
|
|
||||||
|
|
||||||
/* Let ops->newObjectMap set freeslot so as to reserve slots. */
|
/* Let js_NewScope set freeslot so as to reserve slots. */
|
||||||
uint32 nslots = map->freeslot;
|
JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
|
||||||
JS_ASSERT(nslots >= JSSLOT_PRIVATE);
|
if (scope->freeslot > JS_INITIAL_NSLOTS &&
|
||||||
if (nslots > JS_INITIAL_NSLOTS &&
|
!js_ReallocSlots(cx, obj, scope->freeslot, JS_TRUE)) {
|
||||||
!js_ReallocSlots(cx, obj, nslots, JS_TRUE)) {
|
js_DestroyScope(cx, scope);
|
||||||
js_DropObjectMap(cx, map, obj);
|
goto bad;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
obj->map = &scope->map;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
/* Ensure that the map field is initialized for GC. */
|
||||||
|
obj->map = NULL;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
|
@ -2093,11 +2099,8 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent
|
||||||
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
||||||
obj->fslots[i] = JSVAL_VOID;
|
obj->fslots[i] = JSVAL_VOID;
|
||||||
|
|
||||||
if (!CreateMapForObject(cx, obj, proto, &js_ObjectOps))
|
|
||||||
return NULL;
|
|
||||||
obj->dslots = NULL;
|
obj->dslots = NULL;
|
||||||
|
return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* FASTCALL
|
JSObject* FASTCALL
|
||||||
|
@ -2363,7 +2366,7 @@ with_ThisObject(JSContext *cx, JSObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
|
JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
|
||||||
js_NewObjectMap, js_DestroyObjectMap,
|
NULL,
|
||||||
with_LookupProperty, js_DefineProperty,
|
with_LookupProperty, js_DefineProperty,
|
||||||
with_GetProperty, with_SetProperty,
|
with_GetProperty, with_SetProperty,
|
||||||
with_GetAttributes, with_SetAttributes,
|
with_GetAttributes, with_SetAttributes,
|
||||||
|
@ -2455,7 +2458,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
/*
|
/*
|
||||||
* Block objects should never be exposed to scripts. Thus the clone should
|
* Block objects should never be exposed to scripts. Thus the clone should
|
||||||
* not own the property map and rather always share it with the prototype
|
* not own the property map and rather always share it with the prototype
|
||||||
* object. This allows to skip updating OBJ_SCOPE(obj)->map.freeslot after
|
* object. This allows us to skip updating OBJ_SCOPE(obj)->freeslot after
|
||||||
* we copy the stack slots into reserved slots.
|
* we copy the stack slots into reserved slots.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(OBJ_SCOPE(obj)->object != obj);
|
JS_ASSERT(OBJ_SCOPE(obj)->object != obj);
|
||||||
|
@ -2845,50 +2848,6 @@ bad:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp)
|
|
||||||
{
|
|
||||||
map->nrefs = nrefs;
|
|
||||||
map->ops = ops;
|
|
||||||
map->freeslot = JSSLOT_FREE(clasp);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectMap *
|
|
||||||
js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj)
|
|
||||||
{
|
|
||||||
return (JSObjectMap *) js_NewScope(cx, nrefs, ops, clasp, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
js_DestroyObjectMap(JSContext *cx, JSObjectMap *map)
|
|
||||||
{
|
|
||||||
js_DestroyScope(cx, (JSScope *)map);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectMap *
|
|
||||||
js_HoldObjectMap(JSContext *cx, JSObjectMap *map)
|
|
||||||
{
|
|
||||||
JS_ASSERT(map->nrefs >= 0);
|
|
||||||
JS_ATOMIC_INCREMENT(&map->nrefs);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectMap *
|
|
||||||
js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj)
|
|
||||||
{
|
|
||||||
JS_ASSERT(map->nrefs > 0);
|
|
||||||
JS_ATOMIC_DECREMENT(&map->nrefs);
|
|
||||||
if (map->nrefs == 0) {
|
|
||||||
map->ops->destroyObjectMap(cx, map);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj)
|
|
||||||
((JSScope *)map)->object = NULL;
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FreeSlots(JSContext *cx, JSObject *obj)
|
FreeSlots(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
|
@ -3072,11 +3031,6 @@ JSObject *
|
||||||
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
JSObject *parent, uintN objectSize)
|
JSObject *parent, uintN objectSize)
|
||||||
{
|
{
|
||||||
JSObject *obj;
|
|
||||||
JSObjectOps *ops;
|
|
||||||
uint32 i;
|
|
||||||
JSTempValueRooter tvr;
|
|
||||||
|
|
||||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||||
if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
|
if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
|
||||||
jsdtrace_object_create_start(cx->fp, clasp);
|
jsdtrace_object_create_start(cx->fp, clasp);
|
||||||
|
@ -3097,16 +3051,18 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
|
JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
|
||||||
((JSExtendedClass *)clasp)->equality);
|
((JSExtendedClass *)clasp)->equality);
|
||||||
|
|
||||||
|
/* Always call the class's getObjectOps hook if it has one. */
|
||||||
|
JSObjectOps *ops = clasp->getObjectOps
|
||||||
|
? clasp->getObjectOps(cx, clasp)
|
||||||
|
: &js_ObjectOps;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an object from the GC heap and initialize all its fields before
|
* Allocate an object from the GC heap and initialize all its fields before
|
||||||
* doing any operation that can potentially trigger GC.
|
* doing any operation that can potentially trigger GC.
|
||||||
*/
|
*/
|
||||||
obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
|
JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto earlybad;
|
goto out;
|
||||||
|
|
||||||
obj->map = NULL;
|
|
||||||
obj->dslots = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the class slot with the initial value of the system and delegate
|
* Set the class slot with the initial value of the system and delegate
|
||||||
|
@ -3117,55 +3073,54 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||||
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
|
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
|
||||||
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
|
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
|
||||||
|
|
||||||
/* Set the proto and parent properties. */
|
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||||
STOBJ_SET_PROTO(obj, proto);
|
|
||||||
STOBJ_SET_PARENT(obj, parent);
|
/*
|
||||||
|
* Default parent to the parent of the prototype, which was set from
|
||||||
|
* the parent of the prototype's constructor.
|
||||||
|
*/
|
||||||
|
obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL((!parent && proto)
|
||||||
|
? OBJ_GET_PARENT(cx, proto)
|
||||||
|
: parent);
|
||||||
|
|
||||||
/* Initialize the remaining fixed slots. */
|
/* Initialize the remaining fixed slots. */
|
||||||
for (i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
for (uint32 i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
||||||
obj->fslots[i] = JSVAL_VOID;
|
obj->fslots[i] = JSVAL_VOID;
|
||||||
|
|
||||||
|
obj->dslots = NULL;
|
||||||
|
|
||||||
|
if (OPS_IS_NATIVE(ops)) {
|
||||||
|
if (!InitScopeForObject(cx, obj, proto, ops)) {
|
||||||
|
obj = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JS_ASSERT(ops->objectMap->ops == ops);
|
||||||
|
obj->map = const_cast<JSObjectMap *>(ops->objectMap);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
|
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
|
||||||
objectSize - sizeof(JSObject));
|
objectSize - sizeof(JSObject));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/* Check that the newborn root still holds the object. */
|
||||||
* Root obj to prevent it from being collected out from under this call to
|
JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
|
||||||
* js_NewObject. There's a possibilty of GC under the objectHook call-out
|
|
||||||
* further below.
|
|
||||||
*/
|
|
||||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
|
|
||||||
|
|
||||||
/* Always call the class's getObjectOps hook if it has one. */
|
|
||||||
ops = clasp->getObjectOps
|
|
||||||
? clasp->getObjectOps(cx, clasp)
|
|
||||||
: &js_ObjectOps;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default parent to the parent of the prototype, which was set from
|
|
||||||
* the parent of the prototype's constructor.
|
|
||||||
*/
|
|
||||||
if (proto && !parent)
|
|
||||||
STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto));
|
|
||||||
|
|
||||||
if (!CreateMapForObject(cx, obj, proto, ops))
|
|
||||||
goto bad;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not call debug hooks on trace, because we might be in a non-_FAIL
|
* Do not call debug hooks on trace, because we might be in a non-_FAIL
|
||||||
* builtin. See bug 481444.
|
* builtin. See bug 481444.
|
||||||
*/
|
*/
|
||||||
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
|
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
|
||||||
|
JSAutoTempValueRooter tvr(cx, obj);
|
||||||
JS_KEEP_ATOMS(cx->runtime);
|
JS_KEEP_ATOMS(cx->runtime);
|
||||||
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
|
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
|
||||||
cx->debugHooks->objectHookData);
|
cx->debugHooks->objectHookData);
|
||||||
JS_UNKEEP_ATOMS(cx->runtime);
|
JS_UNKEEP_ATOMS(cx->runtime);
|
||||||
|
cx->weakRoots.newborn[GCX_OBJECT] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
|
||||||
cx->weakRoots.newborn[GCX_OBJECT] = obj;
|
|
||||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||||
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
|
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
|
||||||
jsdtrace_object_create(cx, clasp, obj);
|
jsdtrace_object_create(cx, clasp, obj);
|
||||||
|
@ -3173,28 +3128,21 @@ out:
|
||||||
jsdtrace_object_create_done(cx->fp, clasp);
|
jsdtrace_object_create_done(cx->fp, clasp);
|
||||||
#endif
|
#endif
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
bad:
|
|
||||||
obj = NULL;
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
earlybad:
|
|
||||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
|
||||||
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
|
|
||||||
jsdtrace_object_create(cx, clasp, NULL);
|
|
||||||
if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
|
|
||||||
jsdtrace_object_create_done(cx->fp, clasp);
|
|
||||||
#endif
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
|
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(!clasp->getObjectOps);
|
||||||
|
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
||||||
|
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
|
||||||
|
|
||||||
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
js_HoldScope(OBJ_SCOPE(proto));
|
||||||
|
obj->map = proto->map;
|
||||||
obj->classword = jsuword(clasp);
|
obj->classword = jsuword(clasp);
|
||||||
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||||
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
|
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
|
||||||
|
@ -3203,9 +3151,6 @@ js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
|
||||||
while (slot < JS_INITIAL_NSLOTS)
|
while (slot < JS_INITIAL_NSLOTS)
|
||||||
obj->fslots[slot++] = JSVAL_VOID;
|
obj->fslots[slot++] = JSVAL_VOID;
|
||||||
|
|
||||||
JS_ASSERT(!clasp->getObjectOps);
|
|
||||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
|
||||||
obj->map = js_HoldObjectMap(cx, proto->map);
|
|
||||||
obj->dslots = NULL;
|
obj->dslots = NULL;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -3456,11 +3401,8 @@ bad:
|
||||||
void
|
void
|
||||||
js_FinalizeObject(JSContext *cx, JSObject *obj)
|
js_FinalizeObject(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
JSObjectMap *map;
|
|
||||||
|
|
||||||
/* Cope with stillborn objects that have no map. */
|
/* Cope with stillborn objects that have no map. */
|
||||||
map = obj->map;
|
if (!obj->map)
|
||||||
if (!map)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cx->debugHooks->objectHook) {
|
if (cx->debugHooks->objectHook) {
|
||||||
|
@ -3476,8 +3418,8 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
|
||||||
jsdtrace_object_finalize(obj);
|
jsdtrace_object_finalize(obj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Drop map and free slots. */
|
if (OBJ_IS_NATIVE(obj))
|
||||||
js_DropObjectMap(cx, map, obj);
|
js_DropScope(cx, OBJ_SCOPE(obj), obj);
|
||||||
FreeSlots(cx, obj);
|
FreeSlots(cx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3486,38 +3428,35 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
|
||||||
JSBool
|
JSBool
|
||||||
js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
|
js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
|
||||||
{
|
{
|
||||||
JSObjectMap *map;
|
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||||
JSClass *clasp;
|
|
||||||
|
|
||||||
map = obj->map;
|
JSScope *scope = OBJ_SCOPE(obj);
|
||||||
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
|
JSClass *clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
if (scope->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
|
||||||
if (map->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
|
/* Adjust scope->freeslot to include computed reserved slots, if any. */
|
||||||
/* Adjust map->freeslot to include computed reserved slots, if any. */
|
scope->freeslot += clasp->reserveSlots(cx, obj);
|
||||||
map->freeslot += clasp->reserveSlots(cx, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map->freeslot >= STOBJ_NSLOTS(obj) &&
|
if (scope->freeslot >= STOBJ_NSLOTS(obj) &&
|
||||||
!js_ReallocSlots(cx, obj, map->freeslot + 1, JS_FALSE)) {
|
!js_ReallocSlots(cx, obj, scope->freeslot + 1, JS_FALSE)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* js_ReallocSlots or js_FreeSlot should set the free slots to void. */
|
/* js_ReallocSlots or js_FreeSlot should set the free slots to void. */
|
||||||
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, map->freeslot)));
|
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
|
||||||
*slotp = map->freeslot++;
|
*slotp = scope->freeslot++;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
||||||
{
|
{
|
||||||
JSObjectMap *map;
|
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||||
|
|
||||||
map = obj->map;
|
JSScope *scope = OBJ_SCOPE(obj);
|
||||||
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
|
|
||||||
LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
|
LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
|
||||||
if (map->freeslot == slot + 1) {
|
if (scope->freeslot == slot + 1) {
|
||||||
map->freeslot = slot;
|
scope->freeslot = slot;
|
||||||
|
|
||||||
/* When shrinking, js_ReallocSlots always returns true. */
|
/* When shrinking, js_ReallocSlots always returns true. */
|
||||||
js_ReallocSlots(cx, obj, slot, JS_FALSE);
|
js_ReallocSlots(cx, obj, slot, JS_FALSE);
|
||||||
|
@ -3914,8 +3853,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
proto = OBJ_GET_PROTO(cx, proto)) {
|
proto = OBJ_GET_PROTO(cx, proto)) {
|
||||||
protoIndex++;
|
protoIndex++;
|
||||||
}
|
}
|
||||||
scope = OBJ_SCOPE(obj2);
|
if (!OBJ_IS_NATIVE(obj2)) {
|
||||||
if (!MAP_IS_NATIVE(&scope->map)) {
|
|
||||||
/* Whoops, newresolve handed back a foreign obj2. */
|
/* Whoops, newresolve handed back a foreign obj2. */
|
||||||
JS_ASSERT(obj2 != obj);
|
JS_ASSERT(obj2 != obj);
|
||||||
ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
|
ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
|
||||||
|
@ -3931,6 +3869,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
* not on obj's proto chain. That last case is a
|
* not on obj's proto chain. That last case is a
|
||||||
* "too bad!" case.
|
* "too bad!" case.
|
||||||
*/
|
*/
|
||||||
|
scope = OBJ_SCOPE(obj2);
|
||||||
if (scope->object == obj2)
|
if (scope->object == obj2)
|
||||||
sprop = SCOPE_GET_PROPERTY(scope, id);
|
sprop = SCOPE_GET_PROPERTY(scope, id);
|
||||||
}
|
}
|
||||||
|
@ -3953,8 +3892,8 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
JS_LOCK_OBJ(cx, obj);
|
JS_LOCK_OBJ(cx, obj);
|
||||||
|
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||||
scope = OBJ_SCOPE(obj);
|
scope = OBJ_SCOPE(obj);
|
||||||
JS_ASSERT(MAP_IS_NATIVE(&scope->map));
|
|
||||||
if (scope->object == obj)
|
if (scope->object == obj)
|
||||||
sprop = SCOPE_GET_PROPERTY(scope, id);
|
sprop = SCOPE_GET_PROPERTY(scope, id);
|
||||||
}
|
}
|
||||||
|
@ -5842,8 +5781,8 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
|
||||||
* above.
|
* above.
|
||||||
*/
|
*/
|
||||||
nslots = STOBJ_NSLOTS(obj);
|
nslots = STOBJ_NSLOTS(obj);
|
||||||
if (scope->object == obj && scope->map.freeslot < nslots)
|
if (scope->object == obj && scope->freeslot < nslots)
|
||||||
nslots = scope->map.freeslot;
|
nslots = scope->freeslot;
|
||||||
|
|
||||||
for (i = 0; i != nslots; ++i) {
|
for (i = 0; i != nslots; ++i) {
|
||||||
v = STOBJ_GET_SLOT(obj, i);
|
v = STOBJ_GET_SLOT(obj, i);
|
||||||
|
@ -5877,7 +5816,7 @@ js_Clear(JSContext *cx, JSObject *obj)
|
||||||
n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
|
n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
|
||||||
while (--i >= n)
|
while (--i >= n)
|
||||||
STOBJ_SET_SLOT(obj, i, JSVAL_VOID);
|
STOBJ_SET_SLOT(obj, i, JSVAL_VOID);
|
||||||
scope->map.freeslot = n;
|
scope->freeslot = n;
|
||||||
}
|
}
|
||||||
JS_UNLOCK_OBJ(cx, obj);
|
JS_UNLOCK_OBJ(cx, obj);
|
||||||
}
|
}
|
||||||
|
@ -5926,8 +5865,8 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whether or not we grew nslots, we may need to advance freeslot. */
|
/* Whether or not we grew nslots, we may need to advance freeslot. */
|
||||||
if (scope->object == obj && slot >= scope->map.freeslot)
|
if (scope->object == obj && slot >= scope->freeslot)
|
||||||
scope->map.freeslot = slot + 1;
|
scope->freeslot = slot + 1;
|
||||||
|
|
||||||
STOBJ_SET_SLOT(obj, slot, v);
|
STOBJ_SET_SLOT(obj, slot, v);
|
||||||
GC_POKE(cx, JS_NULL);
|
GC_POKE(cx, JS_NULL);
|
||||||
|
@ -6131,7 +6070,7 @@ js_DumpObject(JSObject *obj)
|
||||||
uint32 i, slots;
|
uint32 i, slots;
|
||||||
JSClass *clasp;
|
JSClass *clasp;
|
||||||
jsuint reservedEnd;
|
jsuint reservedEnd;
|
||||||
JSBool sharesScope = JS_FALSE;
|
bool sharesScope = false;
|
||||||
|
|
||||||
fprintf(stderr, "object %p\n", (void *) obj);
|
fprintf(stderr, "object %p\n", (void *) obj);
|
||||||
clasp = STOBJ_GET_CLASS(obj);
|
clasp = STOBJ_GET_CLASS(obj);
|
||||||
|
@ -6186,7 +6125,9 @@ js_DumpObject(JSObject *obj)
|
||||||
if (clasp->flags & JSCLASS_HAS_PRIVATE)
|
if (clasp->flags & JSCLASS_HAS_PRIVATE)
|
||||||
reservedEnd++;
|
reservedEnd++;
|
||||||
reservedEnd += JSCLASS_RESERVED_SLOTS(clasp);
|
reservedEnd += JSCLASS_RESERVED_SLOTS(clasp);
|
||||||
slots = sharesScope ? reservedEnd : obj->map->freeslot;
|
slots = (OBJ_IS_NATIVE(obj) && !sharesScope)
|
||||||
|
? OBJ_SCOPE(obj)->freeslot
|
||||||
|
: STOBJ_NSLOTS(obj);
|
||||||
for (i = 0; i < slots; i++) {
|
for (i = 0; i < slots; i++) {
|
||||||
fprintf(stderr, " %3d ", i);
|
fprintf(stderr, " %3d ", i);
|
||||||
if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) {
|
if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) {
|
||||||
|
|
|
@ -56,9 +56,14 @@ JS_BEGIN_EXTERN_C
|
||||||
|
|
||||||
/* For detailed comments on these function pointer types, see jsprvtd.h. */
|
/* For detailed comments on these function pointer types, see jsprvtd.h. */
|
||||||
struct JSObjectOps {
|
struct JSObjectOps {
|
||||||
|
/*
|
||||||
|
* Custom shared object map for non-native objects. For native objects
|
||||||
|
* this should be null indicating, that JSObject.map is an instance of
|
||||||
|
* JSScope.
|
||||||
|
*/
|
||||||
|
const JSObjectMap *objectMap;
|
||||||
|
|
||||||
/* Mandatory non-null function pointer members. */
|
/* Mandatory non-null function pointer members. */
|
||||||
JSNewObjectMapOp newObjectMap;
|
|
||||||
JSObjectMapOp destroyObjectMap;
|
|
||||||
JSLookupPropOp lookupProperty;
|
JSLookupPropOp lookupProperty;
|
||||||
JSDefinePropOp defineProperty;
|
JSDefinePropOp defineProperty;
|
||||||
JSPropertyIdOp getProperty;
|
JSPropertyIdOp getProperty;
|
||||||
|
@ -83,9 +88,7 @@ struct JSObjectOps {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSObjectMap {
|
struct JSObjectMap {
|
||||||
jsrefcount nrefs; /* count of all referencing objects */
|
|
||||||
JSObjectOps *ops; /* high level object operation vtable */
|
JSObjectOps *ops; /* high level object operation vtable */
|
||||||
uint32 freeslot; /* index of next free slot in object */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Shorthand macros for frequently-made calls. */
|
/* Shorthand macros for frequently-made calls. */
|
||||||
|
@ -206,8 +209,8 @@ struct JSObject {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* STOBJ prefix means Single Threaded Object. Use the following fast macros to
|
* STOBJ prefix means Single Threaded Object. Use the following fast macros to
|
||||||
* directly manipulate slots in obj when only one thread can access obj and
|
* directly manipulate slots in obj when only one thread can access obj, or
|
||||||
* when obj->map->freeslot can be inconsistent with slots.
|
* when accessing read-only slots within JS_INITIAL_NSLOTS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define STOBJ_NSLOTS(obj) \
|
#define STOBJ_NSLOTS(obj) \
|
||||||
|
@ -266,7 +269,7 @@ STOBJ_GET_CLASS(const JSObject* obj)
|
||||||
JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE)))
|
JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE)))
|
||||||
|
|
||||||
#define OBJ_CHECK_SLOT(obj,slot) \
|
#define OBJ_CHECK_SLOT(obj,slot) \
|
||||||
JS_ASSERT(slot < (obj)->map->freeslot)
|
JS_ASSERT_IF(OBJ_IS_NATIVE(obj), slot < OBJ_SCOPE(obj)->freeslot)
|
||||||
|
|
||||||
#define LOCKED_OBJ_GET_SLOT(obj,slot) \
|
#define LOCKED_OBJ_GET_SLOT(obj,slot) \
|
||||||
(OBJ_CHECK_SLOT(obj, slot), STOBJ_GET_SLOT(obj, slot))
|
(OBJ_CHECK_SLOT(obj, slot), STOBJ_GET_SLOT(obj, slot))
|
||||||
|
@ -368,12 +371,14 @@ STOBJ_GET_CLASS(const JSObject* obj)
|
||||||
#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj)
|
#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj)
|
||||||
#define OBJ_GET_PRIVATE(cx,obj) STOBJ_GET_PRIVATE(obj)
|
#define OBJ_GET_PRIVATE(cx,obj) STOBJ_GET_PRIVATE(obj)
|
||||||
|
|
||||||
/* Test whether a map or object is native. */
|
/*
|
||||||
#define MAP_IS_NATIVE(map) \
|
* Test whether the object is native. FIXME bug 492938: consider how it would
|
||||||
JS_LIKELY((map)->ops == &js_ObjectOps || \
|
* affect the performance to do just the !ops->objectMap check.
|
||||||
(map)->ops->newObjectMap == js_ObjectOps.newObjectMap)
|
*/
|
||||||
|
#define OPS_IS_NATIVE(ops) \
|
||||||
|
JS_LIKELY((ops) == &js_ObjectOps || !(ops)->objectMap)
|
||||||
|
|
||||||
#define OBJ_IS_NATIVE(obj) MAP_IS_NATIVE((obj)->map)
|
#define OBJ_IS_NATIVE(obj) OPS_IS_NATIVE((obj)->map->ops)
|
||||||
|
|
||||||
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
|
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
|
||||||
extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
|
extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
|
||||||
|
@ -502,23 +507,6 @@ extern const char js_defineSetter_str[];
|
||||||
extern const char js_lookupGetter_str[];
|
extern const char js_lookupGetter_str[];
|
||||||
extern const char js_lookupSetter_str[];
|
extern const char js_lookupSetter_str[];
|
||||||
|
|
||||||
extern void
|
|
||||||
js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp);
|
|
||||||
|
|
||||||
extern JSObjectMap *
|
|
||||||
js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj);
|
|
||||||
|
|
||||||
extern void
|
|
||||||
js_DestroyObjectMap(JSContext *cx, JSObjectMap *map);
|
|
||||||
|
|
||||||
extern JSObjectMap *
|
|
||||||
js_HoldObjectMap(JSContext *cx, JSObjectMap *map);
|
|
||||||
|
|
||||||
extern JSObjectMap *
|
|
||||||
js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj);
|
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp);
|
js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp);
|
||||||
|
|
||||||
|
|
|
@ -2973,7 +2973,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||||
!js_ReallocSlots(cx, blockObj, slot + 1, JS_FALSE)) {
|
!js_ReallocSlots(cx, blockObj, slot + 1, JS_FALSE)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
blockObj->map->freeslot = slot + 1;
|
OBJ_SCOPE(blockObj)->freeslot = slot + 1;
|
||||||
STOBJ_SET_SLOT(blockObj, slot, PRIVATE_TO_JSVAL(pn));
|
STOBJ_SET_SLOT(blockObj, slot, PRIVATE_TO_JSVAL(pn));
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -6091,7 +6091,10 @@ CompExprTransplanter::transplant(JSParseNode *pn)
|
||||||
|
|
||||||
case PN_BINARY:
|
case PN_BINARY:
|
||||||
transplant(pn->pn_left);
|
transplant(pn->pn_left);
|
||||||
transplant(pn->pn_right);
|
|
||||||
|
/* Binary TOK_COLON nodes can have left == right. See bug 492714. */
|
||||||
|
if (pn->pn_right != pn->pn_left)
|
||||||
|
transplant(pn->pn_right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PN_UNARY:
|
case PN_UNARY:
|
||||||
|
|
|
@ -183,8 +183,10 @@ JS_BEGIN_EXTERN_C
|
||||||
* TOK_RB list pn_head: list of pn_count array element exprs
|
* TOK_RB list pn_head: list of pn_count array element exprs
|
||||||
* [,,] holes are represented by TOK_COMMA nodes
|
* [,,] holes are represented by TOK_COMMA nodes
|
||||||
* pn_xflags: PN_ENDCOMMA if extra comma at end
|
* pn_xflags: PN_ENDCOMMA if extra comma at end
|
||||||
* TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
|
* TOK_RC list pn_head: list of pn_count binary TOK_COLON nodes
|
||||||
* each has pn_left: property id, pn_right: value
|
* TOK_COLON binary key-value pair in object initializer or
|
||||||
|
* destructuring lhs
|
||||||
|
* pn_left: property id, pn_right: value
|
||||||
* var {x} = object destructuring shorthand shares
|
* var {x} = object destructuring shorthand shares
|
||||||
* PN_NAME node for x on left and right of TOK_COLON
|
* PN_NAME node for x on left and right of TOK_COLON
|
||||||
* node in TOK_RC's list, has PNX_DESTRUCT flag
|
* node in TOK_RC's list, has PNX_DESTRUCT flag
|
||||||
|
|
|
@ -257,30 +257,6 @@ struct JSTempValueRooter {
|
||||||
|
|
||||||
/* JSObjectOps function pointer typedefs. */
|
/* JSObjectOps function pointer typedefs. */
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops
|
|
||||||
* members initialized from the same-named parameters, and with the nslots and
|
|
||||||
* freeslot members initialized according to ops and clasp. Return null on
|
|
||||||
* error, non-null on success.
|
|
||||||
*
|
|
||||||
* JSObjectMaps are reference-counted by generic code in the engine. Usually,
|
|
||||||
* the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref
|
|
||||||
* returned to the caller on success. After a successful construction, some
|
|
||||||
* number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs
|
|
||||||
* reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will
|
|
||||||
* be called to dispose of the map.
|
|
||||||
*/
|
|
||||||
typedef JSObjectMap *
|
|
||||||
(* JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic type for an infallible JSObjectMap operation, used currently by
|
|
||||||
* JSObjectOps.destroyObjectMap.
|
|
||||||
*/
|
|
||||||
typedef void
|
|
||||||
(* JSObjectMapOp)(JSContext *cx, JSObjectMap *map);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for id in obj and its prototype chain, returning false on error or
|
* Look for id in obj and its prototype chain, returning false on error or
|
||||||
* exception, true on success. On success, return null in *propp if id was
|
* exception, true on success. On success, return null in *propp if id was
|
||||||
|
|
|
@ -77,23 +77,23 @@ js_GetMutableScope(JSContext *cx, JSObject *obj)
|
||||||
* birth, and runtime clone of a block objects are never mutated.
|
* birth, and runtime clone of a block objects are never mutated.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(STOBJ_GET_CLASS(obj) != &js_BlockClass);
|
JS_ASSERT(STOBJ_GET_CLASS(obj) != &js_BlockClass);
|
||||||
newscope = js_NewScope(cx, 0, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj),
|
newscope = js_NewScope(cx, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj), obj);
|
||||||
obj);
|
|
||||||
if (!newscope)
|
if (!newscope)
|
||||||
return NULL;
|
return NULL;
|
||||||
JS_LOCK_SCOPE(cx, newscope);
|
JS_LOCK_SCOPE(cx, newscope);
|
||||||
obj->map = js_HoldObjectMap(cx, &newscope->map);
|
obj->map = &newscope->map;
|
||||||
JS_ASSERT(newscope->map.freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj)));
|
|
||||||
|
JS_ASSERT(newscope->freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj)));
|
||||||
clasp = STOBJ_GET_CLASS(obj);
|
clasp = STOBJ_GET_CLASS(obj);
|
||||||
if (clasp->reserveSlots) {
|
if (clasp->reserveSlots) {
|
||||||
freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj);
|
freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj);
|
||||||
if (freeslot > STOBJ_NSLOTS(obj))
|
if (freeslot > STOBJ_NSLOTS(obj))
|
||||||
freeslot = STOBJ_NSLOTS(obj);
|
freeslot = STOBJ_NSLOTS(obj);
|
||||||
if (newscope->map.freeslot < freeslot)
|
if (newscope->freeslot < freeslot)
|
||||||
newscope->map.freeslot = freeslot;
|
newscope->freeslot = freeslot;
|
||||||
}
|
}
|
||||||
scope = (JSScope *) js_DropObjectMap(cx, &scope->map, obj);
|
|
||||||
JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
|
JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
|
||||||
|
js_DropScope(cx, scope, obj);
|
||||||
return newscope;
|
return newscope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,17 +160,19 @@ CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSScope *
|
JSScope *
|
||||||
js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
|
js_NewScope(JSContext *cx, JSObjectOps *ops, JSClass *clasp, JSObject *obj)
|
||||||
JSObject *obj)
|
|
||||||
{
|
{
|
||||||
JSScope *scope;
|
JS_ASSERT(OPS_IS_NATIVE(ops));
|
||||||
|
JS_ASSERT(obj);
|
||||||
|
|
||||||
scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
|
JSScope *scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
|
||||||
if (!scope)
|
if (!scope)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
js_InitObjectMap(&scope->map, nrefs, ops, clasp);
|
scope->map.ops = ops;
|
||||||
scope->object = obj;
|
scope->object = obj;
|
||||||
|
scope->nrefs = 1;
|
||||||
|
scope->freeslot = JSSLOT_FREE(clasp);
|
||||||
scope->flags = 0;
|
scope->flags = 0;
|
||||||
InitMinimalScope(cx, scope);
|
InitMinimalScope(cx, scope);
|
||||||
|
|
||||||
|
@ -203,6 +205,28 @@ js_DestroyScope(JSContext *cx, JSScope *scope)
|
||||||
JS_free(cx, scope);
|
JS_free(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
js_HoldScope(JSScope *scope)
|
||||||
|
{
|
||||||
|
JS_ASSERT(scope->nrefs >= 0);
|
||||||
|
JS_ATOMIC_INCREMENT(&scope->nrefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBool
|
||||||
|
js_DropScope(JSContext *cx, JSScope *scope, JSObject *obj)
|
||||||
|
{
|
||||||
|
JS_ASSERT(scope->nrefs > 0);
|
||||||
|
JS_ATOMIC_DECREMENT(&scope->nrefs);
|
||||||
|
|
||||||
|
if (scope->nrefs == 0) {
|
||||||
|
js_DestroyScope(cx, scope);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (scope->object == obj)
|
||||||
|
scope->object = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef JS_DUMP_PROPTREE_STATS
|
#ifdef JS_DUMP_PROPTREE_STATS
|
||||||
typedef struct JSScopeStats {
|
typedef struct JSScopeStats {
|
||||||
jsrefcount searches;
|
jsrefcount searches;
|
||||||
|
|
|
@ -201,6 +201,8 @@ struct JSScope {
|
||||||
JSTitle title; /* lock state */
|
JSTitle title; /* lock state */
|
||||||
#endif
|
#endif
|
||||||
JSObject *object; /* object that owns this scope */
|
JSObject *object; /* object that owns this scope */
|
||||||
|
jsrefcount nrefs; /* count of all referencing objects */
|
||||||
|
uint32 freeslot; /* index of next free slot in object */
|
||||||
uint32 shape; /* property cache shape identifier */
|
uint32 shape; /* property cache shape identifier */
|
||||||
uint8 flags; /* flags, see below */
|
uint8 flags; /* flags, see below */
|
||||||
int8 hashShift; /* multiplicative hash shift */
|
int8 hashShift; /* multiplicative hash shift */
|
||||||
|
@ -213,7 +215,8 @@ struct JSScope {
|
||||||
|
|
||||||
#define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
|
#define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
|
||||||
|
|
||||||
#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
|
#define OBJ_SCOPE(obj) (JS_ASSERT(OBJ_IS_NATIVE(obj)), \
|
||||||
|
(JSScope *) (obj)->map)
|
||||||
#define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape)
|
#define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape)
|
||||||
|
|
||||||
/* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
|
/* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
|
||||||
|
@ -329,7 +332,7 @@ struct JSScopeProperty {
|
||||||
|
|
||||||
#define SPROP_INVALID_SLOT 0xffffffff
|
#define SPROP_INVALID_SLOT 0xffffffff
|
||||||
|
|
||||||
#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->map.freeslot)
|
#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->freeslot)
|
||||||
#define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
|
#define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
|
||||||
|
|
||||||
#define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
|
#define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
|
||||||
|
@ -396,12 +399,17 @@ extern JSScope *
|
||||||
js_GetMutableScope(JSContext *cx, JSObject *obj);
|
js_GetMutableScope(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
extern JSScope *
|
extern JSScope *
|
||||||
js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
|
js_NewScope(JSContext *cx, JSObjectOps *ops, JSClass *clasp, JSObject *obj);
|
||||||
JSObject *obj);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_DestroyScope(JSContext *cx, JSScope *scope);
|
js_DestroyScope(JSContext *cx, JSScope *scope);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js_HoldScope(JSScope *scope);
|
||||||
|
|
||||||
|
extern JSBool
|
||||||
|
js_DropScope(JSContext *cx, JSScope *scope, JSObject *obj);
|
||||||
|
|
||||||
extern JS_FRIEND_API(JSScopeProperty **)
|
extern JS_FRIEND_API(JSScopeProperty **)
|
||||||
js_SearchScope(JSScope *scope, jsid id, JSBool adding);
|
js_SearchScope(JSScope *scope, jsid id, JSBool adding);
|
||||||
|
|
||||||
|
|
|
@ -5362,7 +5362,7 @@ js_OverfullFragmento(JSTraceMonitor* tm, Fragmento *fragmento)
|
||||||
*/
|
*/
|
||||||
maxsz /= 16;
|
maxsz /= 16;
|
||||||
}
|
}
|
||||||
return (fragmento->_stats.pages > (maxsz >> NJ_LOG2_PAGE_SIZE));
|
return (fragmento->cacheUsed() > maxsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_FORCES_STACK JS_FRIEND_API(void)
|
JS_FORCES_STACK JS_FRIEND_API(void)
|
||||||
|
@ -6301,21 +6301,25 @@ TraceRecorder::binary(LOpcode op)
|
||||||
return JSRS_STOP;
|
return JSRS_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSObjectOps, newObjectMap) == 0);
|
JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, size_t op_offset)
|
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, size_t op_offset)
|
||||||
{
|
{
|
||||||
#define OP(ops) (*(JSObjectOp*) ((char*)(ops) + op_offset))
|
JS_ASSERT(op_offset < sizeof(JSObjectOps));
|
||||||
if (OP(map->ops) != OP(&js_ObjectOps))
|
JS_ASSERT(op_offset % sizeof(void *) == 0);
|
||||||
return false;
|
|
||||||
|
|
||||||
ops_ins = addName(lir->insLoad(LIR_ldp, map_ins, offsetof(JSObjectMap, ops)), "ops");
|
#define OP(ops) (*(void **) ((uint8 *) (ops) + op_offset))
|
||||||
|
void* ptr = OP(map->ops);
|
||||||
|
if (ptr != OP(&js_ObjectOps))
|
||||||
|
return false;
|
||||||
|
#undef OP
|
||||||
|
|
||||||
|
ops_ins = addName(lir->insLoad(LIR_ldp, map_ins, int(offsetof(JSObjectMap, ops))), "ops");
|
||||||
LIns* n = lir->insLoad(LIR_ldp, ops_ins, op_offset);
|
LIns* n = lir->insLoad(LIR_ldp, ops_ins, op_offset);
|
||||||
guard(true,
|
guard(true,
|
||||||
addName(lir->ins2(LIR_eq, n, INS_CONSTFUNPTR(OP(&js_ObjectOps))), "guard(native-map)"),
|
addName(lir->ins2(LIR_eq, n, INS_CONSTPTR(ptr)), "guard(native-map)"),
|
||||||
BRANCH_EXIT);
|
BRANCH_EXIT);
|
||||||
#undef OP
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6340,10 +6344,9 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||||
LIns* ops_ins;
|
LIns* ops_ins;
|
||||||
|
|
||||||
// Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops
|
// Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops
|
||||||
// (newObjectMap == js_ObjectOps.newObjectMap) which is required to use
|
// which is required to use native objects (those whose maps are scopes),
|
||||||
// native objects (those whose maps are scopes), or even more narrow
|
// or even more narrow conditions required because the cache miss case
|
||||||
// conditions required because the cache miss case will call a particular
|
// will call a particular object-op (js_GetProperty, js_SetProperty).
|
||||||
// object-op (js_GetProperty, js_SetProperty).
|
|
||||||
//
|
//
|
||||||
// We parameterize using offsetof and guard on match against the hook at
|
// We parameterize using offsetof and guard on match against the hook at
|
||||||
// the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP
|
// the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP
|
||||||
|
@ -6354,7 +6357,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||||
// No need to guard native-ness of global object.
|
// No need to guard native-ness of global object.
|
||||||
JS_ASSERT(OBJ_IS_NATIVE(globalObj));
|
JS_ASSERT(OBJ_IS_NATIVE(globalObj));
|
||||||
if (aobj != globalObj) {
|
if (aobj != globalObj) {
|
||||||
size_t op_offset = offsetof(JSObjectOps, newObjectMap);
|
size_t op_offset = offsetof(JSObjectOps, objectMap);
|
||||||
if (mode == JOF_PROP || mode == JOF_VARPROP) {
|
if (mode == JOF_PROP || mode == JOF_VARPROP) {
|
||||||
JS_ASSERT(!(format & JOF_SET));
|
JS_ASSERT(!(format & JOF_SET));
|
||||||
op_offset = offsetof(JSObjectOps, getProperty);
|
op_offset = offsetof(JSObjectOps, getProperty);
|
||||||
|
|
|
@ -4912,10 +4912,10 @@ xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* js_XMLObjectOps.newObjectMap == js_NewObjectMap, so XML objects appear to
|
* js_XMLObjectOps.newObjectMap is null, so XML objects appear to be native.
|
||||||
* be native. Thus xml_lookupProperty must return a valid JSScopeProperty
|
* Thus xml_lookupProperty must return a valid JSScopeProperty pointer
|
||||||
* pointer parameter via *propp to signify "property found". Since the only
|
* parameter via *propp to signify "property found". Since the only call to
|
||||||
* call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
|
* xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
|
||||||
* js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
|
* js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
|
||||||
* in the interpreter, the only time we add a JSScopeProperty here is when an
|
* in the interpreter, the only time we add a JSScopeProperty here is when an
|
||||||
* unqualified name is being accessed or when "name in xml" is called.
|
* unqualified name is being accessed or when "name in xml" is called.
|
||||||
|
@ -5428,9 +5428,9 @@ out:
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use js_NewObjectMap so XML objects satisfy OBJ_IS_NATIVE tests. */
|
/* Use NULL for objectMap so XML objects satisfy OBJ_IS_NATIVE tests. */
|
||||||
JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
|
JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
|
||||||
js_NewObjectMap, js_DestroyObjectMap,
|
NULL,
|
||||||
xml_lookupProperty, xml_defineProperty,
|
xml_lookupProperty, xml_defineProperty,
|
||||||
xml_getProperty, xml_setProperty,
|
xml_getProperty, xml_setProperty,
|
||||||
xml_getAttributes, xml_setAttributes,
|
xml_getAttributes, xml_setAttributes,
|
||||||
|
|
|
@ -404,10 +404,14 @@ JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern JSObjectOps JavaArray_ops;
|
||||||
|
|
||||||
|
static const JSObjectMap JavaArrayMap = { &JavaArray_ops };
|
||||||
|
|
||||||
JSObjectOps JavaArray_ops = {
|
JSObjectOps JavaArray_ops = {
|
||||||
|
&JavaArrayMap, /* objectMap */
|
||||||
|
|
||||||
/* Mandatory non-null function pointer members. */
|
/* Mandatory non-null function pointer members. */
|
||||||
jsj_wrapper_newObjectMap, /* newObjectMap */
|
|
||||||
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
|
|
||||||
JavaArray_lookupProperty,
|
JavaArray_lookupProperty,
|
||||||
JavaArray_defineProperty,
|
JavaArray_defineProperty,
|
||||||
JavaArray_getPropertyById, /* getProperty */
|
JavaArray_getPropertyById, /* getProperty */
|
||||||
|
|
|
@ -529,10 +529,14 @@ done:
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern JSObjectOps JavaClass_ops;
|
||||||
|
|
||||||
|
static const JSObjectMap JavaClassMap = { &JavaClass_ops };
|
||||||
|
|
||||||
JSObjectOps JavaClass_ops = {
|
JSObjectOps JavaClass_ops = {
|
||||||
|
&JavaClassMap, /* objectMap */
|
||||||
|
|
||||||
/* Mandatory non-null function pointer members. */
|
/* Mandatory non-null function pointer members. */
|
||||||
jsj_wrapper_newObjectMap, /* newObjectMap */
|
|
||||||
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
|
|
||||||
JavaClass_lookupProperty,
|
JavaClass_lookupProperty,
|
||||||
JavaClass_defineProperty,
|
JavaClass_defineProperty,
|
||||||
JavaClass_getPropertyById, /* getProperty */
|
JavaClass_getPropertyById, /* getProperty */
|
||||||
|
|
|
@ -999,32 +999,10 @@ JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
|
||||||
|
|
||||||
#define JSJ_SLOT_COUNT (JSSLOT_PRIVATE+1)
|
#define JSJ_SLOT_COUNT (JSSLOT_PRIVATE+1)
|
||||||
|
|
||||||
JSObjectMap *
|
|
||||||
jsj_wrapper_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj)
|
|
||||||
{
|
|
||||||
JSObjectMap * map;
|
|
||||||
|
|
||||||
map = (JSObjectMap *) JS_malloc(cx, sizeof(JSObjectMap));
|
|
||||||
if (map) {
|
|
||||||
map->nrefs = nrefs;
|
|
||||||
map->ops = ops;
|
|
||||||
map->freeslot = JSJ_SLOT_COUNT;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
jsj_wrapper_destroyObjectMap(JSContext *cx, JSObjectMap *map)
|
|
||||||
{
|
|
||||||
JS_free(cx, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
jsval
|
jsval
|
||||||
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
||||||
{
|
{
|
||||||
JS_ASSERT(slot < JSJ_SLOT_COUNT);
|
JS_ASSERT(slot < JSJ_SLOT_COUNT);
|
||||||
JS_ASSERT(obj->map->freeslot == JSJ_SLOT_COUNT);
|
|
||||||
return STOBJ_GET_SLOT(obj, slot);
|
return STOBJ_GET_SLOT(obj, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,15 +1010,18 @@ JSBool
|
||||||
jsj_wrapper_setRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
jsj_wrapper_setRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||||
{
|
{
|
||||||
JS_ASSERT(slot < JSJ_SLOT_COUNT);
|
JS_ASSERT(slot < JSJ_SLOT_COUNT);
|
||||||
JS_ASSERT(obj->map->freeslot == JSJ_SLOT_COUNT);
|
|
||||||
STOBJ_SET_SLOT(obj, slot, v);
|
STOBJ_SET_SLOT(obj, slot, v);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern JSObjectOps JavaObject_ops;
|
||||||
|
|
||||||
|
static const JSObjectMap JavaObjectMap = { &JavaObject_ops };
|
||||||
|
|
||||||
JSObjectOps JavaObject_ops = {
|
JSObjectOps JavaObject_ops = {
|
||||||
|
&JavaObjectMap, /* objectMap */
|
||||||
|
|
||||||
/* Mandatory non-null function pointer members. */
|
/* Mandatory non-null function pointer members. */
|
||||||
jsj_wrapper_newObjectMap, /* newObjectMap */
|
|
||||||
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
|
|
||||||
JavaObject_lookupProperty,
|
JavaObject_lookupProperty,
|
||||||
JavaObject_defineProperty,
|
JavaObject_defineProperty,
|
||||||
JavaObject_getPropertyById, /* getProperty */
|
JavaObject_getPropertyById, /* getProperty */
|
||||||
|
|
|
@ -643,13 +643,6 @@ jsj_EnterJava(JSContext *cx, JNIEnv **envp);
|
||||||
extern void
|
extern void
|
||||||
jsj_ExitJava(JSJavaThreadState *jsj_env);
|
jsj_ExitJava(JSJavaThreadState *jsj_env);
|
||||||
|
|
||||||
extern JSObjectMap *
|
|
||||||
jsj_wrapper_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
|
|
||||||
JSClass *clasp, JSObject *obj);
|
|
||||||
|
|
||||||
extern void
|
|
||||||
jsj_wrapper_destroyObjectMap(JSContext *cx, JSObjectMap *map);
|
|
||||||
|
|
||||||
extern jsval
|
extern jsval
|
||||||
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
|
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче