This commit is contained in:
Peter Van der Beken 2009-05-15 16:39:20 +02:00
Родитель a13d3e8fd0 ed5dd519a5
Коммит 19f5997758
157 изменённых файлов: 3499 добавлений и 2400 удалений

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

@ -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 OShannessy <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 OShannessy <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, &region); 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;
&region);
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 (&region); 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, &region->rgn)) if (! pixman_image_set_clip_region32 (surface->pixman_image, region? &region->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 (&region->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 (&region->rgn); pixman_region32_init (&region->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 (&region->rgn, pixman_region32_init_rect (&region->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 (&region->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 (&region->rgn); pixman_region32_fini (&region->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 (&region->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 (&region->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 (&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 (&region->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 (&region->rgn); return pixman_region32_n_rects (&region->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 (&region->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 (&region->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 (&region->rgn); pixman_box32_t *pextents;
if (region->status) {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
return;
}
pextents = pixman_region32_extents (&region->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 (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (&region);
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 (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (&region);
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 (&region,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
pixman_region32_fini (&region);
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 (&region->rgn); if (region->status)
} return TRUE;
return ! pixman_region32_not_empty (&region->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 (&region->rgn, x, y); if (region->status)
} return;
pixman_region_overlap_t pixman_region32_translate (&region->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 (&region->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 (&region->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 (&region->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.

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

@ -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);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше