merge fx-team to m-c

This commit is contained in:
Rob Campbell 2011-11-21 10:19:34 -04:00
commit 86ea298eb5
316 changed files with 13154 additions and 4755 deletions

View File

@ -592,8 +592,8 @@ NotificationController::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
if (aThisEvent->mPackedEvent) {
aThisEvent->mPackedEvent->mEventType =
aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
static_cast<PRUint32>(nsIAccessibleEvent::EVENT_SELECTION_ADD) :
static_cast<PRUint32>(nsIAccessibleEvent::EVENT_SELECTION_REMOVE);
nsIAccessibleEvent::EVENT_SELECTION_ADD :
nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
aThisEvent->mPackedEvent->mEventRule =
AccEvent::eCoalesceSelectionChange;
@ -603,8 +603,8 @@ NotificationController::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
aThisEvent->mEventType =
aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ?
static_cast<PRUint32>(nsIAccessibleEvent::EVENT_SELECTION_ADD) :
static_cast<PRUint32>(nsIAccessibleEvent::EVENT_SELECTION_REMOVE);
nsIAccessibleEvent::EVENT_SELECTION_ADD :
nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
return;
}

View File

@ -440,7 +440,8 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
eNoValue,
eNoAction,
eNoLiveAttr,
kNoReqStates
kNoReqStates,
eARIAOrientation
},
{
"slider",
@ -450,6 +451,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
eNoAction,
eNoLiveAttr,
kNoReqStates,
eARIAOrientation,
eARIAReadonly
},
{
@ -649,8 +651,8 @@ nsStateMapEntry nsARIAMap::gWAIStateMap[] = {
// eARIAOrientation
nsStateMapEntry(&nsGkAtoms::aria_orientation, eUseFirstState,
"vertical", states::VERTICAL,
"horizontal", states::HORIZONTAL),
"horizontal", states::HORIZONTAL,
"vertical", states::VERTICAL),
// eARIAPressed
nsStateMapEntry(&nsGkAtoms::aria_pressed, kMixedType,

View File

@ -191,7 +191,7 @@ __try {
if (aTargetIndex < 0 || aTargetIndex >= mTargets.Length() || !aTarget)
return E_INVALIDARG;
mTargets[aTargetIndex]->QueryInterface((const nsID&) IID_IUnknown, (void**) aTarget);
mTargets[aTargetIndex]->QueryNativeInterface(IID_IUnknown, (void**) aTarget);
return S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }

View File

@ -124,10 +124,16 @@
testStates("aria_main_anchor", STATE_SELECTABLE);
testStates("aria_navigation_anchor", STATE_SELECTABLE);
// scrollbar
testStates("aria_scrollbar", 0, EXT_STATE_VERTICAL);
// aria-orientation (applied to scrollbar, separator, slider)
testStates("aria_scrollbar", 0, EXT_STATE_HORIZONTAL);
testStates("aria_hscrollbar", 0, EXT_STATE_HORIZONTAL);
testStates("aria_vscrollbar", 0, EXT_STATE_VERTICAL);
testStates("aria_separator", 0, EXT_STATE_HORIZONTAL);
testStates("aria_hseparator", 0, EXT_STATE_HORIZONTAL);
testStates("aria_vseparator", 0, EXT_STATE_VERTICAL);
testStates("aria_slider", 0, EXT_STATE_HORIZONTAL);
testStates("aria_hslider", 0, EXT_STATE_HORIZONTAL);
testStates("aria_vslider", 0, EXT_STATE_VERTICAL);
SimpleTest.finish();
}
@ -160,6 +166,11 @@
title="aria-autocomplete not supported on standard form text input controls">
Mozilla Bug 681674
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=681674"
title="aria-orientation should be applied to separator and slider roles">
Mozilla Bug 681674
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
@ -227,9 +238,15 @@
<a id="aria_main_anchor" role="main" name="main_anchor">main</a>
<a id="aria_navigation_anchor" role="navigation" name="nav_anchor">nav</a>
<!-- scrollbar -->
<div id="aria_scrollbar" role="scrollbar">scrollbar</a>
<div id="aria_hscrollbar" role="scrollbar" aria-orientation="horizontal">horizontal scrollbar</a>
<div id="aria_vscrollbar" role="scrollbar" aria-orientation="vertical">vertical scrollbar</a>
<!-- aria-orientation -->
<div id="aria_scrollbar" role="scrollbar">scrollbar</div>
<div id="aria_hscrollbar" role="scrollbar" aria-orientation="horizontal">horizontal scrollbar</div>
<div id="aria_vscrollbar" role="scrollbar" aria-orientation="vertical">vertical scrollbar</div>
<div id="aria_separator" role="separator">separator</div>
<div id="aria_hseparator" role="separator" aria-orientation="horizontal">horizontal separator</div>
<div id="aria_vseparator" role="separator" aria-orientation="vertical">vertical separator</div>
<div id="aria_slider" role="slider">slider</div>
<div id="aria_hslider" role="slider" aria-orientation="horizontal">horizontal slider</div>
<div id="aria_vslider" role="slider" aria-orientation="vertical">vertical slider</div>
</body>
</html>

View File

@ -36,9 +36,9 @@
#
# ***** END LICENSE BLOCK *****
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
// Bug 671101 - directly using webNavigation in this context
// causes docshells to leak

View File

@ -260,10 +260,10 @@ var gTests = [
function nextTest() {
if (gTests.length) {
var test = gTests.shift();
info("Start of test: " + test.desc);
test.run();
waitForFocus(nextTest);
waitForFocus(function() {
info("Start of test: " + test.desc);
test.run();
});
}
else {
// Collapse the personal toolbar if needed.
@ -283,6 +283,6 @@ function test() {
if (wasCollapsed)
setToolbarVisibility(toolbar, true);
waitForFocus(nextTest);
nextTest();
}

View File

@ -36,7 +36,7 @@
"use strict";
const Cu = Components.utils;
let Cu = Components.utils;
Cu.import("resource:///modules/tabview/utils.jsm");

View File

@ -56,6 +56,7 @@ endif
DIRS += pgo
ifdef ENABLE_TESTS
DIRS += autoconf/test
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
DIRS += mobile/sutagent/android \
mobile/sutagent/android/watcher \

View File

@ -1,4 +1,4 @@
#! /usr/bin/env perl
#!/usr/bin/env perl
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
@ -16,10 +16,12 @@
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1999
# Portions created by the Initial Developer are Copyright (C) 1999-2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Steve Lamm <slamm@netscape.com>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
@ -35,29 +37,81 @@
#
# ***** END LICENSE BLOCK *****
# make-makefiles - Quickly create Makefiles for subdirectories.
# Also, creates any needed subdirectories.
#
# usage: make-makefiles [ -t <topsrcdir> -p <print_topsrcdir> -d <depth> ] [ <subdir> | <subdir>/Makefile ] ...
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
use Getopt::Long;
# Send comments, improvements, bugs to Steve Lamm (slamm@netscape.com).
use Benchmark;
use Cwd;
use File::Basename;
use File::Copy;
use File::Path qw{mkpath};
#$debug = 1;
##-------------------##
##---] EXPORTS [---##
##-------------------##
our $VERSION = qw(2.0);
if ($^O eq 'msys') {
$pwdcmd = 'pwd -W';
##--------------------##
##---] INCLUDES [---##
##--------------------##
##############################################################
# pymake: special case path handling for windows cmd shell.
# if invoked by cmd.exe and msys-perl is in play
# $0 may contain a drive letter
# modules use-or-expect msys/unix paths
# adjust $0 => C:/foo => /c/foo so string tests and
# manipulation can by applied properly.
##############################################################
sub BEGIN
{
if ($^O eq 'msys' && $ENV{PATH} =~ m!\w:/!)
{
$0 =~ s!^(\w):!/$1!;
}
eval 'use FindBin';
die $@ if ($@);
}
else {
$pwdcmd = 'pwd';
use lib $FindBin::Bin;
use makemakefile;
##-------------------##
##---] GLOBALS [---##
##-------------------##
my %argv;
my $t0 = Benchmark->new();
sub END
{
if ($argv{bench})
{
my $t1 = Benchmark->new();
my $delta = timediff($t1, $t0);
print STDERR timestr($delta), "\n";
}
}
##----------------##
##---] MAIN [---##
##----------------##
umask 0;
my $debug = $argv{debug} || 0;
my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd';
# Determine various tree path variables
#
($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV);
my ($topsrcdir, $ptopsrcdir, $depth, @makefiles) = parse_arguments(@ARGV);
$object_fullpath = `$pwdcmd`;
my $object_fullpath = `$pwdcmd`; # Cwd::getcwd()
chdir $depth;
$object_root = `$pwdcmd`;
my $object_root = `$pwdcmd`; # Cwd::getcwd()
chomp $object_fullpath;
chomp $object_root;
@ -65,24 +119,23 @@ chomp $object_root;
# 'make-makefile' was called. For example, if make-makefile was
# called from "mozilla/gfx/src", then $source_subdir would be
# "gfx/src/".
$source_subdir = "$object_fullpath/";
my $source_subdir = "$object_fullpath/";
my $quoted_object_root = quotemeta($object_root);
$source_subdir =~ s|^$quoted_object_root/||;
# Prefix makefiles with $source_subdir so that paths
# will be relative to the top of the object tree.
#
for $makefile (@makefiles) {
my $makefile;
for $makefile (@makefiles) { # dead code ?
$makefile = "$source_subdir$makefile";
}
create_directories(@makefiles);
# Find the path to the source directory based on how 'make-makefile'
# was invoked. The path is either relative to the object directory
# or an absolute path.
$given_srcdir = find_srcdir($topsrcdir, $depth);
$pgiven_srcdir = find_srcdir($ptopsrcdir, $depth);
my $given_srcdir = find_srcdir($topsrcdir, $depth);
my $pgiven_srcdir = find_srcdir($ptopsrcdir, $depth);
if ($debug) {
warn "object_fullpath = $object_fullpath\n";
@ -92,18 +145,21 @@ if ($debug) {
warn "given_srcdir = $given_srcdir\n";
}
@unhandled = update_makefiles($given_srcdir, $pgiven_srcdir, @makefiles);
my @errors;
my @unhandled = update_makefiles_legacy($given_srcdir, $pgiven_srcdir, @makefiles);
push(@errors, $@) if ($@);
run_config_status(@unhandled);
push(@errors, $@) if ($@ && $argv{'no-warnings'});
exit scalar(@errors);
# end of Main
############################################################
sub dirname {
return $_[0] =~ /(.*)\/.*/ ? "$1" : '.';
}
###########################################################################
# find_depth: Pull the value of DEPTH out of a Makefile (or Makefile.in)
###########################################################################
sub find_depth {
my $depth = '';
open(MAKEFILE, "<$_[0]") || die "Unable to open $_[0]: $!\n";
@ -116,39 +172,115 @@ sub find_depth {
return $depth;
}
###########################################################################
## Intent: Parse command line arguments and assign values
###########################################################################
sub parse_arguments {
my @args = @_;
my $depth = '';
my $topsrcdir = '';
my $ptopsrcdir;
my @makefiles = ();
while (1) {
if ($args[0] eq '-d') {
$depth = $args[1];
shift @args;
shift @args;
} elsif ($args[0] eq '-t') {
$topsrcdir = $args[1];
shift @args;
shift @args;
} elsif ($args[0] eq '-p') {
$ptopsrcdir = $args[1];
shift @args;
shift @args;
} else {
last;
}
my @arglist = qw(badtokens! bench
chdir=s
debug
depth|d=s
enhanced
obj=s top|t=s ptop|p=s
src=s dst=s
);
unless(GetOptions(\%argv, @arglist))
{
my $script = join('/', $FindBin::RealBin, $FindBin::Script);
system("perldoc $script </dev/null");
exit
}
@args = @ARGV;
my $topsrcdir = $argv{top} || '';
if (! $topsrcdir)
{
$topsrcdir = $argv{top} = getTopDir();
}
if ($topsrcdir eq '') {
$topsrcdir = $0; # Figure out topsrcdir based on program name.
$topsrcdir =~ s|/?build/autoconf/.*$||;
my $ptopsrcdir ||= $argv{ptop} || $topsrcdir || '';
## Init --no- switch values
foreach my $var (qw(badtokens exclusions warnings))
{
$argv{"no-${var}"} = $argv{$var} || 0;
}
if ($ptopsrcdir eq '') {
$ptopsrcdir = $topsrcdir;
# Propogate parsed arguments for module use [--debug, --verbose]
while (my($k, $v) = each %argv)
{
$main::argv{$k} = $v;
}
if ($depth eq '') {
if ($argv{chdir})
{
chdir $argv{chdir} || die "chdir $argv{chdir} failed: $!";
}
##############################################################
## Arguments allowing make-makefile to be invoked from $topsrc
##############################################################
if (!$argv{top} || !$argv{obj})
{
}
## Limit access to container makefiles for now
elsif ($argv{enhanced})
{
my @errors;
## iterate over @ARGV to preserve original filename for 'unhandled'
my @files = map{ getRelPath($_) } @ARGV;
my $top = getTopDir();
my $obj = getObjDir();
mkdirr(map{ "$obj/$_" } @files);
push(@errors, $@) if ($@); # legacy behavior: do not exit with status
my $exclude = join('/', $FindBin::RealBin, $FindBin::Script);
$exclude .= '.excl'; # $argv{exclude}
my %exclude = getExclusions($exclude);
my @unhandled;
foreach my $relpath (@files)
{
my $rel = join('/', $relpath, 'Makefile.in');
my $mf = join('/', $top, $rel);
next if ($exclude{$rel});
print STDERR " ** relpath=[$relpath], mf=[$mf]\n" if ($main::argv{debug});
my $rc = updateMakefiles($relpath, {depth=>$depth, obj=>$obj, top=>$top});
if ($@)
{
push(@errors, $@);
}
elsif ($rc eq 'badtokens')
{
push(@unhandled, $mf);
}
}
run_config_status(@unhandled);
push(@errors, $@) if ($@ && $argv{'no-warnings'});
exit scalar(@errors);
}
my $depth = $argv{depth} || '';
if (! $depth)
{
foreach my $fyl (@args)
{
if (my $tmp = find_depth($fyl))
{
$depth = $tmp;
last;
}
}
}
if (! $depth) {
# Use $(DEPTH) in the Makefile or Makefile.in to determine the depth
if (-e "Makefile.in") {
$depth = find_depth("Makefile.in");
@ -166,34 +298,21 @@ sub parse_arguments {
# Build the list of makefiles to generate
#
@makefiles = ();
my $makefile;
foreach $makefile (@args) {
$makefile =~ s/\.in$//;
$makefile =~ s/\/$//;
$makefile =~ /Makefile$/
or $makefile =~ /^\.\//
or $makefile .= "/Makefile";
while (@args)
{
next unless my $makefile = shift @args;
$makefile =~ s/\.in$//;
$makefile =~ s/\/$//;
$makefile =~ /Makefile$/
or $makefile =~ /^\.\//
or $makefile .= "/Makefile";
push @makefiles, "$makefile";
}
@makefiles = "Makefile" unless @args;
@makefiles = "Makefile" unless @makefiles;
return ($topsrcdir, $ptopsrcdir, $depth, @makefiles);
}
# Create all the directories at once.
# This can be much faster than calling mkdir() for each one.
sub create_directories {
my @makefiles = @_;
my @dirs = ();
my $ac_file;
foreach $ac_file (@makefiles) {
push @dirs, dirname($ac_file);
}
# Call mkdir with the directories sorted by subdir count (how many /'s)
system "mkdir -p ". join(' ', map("\"$_\"", @dirs)) if @dirs;
}
# Find the top of the source directory
# (Assuming that the executable is in $top_srcdir/build/autoconf)
sub find_srcdir {
@ -214,111 +333,146 @@ sub find_srcdir {
return $ac_given_srcdir;
}
# Output the makefiles.
#
sub update_makefiles {
my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_;
my @unhandled=();
1;
###########################################################################
## perldoc
###########################################################################
__END__
my $ac_file;
foreach $ac_file (@makefiles) {
my $ac_file_in = "$ac_given_srcdir/${ac_file}.in";
my $ac_dir = dirname($ac_file);
my $ac_dots = '';
my $ac_dir_suffix = '';
my $srcdir = '.';
my $top_srcdir = '.';
=head1 NAME
# Determine $srcdir and $top_srcdir
#
if ($ac_dir ne '.') {
$ac_dir_suffix = "/$ac_dir";
$ac_dir_suffix =~ s%^/\./%/%;
$ac_dots = $ac_dir_suffix;
# Remove .. components from the provided dir suffix, and
# also the forward path components they were reversing.
my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g;
while ($backtracks--) {
$ac_dots =~ s%/[^/]*%%;
}
$ac_dots =~ s%/[^/]*%../%g;
}
if ($ac_given_srcdir eq '.') {
if ($ac_dots ne '') {
$top_srcdir = $ac_dots;
$top_srcdir =~ s%/$%%;
}
} elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) {
$srcdir = "$pac_given_srcdir$ac_dir_suffix";
$top_srcdir = "$pac_given_srcdir";
} else {
if ($debug) {
print "ac_dots = $ac_dots\n";
print "ac_dir_suffix = $ac_dir_suffix\n";
}
$srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix";
$top_srcdir = "$ac_dots$ac_given_srcdir";
}
make-makefile - Generate a Makefile from a F<Makefile.in> template
if ($debug) {
print "ac_dir = $ac_dir\n";
print "ac_file = $ac_file\n";
print "ac_file_in = $ac_file_in\n";
print "srcdir = $srcdir\n";
print "top_srcdir = $top_srcdir\n";
print "cwd = " . `$pwdcmd` . "\n";
}
=head1 SYNOPSIS
# Copy the file and make substitutions.
# @srcdir@ -> value of $srcdir
# @top_srcdir@ -> value of $top_srcdir
#
if (-e $ac_file) {
next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date.
warn "updating $ac_file\n";
} else {
warn "creating $ac_file\n";
}
make-makefile [--top t] [--obj o] [--depth d] foo/bar/Makefile.in tans/fans/Makefile foo/bar
open INFILE, "<$ac_file_in" or do {
warn "$0: Cannot read $ac_file_in: No such file or directory\n";
next;
};
open OUTFILE, ">$ac_file" or do {
warn "$0: Unable to create $ac_file\n";
next;
};
=head1 DESCRIPTION
while (<INFILE>) {
#if (/\@[_a-zA-Z]*\@.*\@[_a-zA-Z]*\@/) {
# #warn "Two defines on a line:$ac_file:$.:$_";
# push @unhandled, $ac_file;
# last;
#}
Given options and makefile path arguments determine path to the template
F<Makefile.in> beneath a source directory and path to generated F<Makefile>
beneath $MOZ_OBJDIR. DEPTH from destination directory to the 'root' will
also be determined. F<Makefile.in> will be read in, template strings of the
gorm @token@ will be replaced with derived values and a generated makefile
will be written out as F<Makefile>.
s/\@srcdir\@/$srcdir/g;
s/\@top_srcdir\@/$top_srcdir/g;
Makefile DEPTH= can be determined in a few different ways:
o The string C<DEPTH=../../..> may be embedded within F<Makefile.in>.
o Search parent directories for F<Makefile.in> and use it to assign the child.
if (/\@[_a-zA-Z]*\@/) {
#warn "Unknown variable:$ac_file:$.:$_";
push @unhandled, $ac_file;
last;
}
print OUTFILE;
}
close INFILE;
close OUTFILE;
}
return @unhandled;
}
sub run_config_status {
my @unhandled = @_;
=head2 Option List
# Run config.status with any unhandled files.
#
if (@unhandled) {
$ENV{CONFIG_FILES}= join ' ', @unhandled;
system "./config.status";
}
}
=over 4
=item --chdir
Move to this directory before doing anything else
=item -d, --depth
Explicitly specify the relative path from directory containing Makefile.in
to the top sandbox directory. memory/makefile, DEPTH=../.., js/src/config, DEPTH=..
=item --enhanced
Use alternate/simplified path construction when options --top and --obj are
passed. This feature will be used by container makefiles to support makefile
generation while cd'd into the sandbox top directory.
=item -t, --top
Path the root of a development sandbox.
=item --obj
Path to object directory where generated makefile will be written ($MOZ_OBJDIR).
=item --ptop
Print top source dir
=back
=head2 Options List DEBUG
=over 4
=item --bench
Enable script benchmarking, report elapsed runtime.
=item --debug
Enable script debug mode.
=back
=head2 Options List --NO-
=over 4
=item --no-badtokens (wip)
Handle unexpanded @token@ makefile tokens as an error condition.
Do not rely on system(config.status) to externally supply values.
=item --no-excludes
Ignore file entries on the exclusion list, generate everything.
=item --no-warnings
Warnings are handled as an error condition.
=back
=head2 Examples
=over 4
=item * make-makefile -t /mozilla/nightly -d . memory/mozalloc
cd $MOZ_OBJDIR;
--top and --depth are explicitly set for generting memory/mozalloc/Makefile.
=item * make-makefile -t /mozilla/nightly -d ../../../.. html5lib_tree_construction/Makefile
cd $MOZ_OBJDIR/parser/htmlparser/tests/mochitest
--top and --depth are explicitly set for generting a makefile from within
a subdirectory of $MOZ_OBJDIR
=item * make-makefile --top /mozilla/nightly --obj /mozilla/nightly/obj memory/mozalloc
With --top and --obj explicitly set generate $MOZ_OBJDIR/memory/mozalloc/Makefile
while sitting in the sandbox root.
=back
=head2 Work In Progress
=over 4
=item --no-badtokens
Fail on unexpanded @foo@ makefile tokens. Any tokens that can be expanded
directly by make-makefile will avoid config.status shell overhead.
=item Depth from delta(--obj, --top)
If DEPTH= has not been embedded within a makefile the value could
be set directly if --top and --obj are specified and the paths overlap.
=back
=head1 SEE ALSO
L<config/rules.mk>
=cut

View File

@ -0,0 +1,5 @@
###########################################################################
## Intent: Exclusion list for container make builds
###########################################################################
# EOF

View File

@ -0,0 +1,745 @@
package makemakefile;
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1999-2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Steve Lamm <slamm@netscape.com>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of 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 *****
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
# use feature 'state'; 5.10+ not available everywhere
##-------------------##
##---] EXPORTS [---##
##-------------------##
our $VERSION = qw(2.0);
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(dirname_legacy
getConfig getDepth getRelPath getObjDir getTopDir mkdirr
getExclusions
run_config_status
updateMakefiles
update_makefiles_legacy
);
##--------------------##
##---] INCLUDES [---##
##--------------------##
use Cwd;
use Cwd qw{abs_path};
use FindBin;
use File::Basename;
use File::Copy;
##-------------------##
##---] GLOBALS [---##
##-------------------##
umask 0;
my $cwd = Cwd::abs_path('.');
my %argv;
###########################################################################
## Intent: Helper function, retrieve contents of a file with error checking
## -----------------------------------------------------------------------
## Args:
## scalar path to input file
## Returns:
## array contents of the given file
## $@ set on error
###########################################################################
sub cat
{
my $fyl = shift || '';
$@ = '';
my @data;
local *FYL;
if (!open(FYL, $fyl))
{
$@ = "open($fyl) failed: $!";
}
else
{
@data = <FYL>;
close(FYL);
}
return @data;
} # cat
###########################################################################
## Intent: Return directory path for a given argument
## -----------------------------------------------------------------------
## -----------------------------------------------------------------------
## Todo:
## o Check if function can be replaced by File::Basename::dirname()
###########################################################################
sub dirname_legacy
{
my $str = (@_ && defined($_[0])) ? shift : '';
return $str =~ /(.*)\/.*/ ? "$1" : '.';
}
###########################################################################
## Intent: Given a list of makefile paths recursively create all
## directories between file and the root
## -----------------------------------------------------------------------
## Args:
## array A list of makefiles
## fargs Function arguments
## mode Filesystem mode used for directory creation
## Returns:
## $@ Set on error
## 0 on success
## -----------------------------------------------------------------------
## Note:
## Reporting directory creation can be enabled by the --verbose
## command line argument.
###########################################################################
sub mkdirr
{
my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : ();
my $mode = $fargs{mode} || 0755;
my $verbose = $main::argv{verbose} || 0;
$@ = '' unless ($fargs{recursive});
$fargs{recursive} = 1;
my @errors;
push(@errors, $@) if ($@);
foreach my $path (@_)
{
(my $dir = $path) =~ s%/?Makefile[^/]*$%%o;
next unless (length($dir));
next if (-e $dir);
mkdirr( dirname($dir), \%fargs);
eval{ File::Path::mkpath($dir, $verbose, 0755); };
push(@errors, $@) if ($@);
}
$@ = join("\n", @errors);
return $@ ? 0 : 1;
} # mkdirr
###########################################################################
## Intent: Read in configure values and return a hash of key/value pairs
## -----------------------------------------------------------------------
## Args:
## fargs Function arguments
## reset clear value storage and repopulate
## Returns:
## hash configure data to use for makefile substitutions
## -----------------------------------------------------------------------
## Todo: wrapper for reading config* and run_config_status
###########################################################################
my %_CONFIG_; # todo: state %config; w/5.10
sub getConfig
{
my %fargs = (@_ && ref($_[$#_]) eq 'HASH') ? %{ (pop) } : ();
if ($fargs{reset})
{
%_CONFIG_ = ();
shift;
}
#my $ac_file_in = "$ac_given_srcdir/${ac_file}.in";
#my $ac_dir = dirname_legacy($ac_file);
#my $ac_dots = '';
#my $ac_dir_suffix = '';
#my $srcdir = '.';
#my $top_srcdir = '.';
unless (%_CONFIG_)
{
while (@_)
{
my ($k, $v) = splice(@_, 0, 2);
$_CONFIG_{$k} = $v;
}
}
return %_CONFIG_;
} # getConfig
###########################################################################
## Intent: Determine path depth between leaf and root directory.
## o DEPTH= may be set by makefile content
## o DEPTH= may be set by Makefile in a parent
## o Manually determine by relpath form leaf to sandbox top
## -----------------------------------------------------------------------
## Args:
## scalar Path to makefile or directory to determine DEPTH for
## Returns:
## scalar Relative path from leaf to root directory
## -----------------------------------------------------------------------
###########################################################################
sub getDepth($)
{
my $fyl = shift || '';
my @path = split(m%/%o, $fyl);
pop(@path) if ('Makefile' eq substr($path[$#path], 0, 8));
my $depth;
my @depth;
my $top = getTopDir();
my @top = split(m%/%o, $top);
my @pathNoTop = @path;
splice(@pathNoTop, 0, scalar(@top));
SEARCH:
while (@path)
{
## Search for a file containing DEPTH=../..
foreach my $fyl ( qw{Makefile.in Makefile} )
{
my $path = join('/', @path, $fyl);
local *FYL;
if (!open(FYL, $path)) {} # NOP
elsif (my @tmp = map{ /^\s*DEPTH\s*=\s*([\.\/]+)/o ? $1 : () } <FYL>)
{
$depth = join('/', @depth, shift @tmp);
last SEARCH;
}
close(FYL);
}
pop @path;
pop @pathNoTop;
if (0 == scalar(@pathNoTop))
{
$depth = join('/', @depth);
last;
}
## Construct path manually
push(@depth, '..');
}
return $depth;
} # getDepth
###########################################################################
## Intent: Read in the exclusion file
###########################################################################
sub getExclusions
{
my $file = shift || '';
return () if ($main::argv{'no-exclusions'});
my %exclude;
if ($file)
{
my @data = cat($file);
foreach (@data)
{
next unless ($_);
next if (/^\s*\#/o);
next unless (m%/%);
chomp;
$exclude{$_}++;
}
}
return %exclude;
} # getExclusions
###########################################################################
## Intent: Given the path to a makefile beneath either src or obj
## derive the relative path prefix between makefile and root.
###########################################################################
sub getRelPath
{
my $path0 = shift;
my $abspath;
# Determine type and orientation
my $name = basename($path0);
my $haveMF = ($name eq 'Makefile.in') ? 1
: ($name eq 'Makefile') ? -1
: 0
;
####################################################
## Prep work: form a relative path with ../ removed
####################################################
my $top = getTopDir();
my $obj = getObjDir();
## If the same Makefile will be created alongside Makefile.in
my $topQM = quotemeta($top);
my $objQM = quotemeta($obj);
if ('..' eq substr($path0, 0, 2))
{
my @cwd = split(m%/%, $cwd);
my @pth = split(m%/%, $path0);
while (@pth && $pth[0] eq '..')
{
pop(@cwd);
shift @pth;
}
$path0 = join('/', @cwd, @pth);
$abspath = $path0;
}
if ('/' eq substr($path0, 0, 1))
{
$path0 =~ s%^$objQM\/?%%;
$path0 =~ s%^$topQM\/?%%;
}
#######################################################################
## Build a list of directories to search. Input source will be one
## of path to Makefile.in, path to Makefile, directory, file within
## a directory or relative path from cwd.
#######################################################################
my @subdirs;
my $path = (0 == $haveMF) ? $path0 : dirname($path0);
push(@subdirs, $path); # containing directory
push(@subdirs, dirname($path)) if (0 == $haveMF && -f $path); # Arg is file within a directory
push(@subdirs, $cwd); # relative to pwd
# obj - path to generated makefile
# top - path to Makefile.in source template
my @prefixes = ('/' ne substr($path0, 0, 1))
? (&getTopDir, &getObjDir)
: ()
;
ON_SAFARI:
for my $prefix (@prefixes)
{
next unless ($prefix); # no command line not passed
foreach my $subdir (@subdirs)
{
foreach my $mf ('Makefile.in', 'Makefile')
{
my $path = join('/', $prefix, $subdir, $mf);
if (-e $path)
{
$name = $mf;
$haveMF = ($mf eq 'Makefile.in') ? 1 : -1;
$abspath = $path;
last ON_SAFARI;
}
}
}
}
#######################################################################
## Generated makefile does not yet exist or path is invalid.
## Should this conditon be handled to detect non-existent Makefile.in:
## Makefile.am => Makefile.in => Makefile but Makefile.in
#######################################################################
if (!$abspath && -1 == $haveMF && $obj)
{
$abspath = ('/' eq substr($path0, 0, 1))
? $path0
: join('/', $obj, $path0)
;
}
########################################################
## If --top and/or --obj specified extract relative path
########################################################
my $relpath;
if (! $abspath)
{
# Error, fall through
}
elsif (1 == $haveMF) # Makefile.in
{
## err w/o --top
(my $tmp = $abspath) =~ s%^$topQM/?%%;
$relpath = dirname($tmp) unless ($tmp eq $abspath);
}
elsif (-1 == $haveMF) # Makefile
{
## err w/o --obj
(my $tmp = $abspath) =~ s%^$objQM/?%%;
$relpath = dirname($tmp) unless ($tmp eq $abspath);
}
$relpath ||= '';
$relpath =~ s%/./%/%og; # filter ./
$@ = ($relpath) ? '' : "ERROR($path0): Unable to locate sources";
return $relpath || '';
} # getRelPath
###########################################################################
## Intent: Determine sandbox root from script startup directory
## -----------------------------------------------------------------------
## Args:
## _set_ optional, if passed use the given value as path
## _reset_ clear cached directory path to reassign
## Returns:
## scalar - absolute path to the sandbox root directory
## -----------------------------------------------------------------------
###########################################################################
my $gtd_dir;
sub getTopDir
{
if (@_) # testing override
{
$gtd_dir = abs_path($_[1] || '.') if ($_[0] eq '_set_');
$gtd_dir = '' if ($_[0] eq '_reset_');
}
unless ($gtd_dir)
{
## Set by command line
if ($main::argv{top})
{
$gtd_dir = $main::argv{top};
}
else
{
my $path = abs_path($FindBin::RealBin);
my @path = split(m%/%o, $path);
## --2 memory/mozalloc/Makefile.in
## --3 was this for FindBin::Script ?
splice(@path, -2);
$gtd_dir = join('/', @path);
}
}
return $gtd_dir;
} # getTopDir
###########################################################################
## Intent: Determine path to MOZ_OBJDIR/object directory
## -----------------------------------------------------------------------
## Args:
## _set_ optional testing arg, if passed re-compute cached value
## Returns:
## scalar - absolute path to the sandbox object directory
## -----------------------------------------------------------------------
###########################################################################
my $god_dir;
sub getObjDir
{
if (@_) # testing override
{
if ($_[0] eq '_reset_')
{
$god_dir = '';
shift;
}
elsif ($_[0] eq '_set_')
{
shift;
my $path = $_[0] || '.';
$god_dir = abs_path($path);
shift;
}
}
## extract $obj from given path
unless ($god_dir)
{
if ($main::argv{obj})
{
$god_dir = $main::argv{obj};
}
elsif (@_ && 'Makefile' eq substr($_, -8))
{
$god_dir = abs_path(shift);
}
else # assume we are sitting in moz_objdir
{
$god_dir = abs_path('.');
}
}
return $god_dir;
} # getObjDir
###########################################################################
## Intent: Generate Makefile from a given Makefile.in template
## -----------------------------------------------------------------------
## Args:
## scalar Relative path to a directory containing a makefile
## fargs Hash ref of function arguments.
## obj Absolute path to MOZ_OBJ/a destination directory
## top Absolute path to the sandbox root
## Returns:
## $@ Set on error
## scalar
## 1 True if the makefile was updated
## 0 Otherwise
## badtokens - If the makefile contains unexpandable @token@ strings
## -----------------------------------------------------------------------
###########################################################################
sub updateMakefiles
{
my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : ();
local $_;
$@ = '';
my $top = $fargs{top};
my $obj = $fargs{obj};
my $relpath = shift || '';
my $src = join('/', $top, $relpath, 'Makefile.in');
my $depth = getDepth($src);
my @src = cat($src);
return 0 if ($@);
my $dst = join('/', $obj, $relpath, 'Makefile');
my @dst = cat($dst);
$@ = '';
my $dstD = dirname($dst);
mkdirr($dstD);
return 0 if ($@);
my %data =
( getConfig(),
depth => $depth,
srcdir => join('/', $top, $relpath),
top_srcdir => $top,
);
my $line = 0;
my @data;
while (scalar @src)
{
$line++;
$_ = shift(@src);
## Expand embedded @foo@
while (/\@[^\@\s\$]+\@/go)
{
my $end = pos($_);
my $val = $&;
my $len = length($val);
$val =~ s/^\@\s*//o;
$val =~ s/\s*\@$//o;
## Identify expansions to see if we can avoid shell overhead
if (!defined $data{$val} && !$argv{'no-badtokens'})
{
if (1) # warnings
{
print STDERR "WARNING: token $val not defined\n";
print STDERR " line $line, src: $src\n";
}
return 'badtokens';
}
# Insert $(error txt) makefile macros for invalid tokens
my $val1 = defined($data{$val})
? $data{$val}
: "\$(error $FindBin::Script: variable ${val} is undefined)"
;
substr($_, ($end-$len), $len, $val1);
}
push(@data, $_);
}
if (("@data" eq "@dst") && scalar(@data))
{
print "Skipping up2date makefile: $dst\n" if ($argv{verbose});
}
else
{
my $action = (scalar @dst) ? 'Updating' : 'Creating';
print "$action makefile: $dst\n";
my $tmp = join('.', $dst, "tmp_$$");
if (!open(FYL, "> $tmp"))
{
$@ = "open($tmp) failed: $!";
}
else
{
print FYL @data;
close(FYL);
## Install the new makefile
File::Copy::move($tmp, $dst)
|| ($@ = "move($tmp, $dst) failed: $!");
}
}
return $@ ? 0 : 1;
} # updateMakefiles
# Output the makefiles.
#
sub update_makefiles_legacy {
my ($ac_given_srcdir, $pac_given_srcdir, @makefiles) = @_;
my $debug = $main::argv{debug} || 0;
my $pwdcmd = ($^O eq 'msys') ? 'pwd -W' : 'pwd';
my @unhandled=();
my @warn;
my $ac_file;
foreach $ac_file (@makefiles) {
my $ac_file_in = "$ac_given_srcdir/${ac_file}.in";
my $ac_dir = dirname_legacy($ac_file);
my $ac_dots = '';
my $ac_dir_suffix = '';
my $srcdir = '.';
my $top_srcdir = '.';
# Determine $srcdir and $top_srcdir
#
if ($ac_dir ne '.') {
$ac_dir_suffix = "/$ac_dir";
$ac_dir_suffix =~ s%^/\./%/%;
$ac_dots = $ac_dir_suffix;
# Remove .. components from the provided dir suffix, and
# also the forward path components they were reversing.
my $backtracks = $ac_dots =~ s%\.\.(/|$)%%g;
while ($backtracks--) {
$ac_dots =~ s%/[^/]*%%;
}
$ac_dots =~ s%/[^/]*%../%g;
}
if ($ac_given_srcdir eq '.') {
if ($ac_dots ne '') {
$top_srcdir = $ac_dots;
$top_srcdir =~ s%/$%%;
}
} elsif ($pac_given_srcdir =~ m%^/% or $pac_given_srcdir =~ m%^.:/%) {
$srcdir = "$pac_given_srcdir$ac_dir_suffix";
$top_srcdir = "$pac_given_srcdir";
} else {
if ($debug) {
print "ac_dots = $ac_dots\n";
print "ac_dir_suffix = $ac_dir_suffix\n";
}
$srcdir = "$ac_dots$ac_given_srcdir$ac_dir_suffix";
$top_srcdir = "$ac_dots$ac_given_srcdir";
}
if ($debug) {
print "ac_dir = $ac_dir\n";
print "ac_file = $ac_file\n";
print "ac_file_in = $ac_file_in\n";
print "srcdir = $srcdir\n";
print "top_srcdir = $top_srcdir\n";
print "cwd = " . `$pwdcmd` . "\n";
}
# Copy the file and make substitutions.
# @srcdir@ -> value of $srcdir
# @top_srcdir@ -> value of $top_srcdir
#
if (-e $ac_file) {
next if -M _ < -M $ac_file_in; # Next if Makefile is up-to-date.
warn "updating $ac_file\n";
} else {
warn "creating $ac_file\n";
}
mkdirr(dirname($ac_file));
open INFILE, "<$ac_file_in" or do {
warn "$0: Cannot read $ac_file_in: No such file or directory\n";
next;
};
open OUTFILE, ">$ac_file" or do {
warn "$0: Unable to create $ac_file\n";
next;
};
while (<INFILE>) {
s/\@srcdir\@/$srcdir/g;
s/\@top_srcdir\@/$top_srcdir/g;
if (/\@[_a-zA-Z]*\@/) {
#warn "Unknown variable:$ac_file:$.:$_";
push @unhandled, $ac_file;
last;
}
print OUTFILE;
}
close INFILE;
close OUTFILE;
}
return @unhandled;
} # update_makefiles_legacy
###########################################################################
## Intent: Invoke config.status for unknown makefiles to create
## directory hierarchy for the tree.
## -----------------------------------------------------------------------
## Args:
## array an optional list of makefiles to process
## Returns:
## 0 on success
## $# set on error
## -----------------------------------------------------------------------
## Note: Is this function needed anymore ? Undefined tokens should fail
## at time of expansion rather than having to source config.status.
## Also config.status could be parsed to define values and avoide the
## shell overhead altogether.
###########################################################################
sub run_config_status {
my @unhandled = @_;
# Run config.status with any unhandled files.
#
my @errors;
if (@unhandled) {
local $ENV{CONFIG_FILES}= join ' ', @unhandled;
my $conf = 'config.status';
if (! -e $conf) # legacy behavior, warn rather than err
{
my $cwd = cwd();
my $err = "$FindBin::Script ERROR: Config file $conf does not exist, cwd=$cwd";
push(@errors, $err);
}
elsif (0 != system("./config.status"))
{
my $cwd = cwd();
push(@errors, "config.status failed \$?=$?, \$!=$!, cwd: $cwd");
}
}
$@ = join("\n", @errors);
## Legacy behavior: config.status problems are not fatal {yet}.
## Display warning since caller will not be calling die.
warn $@ if ($@ && $argv{'no-warnings'});
return $@ ? 1 : 0;
}
1;

View File

@ -0,0 +1,94 @@
# -*- makefile -*-
#
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of 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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
##################################################
## Gather a list of tests, generate timestamp deps
##################################################
TS=.ts
ifneq (,$(findstring check,$(MAKECMDGOALS)))
allsrc = $(wildcard $(srcdir)/*)
tests2run = $(notdir $(filter %.tpl,$(allsrc)))
tests2run += $(notdir $(filter %.tpm,$(allsrc)))
check_targets += $(addprefix $(TS)/,$(tests2run))
endif
all_nop: # export, libs and tools are not needed
check:: $(TS) $(check_targets)
#############################################
# Only invoke tests when sources have changed
#############################################
$(TS)/%: $(srcdir)/%
$(PERL) $(srcdir)/runtest $<
@touch $@
parent = $(patsubst %/,%,$(dir $(srcdir)))
$(TS)/make-makefile.tpl: \
$(srcdir)/make-makefile.tpl\
$(parent)/makemakefile.pm\
$(NULL)
$(PERL) $(srcdir)/runtest $<
@touch $@
$(TS)/makemakefile.tpm: \
$(srcdir)/makemakefile.tpm \
$(parent)/makemakefile.pm \
$(NULL)
$(PERL) $(srcdir)/runtest $<
@touch $@
#####################################################
## Extra dep needed to synchronize parallel execution
#####################################################
$(TS): $(TS)/.done
$(TS)/.done:
$(MKDIR) -p $(dir $@)
touch $@
GARBAGE_DIRS += $(TS)
# EOF

View File

@ -0,0 +1,4 @@
jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX)
@$(RM) $@ jsautocfg.tmp
./jscpucfg > jsautocfg.tmp
mv jsautocfg.tmp $@

View File

@ -0,0 +1,4 @@
jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX)
@$(RM) $@ jsautocfg.tmp
./jscpucfg > jsautocfg.tmp
mv jsautocfg.tmp $@

View File

@ -0,0 +1,8 @@
###########################################################################
## Intent: Exclusion list for container make builds
###########################################################################
/dev/null
/foo/bar
/a/b/c
/a/b/d

View File

@ -0,0 +1,436 @@
#!/usr/bin/env perl
###########################################################################
## Intent: Unit test to verify make-makefile.tpl
###########################################################################
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
#use feature 'state'; # 5.10+ not installed everywhere
use Getopt::Long;
use Cwd;
use Cwd qw{abs_path};
use File::Basename;
use File::Copy;
use File::Path;
use File::Temp qw{ tempdir };
use Test;
sub BEGIN { plan tests => 4 };
my @workdirs;
sub END { system("/bin/rm -fr @workdirs"); } # cleanup behind interrupts
##-------------------##
##---] EXPORTS [---##
##-------------------##
use FindBin;
our $VERSION = qw(1.0);
##------------------##
##---] INCLUDES [---##
##------------------##
use FindBin;
use lib "$FindBin::RealBin/..";
use makemakefile;
##-------------------##
##---] GLOBALS [---##
##-------------------##
my %argv;
###########################################################################
## Intent: Create a temp sandbox populated with sources
## -----------------------------------------------------------------------
## Args:
## array a list of file paths to copy
## Returns:
## $@ set on error
## scalar path to scratch sandbox
## -----------------------------------------------------------------------
###########################################################################
my $root; # state $root not available
sub createSandbox
{
my @errors;
unless ($root)
{
my @tmp = split(m%/%, $FindBin::RealBin);
splice(@tmp, -3);
$root = join('/', @tmp);
}
my $work = tempdir();
push(@workdirs, $work);
my @dirs = map{ join('/', $work, dirname($_)) } @_;
mkdirr(@dirs);
push(@errors, "createSandbox: $@") if ($@);
foreach (@_)
{
## Copy sources into the temp source directory
my $src = join('/', $root, $_);
my $dst = join('/', $work, $_);
unless (copy($src, $dst))
{
push(@errors, "copy($src, $dst) failed: $!");
}
}
print STDERR "createSandbox: $work\n" if ($main::argv{debug});
$@ = join('', map{ "$_\n" } @errors);
$work;
} # createSandbox
###########################################################################
## Intent: wrapper to run the make-makefile command.
## -----------------------------------------------------------------------
## Args:
## array command line arguments passed to make-makefile
## Returns:
## array command output
## $@ set by shell exit status, empty string on success
## $? command shell exit status
###########################################################################
my $mm; # state $mm not available
sub makemakefile
{
my %fargs = (@_ && ref($_[$#_])) ? %{ (pop) } : ();
$mm ||= join('/', dirname($FindBin::Bin), 'make-makefile'); # cmd in parent of test/
my $cmd = join(' ', $mm, @_);
print "RUNNING: $cmd\n" if ($fargs{debug});
my @out = `$cmd 2>&1`;
print STDERR map{ "out> $_" } @out if ($argv{verbose});
$@ = (0 == $?) ? '' : "Command failed: $cmd\n@out";
@out;
} # makemakefile
###########################################################################
## Intent: Helper function, display the contents of a given sandbox
## -----------------------------------------------------------------------
## Args:
## scalar Path to sandbox
## Returns:
## none
## -----------------------------------------------------------------------
###########################################################################
sub find_ls
{
my $path = shift || '';
# Assuming dot contributes to cryptic problems
die "find_ls: a path is required" unless ($path);
my $cmd = "find $path -ls";
print "\nRunning: $cmd\n";
print '=' x 75, "\n";
print `$cmd`;
} # myls
###########################################################################
## Intent: Verify make-makefile is able to digest paths and generate
## makefiles when object directory is a child of top.
###########################################################################
sub check_makemakefile
{
my $work = createSandbox
(
'memory/mozalloc/Makefile.in',
'toolkit/system/windowsproxy/Makefile.in',
'toolkit/crashreporter/google-breakpad/src/client/Makefile.in',
);
my $workdir = createSandbox();
my $top = $workdir;
chdir $top;
my $objA = 'obj-arch-dir';
my $obj = join('/', $top, $objA);
# getTopDir()
local $main::argv{top} = $work;
local $main::argv{obj} = $obj;
getObjDir('_reset_');
my @root = split(m%/%, $FindBin::RealBin);
splice(@root, -3);
my $root = join('/', @root);
my @args =
(
[
banner => "--top and --obj are impled, generate Makefile",
rel => 'memory/mozalloc',
cmd => join(' ',
'--top', $top,
'--obj', $obj,
'memory/mozalloc/Makefile',
),
],
[
banner => "--top and abs(obj) passed",
rel => "toolkit/system/windowsproxy",
cmd => join(' ',
'--top', $top,
"$obj/toolkit/system/windowsproxy/Makefile",
),
exp => "$obj/toolkit/system/windowsproxy/Makefile",
skip => 1, #
],
[
banner => "--obj and abs(top) passed",
rel => "toolkit/crashreporter/google-breakpad/src/client",
cmd => join(' ',
'--obj', $obj,
"$top/toolkit/crashreporter/google-breakpad/src/client/Makefile.in",
),
exp => "$top/toolkit/crashreporter/google-breakpad/src/client/Makefile.in",
skip => 1, #
],
);
foreach (@args)
{
my %rec = @{ $_ };
next if ($rec{skip});
next unless ($rec{rel});
my $srcR = join('/', $top, $rec{rel});
my $dstR = join('/', $obj, $rec{rel});
my $src = join('/', $top, $rec{rel}, 'Makefile.in');
my $dst = join('/', $obj, $rec{rel}, 'Makefile');
# Use distinct sources to avoid cleanup overhead between tests
die "Test source already used: $dstR" if (-d $dstR);
## Copy sources into the temp source directory
my $rootR = join('/', $root, $rec{rel});
my $rootS = join('/', $root, $rec{rel}, 'Makefile.in');
File::Path::mkpath($srcR, 0, 0700);
copy($rootS, $src) or die "copy($rootS, $src) failed: $!";
die "source does not exist: $src" unless (-e $src);
######################
## Generate and verify
######################
print STDERR "RUNNING: $rec{banner}\n" if ($argv{debug});
my @errs;
makemakefile('--enhanced', $rec{cmd}, {verbose=>1});
if ($@)
{
push(@errs, "\$@ should not be set: $@\n");
}
elsif (! -e $dst)
{
push(@errs, "Generated makefile does not exist: $dst, banner: $rec{banner}\n");
}
ok(scalar(@errs), 0, "Errors detected:\n" . join(" $_", @errs));
find_ls($top) if (@errs);
}
} # check_makemakefile
###########################################################################
## Intent: Verify make-makefile is able to digest paths and generate
## makefiles when top/MOZ_OBJDIR are not parent/child directories
## ---------------------------------------------------------------------------
## Args:
## none
## Returns:
## none
## ---------------------------------------------------------------------------
###########################################################################
sub check_makemakefile_distinct
{
my $workdir = createSandbox();
# my $workdir = tempdir();
###############################################
## Now update when top/obj are not parent/child
###############################################
my $top = join('/', $workdir, 'top');
my $obj = join('/', $workdir, 'obj');
$main::argv{top} = $top;
$main::argv{obj} = $obj; # test afterward, using undef ?
my @sbxroot = split(m%/%, $FindBin::RealBin);
splice(@sbxroot, -2);
my $sbxroot = join('/', @sbxroot);
## Copy in a makefile template to to convert
File::Path::mkpath(["$top/memory/mozalloc"], 0, 0700);
copy("$sbxroot/memory/mozalloc/Makefile.in", "$top/memory/mozalloc/Makefile.in");
# work/memory/mozalloc/Makefile.in
my @args =
(
[
banner => '--top and --obj are distinct [1]',
cmd => "--obj $obj memory/mozalloc/Makefile",
exp => "$obj/memory/mozalloc/Makefile",
],
[
banner => "--top and --obj are distinct [2]",
cmd => "--top $top memory/mozalloc/Makefile.in",
exp => "$obj/memory/mozalloc/Makefile",
skip => 1, # test problem: top != obj
],
[
banner => "--top and --obj are distinct [3]",
cmd => join(' ',
"--top $top",
"--obj $obj",
"memory/mozalloc/Makefile.in",
),
exp => "$obj/memory/mozalloc/Makefile",
skip => 1, # test problem: top != obj
],
);
foreach (@args)
{
my %rec = @{ $_ };
print STDERR "banner: $rec{banner}\n" if ($argv{debug});
next if $rec{skip};
unlink $rec{exp};
makemakefile('--enhanced', $rec{cmd});
my @errs;
if ($@)
{
push(@errs, "\$@ should not be set: $@\n");
}
elsif (! -e $rec{exp})
{
push(@errs, "Makefile does not exist: $rec{exp}\n");
}
ok(scalar(@errs), 0, "Errors detected:\n" . join(" $_", @errs));
}
} # check_makemakefile_distinct
###########################################################################
## Intent: Verify legacy behavior, invoke make-makefile when cwd is
## a subdirectory beneath MOZ_OBJDIR.
## -----------------------------------------------------------------------
## Args:
## none
## Returns:
## none
## -----------------------------------------------------------------------
###########################################################################
sub check_makemakefile_legacy
{
my $work = createSandbox
(
'memory/mozalloc/Makefile.in',
'parser/htmlparser/tests/mochitest/html5lib_tree_construction/Makefile.in',
);
my $obj = join('/', $work, 'obj');
mkdir $obj;
my @args =
(
{
banner => '-t path -d dot',
cwd => $obj,
cmd => "-t $work -d . memory/mozalloc/Makefile",
exp => "$obj/memory/mozalloc/Makefile",
skip => 0,
},
{
banner => '-t path -d relpath',
cwd => join('/', $obj, 'parser/htmlparser/tests/mochitest'),
cmd => "-t $work -d ../../../.. html5lib_tree_construction/Makefile",
exp => "$obj/parser/htmlparser/tests/mochitest/html5lib_tree_construction/Makefile",
skip => 0,
},
);
foreach (@args)
{
my %rec = %{ $_ };
next if ($rec{skip});
## make-make while sitting in $objdir
mkdirr($rec{cwd});
chdir $rec{cwd} || die "chdir $rec{cwd} failed; $!";
makemakefile($rec{cmd});
my @errs;
if ($@)
{
push(@errs, "make-makefile $rec{cmd} failed: $@");
}
elsif (! -e $rec{exp})
{
push(@errs, "generated makefile does not exist: $rec{exp}");
}
ok(scalar(@errs), 0, "Errors detected: @errs");
find_ls($work) if (@errs);
}
chdir $FindBin::RealBin;
} # check_makemakefile_legacy
###########################################################################
## Intent: Smoke tests for the unittests module
###########################################################################
sub smoke
{
print STDERR "Running test: smoke()\n" if ($argv{debug});
} # smoke()
###########################################################################
## Intent: Intitialize global test objects and consts
###########################################################################
sub init
{
print "Running: init()\n" if ($argv{debug});
# testplan(24, 0);
} # init()
##----------------##
##---] MAIN [---##
##----------------##
unless(GetOptions(\%argv,
qw(
debug|d
manual
test=s@
verbose
)))
{
print "USAGE: $0\n";
print " --debug Enable script debug mode\n";
print " --manual Also run disabled tests\n";
print " --smoke Run smoke tests then exit\n";
print " --test Run a list of tests by function name\n";
print " --verbose Enable script verbose mode\n";
exit 1;
}
init();
smoke();
check_makemakefile();
check_makemakefile_distinct();
check_makemakefile_legacy();

View File

@ -0,0 +1,519 @@
#!/usr/bin/env perl
###########################################################################
## Intent: Unit test to verify the makemakefile.pm module
###########################################################################
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
#use feature 'state';
use Getopt::Long;
use FindBin;
use Cwd qw{abs_path};
use File::Basename;
use File::Compare;
use File::Copy;
use File::Temp qw{tempdir};
use Test;
sub BEGIN { plan tests => 36 };
my @workdirs;
sub END { system("/bin/rm -fr @workdirs"); } # cleanup behind interrupts
##-------------------##
##---] EXPORTS [---##
##-------------------##
our $VERSION = qw(1.0);
##------------------##
##---] INCLUDES [---##
##------------------##
use FindBin;
use lib "$FindBin::RealBin/..";
use makemakefile;
##-------------------##
##---] GLOBALS [---##
##-------------------##
my %argv;
###########################################################################
## Intent: Create a temp sandbox populated with sources
## -----------------------------------------------------------------------
## Args:
## array files to copy into the temporary sandbox
## Returns:
## $@ set on error
## array
## top - path to temp sandbox root
## obj - path to temp sandbox moz_obj directory
## -----------------------------------------------------------------------
###########################################################################
my $_root_; # state $root
sub createSandbox
{
# state $root;
my @errors;
unless ($_root_)
{
my @tmp = split(m%/%, $FindBin::RealBin);
splice(@tmp, -3);
$_root_ = join('/', @tmp);
}
my $work = tempdir(CLEANUP=>1);
push(@workdirs, $work);
my @dirs = map{ join('/', $work, dirname($_)) } @_;
mkdirr(@dirs);
push(@errors, "createSandbox: $@") if ($@);
foreach (@_)
{
## Copy sources into the temp source directory
my $src = join('/', $_root_, $_);
my $dst = join('/', $work, $_);
unless (copy($src, $dst))
{
push(@errors, "copy($src, $dst) failed: $!");
}
}
print STDERR "createSandbox: $work\n" if ($main::argv{debug});
$@ = join('', map{ "$_\n" } @errors);
$work;
} # createSandbox
###########################################################################
## Intent: Verify legacy dirname function
###########################################################################
sub check_dirname_legacy
{
print "Running: check_dirname_legacy\n" if ($main::argv{debug});
foreach (
['/dev/null', '/dev'],
['/foo/bar/Makefile', '/foo/bar'],
)
{
my ($src, $exp) = @{ $_ };
my $dir = dirname_legacy($src);
ok($dir, $exp, "dirname_legacy($src) failed");
}
my $path = dirname_legacy(undef);
ok($path ? 1 : 0, 1, "dirname('') should expand to cwd");
} # check_dirname_legacy
###########################################################################
## Intent: Verify topdir lookup function
###########################################################################
sub check_getTopDir
{
print "Running: check_getTopDir\n" if ($main::argv{debug});
my $path = getTopDir();
## Unit test is special, cmd not invoked from the same directory
## as the makemakefile.pm module.
ok($path ? 1 : 0, 1, "getTopDir failed");
ok(-d $path ? 1 : 0, 1, "getTopDir: directory $path does not exist");
ok($FindBin::RealBin =~ m%$path/% ? 1 : 0, 1, 'Invalid topdir path');
ok(-e "$path/client.mk" ? 1 : 0, 1, "client.mk not found in $path");
} # check_getTopDir
###########################################################################
## Intent: Verify objdir lookup function
###########################################################################
sub check_getObjDir
{
print "Running: check_getObjDir\n" if ($main::argv{debug});
local $main::argv{obj} = '/bin';
my $path = getObjDir('_reset_');
ok($path ? 1 : 0, 1, "getObjDir failed");
ok(-d $path ? 1 : 0, 1, "getObjDir: directory $path does not exist");
my $top = getTopDir();
$main::argv{obj} = join('/', $top, 'browser'); # use existing path so file can be resolved
my $obj = getObjDir('_reset_');
ok($top ne $obj ? 1 : 0, 1, "top and object directory paths should not match");
## If we fail for /bin use here getObjDir() was not reset
my $client = join('/', $obj, '..', 'client.mk');
ok(-e $client ? 1 : 0, 1, "client.mk not found in parent of $path, $client");
getObjDir('_set_'); # clear cached value and recompute
foreach my $file ("$top/memory/mozalloc/Makefile")
{
my $obj = getObjDir('_reset_', $file);
ok($obj ne $file ? 1 : 0, 1, "getObjDir($file) failed")
}
} # check_getObjDir
###########################################################################
## Intent: Verify rel-path-to-root/getdepth function
###########################################################################
sub check_getDepth
{
my @tmp = split(m%/%o, $FindBin::Bin);
splice(@tmp, -3);
my $root = abs_path( join('/', @tmp) );
my %data =
(
$root => '.',
join('/', $root, 'netwerk/Makefile.in') => '..',
join('/', $root, 'browser/components/privatebrowsing/test/browser/Makefile.in') => '../../../../..',
join('/', $root, 'browser/components/privatebrowsing/test/browser/') => '../../../../..',
join('/', $root, 'browser/components/privatebrowsing/test/browser') => '../../../../..',
join('/', $root, 'browser/components/privatebrowsing/test') => '../../../..',
);
while (my($k, $v) = each %data)
{
my $depth = makemakefile::getDepth($k);
ok($depth, $v, "getDepth($k) failed");
}
} # check_getDepth
###########################################################################
## Intent: Verify reading the exclusion file
###########################################################################
sub check_getExclusions
{
my $cfg = join('/', $FindBin::RealBin, 'make-makefile.excl');
my %excl = getExclusions($cfg);
ok($@, '', '$@ should not be set');
my @excl = sort keys %excl;
ok(scalar @excl, 4, "Exclusion file is invalid: \@excl=@excl");
} # check_getExclusions
###########################################################################
## Intent: Verify rel-path-to-root function
## -----------------------------------------------------------------------
## Args:
## none
## Returns:
## none
## -----------------------------------------------------------------------
## Note:
## String test only, top and obj paths are bogus for this test
###########################################################################
sub check_getRelPath
{
my @tmp = split(m%/%o, $FindBin::Bin);
splice(@tmp, -3);
my $root = abs_path( join('/', @tmp) );
my $obj0 = 'obj-arch';
my $obj = join('/', $root, $obj0);
local $main::argv{top} = $root;
local $main::argv{obj} = $obj;
getTopDir('_reset_');
getObjDir('_set_', $obj);
## Cannot test relative paths with objdir beneath /tmp
## Commented paths are needed for full test coverage
## but are not currently supported by all module functions.
my %data =
(
# Relative - path correct for build directory but
'profile/dirserviceprovider/public/Makefile.in' => 'profile/dirserviceprovider/public',
join('/', $root, 'profile/dirserviceprovider/public/Makefile.in') => 'profile/dirserviceprovider/public',
# File search
'profile/dirserviceprovider/public' => 'profile/dirserviceprovider/public',
# cwd + cleanup
# '../../../profile/dirserviceprovider/public/Makefile.in' => 'profile/dirserviceprovider/public',
# "../../../${obj0}/profile/dirserviceprovider/public/Makefile.in" => 'profile/dirserviceprovider/public',
## Special case: This could be handled but permutations of non-existent files, non-overlapping paths
## and relative paths containing partial subdirectories will compilicate the logic. Wait until needed.
## Relative path: $root + obj + subdir
# "${obj0}/profile/dirserviceprovider/public/Makefile" => 'profile/dirserviceprovider/public',
join('/', $obj, 'profile/dirserviceprovider/public/Makefile') => 'profile/dirserviceprovider/public',
# $RealBin, -d ../../..
# top and obj not subdirectories of each other: /foo/x, /bar/y
);
while (my($k, $v) = each %data)
{
my $dir = getRelPath($k);
ok($@, '', '$@ should not be set');
ok($dir, $v, "ERROR[$k]: exp[$v] != found=[$dir]");
}
my $top = '/tmp/foo';
my $tmp = '/tmp/bar';
local $main::argv{top} = $tmp;
local $main::argv{obj} = $obj;
%data =
(
# "$top/profile/dirserviceprovider/public/Makefile.in" => 'profile/dirserviceprovider/public',
"$obj/profile/dirserviceprovider/public/Makefile" => 'profile/dirserviceprovider/public',
);
while (my($k, $v) = each %data)
{
my $dir = getRelPath($k);
ok($dir, $v, "ERROR[$k]: exp[$v] != found=[$dir]");
}
} # check_getRelPath
###########################################################################
## Intent: Verify rel-path-to-root directory creation
###########################################################################
sub check_mkdirr
{
if (-w '/bin') # cygwin may be writable
{
ok(1, 1, 'bogus test to maintain count');
} else {
mkdirr('/bin/invalid/Makefile');
ok($@ ? 1 : 0, 1, '$@ should be set');
}
my $work = createSandbox();
my @paths = map{ join('/', $work, $_, 'Makefile.in') } qw (xyz/abc foo/bar a/b/c/d/e);
mkdirr(@paths);
ok($@ ? 1 : 0, 0, '$@ should not be set');
push(@paths, '/bin');
my @errors;
foreach (@paths)
{
my $dir = dirname($_);
next if (-d $dir);
push(@errors, "mkdirr($dir) failed\n");
}
ok(scalar @errors, 0, "Errors detected: @errors");
} # check_mkdirr
###########################################################################
## Intent: Verify permutations for system("config.status")
###########################################################################
sub check_run_config_status
{
print STDERR "Running: check_run_config_status()\n"
if ($main::argv{debug});
my $work = createSandbox();
chdir $work;
run_config_status();
ok($@ ? 1 : 0, '$@ should be set, config.status does not exist');
my $cfg = join('/', $work, 'config.status');
local *CFG;
open(CFG, "> $cfg") && close(CFG);
run_config_status();
ok($@, qr/config.status failed/, '$@ should be set, config.status is not executabl');
open(CFG, "> $cfg");
print CFG join("\n",
'#!/bin/sh',
'',
'true',
'');
close(CFG);
chmod 0555, $cfg;
run_config_status();
ok($@, qr/config.status failed/, '$@ should not be set');
} # check_run_config_status
###########################################################################
## Intent: Verify makefile generation by legacy make-makefile functions
## o make-makefile -t /x/y -d ..
###########################################################################
sub check_update_makefiles_legacy
{
print STDERR "Running: check_update_makefiles_legacy()\n"
if ($main::argv{debug});
return unless ($argv{legacy});
print STDERR "check_update_makefiles_legacy: not yet implemented\n";
} # check_update_makefiles_legacy
###########################################################################
## Intent: Verify updateMakefiles()
## o a makefile is generated when none exists.
## o a makefile will only be updated when the templates changes.
## o existing makefiles will be updated when the template changes.
## o @foo@ tokens have been expanded
###########################################################################
sub check_updateMakefiles
{
my @errors;
print STDERR "Running: check_updateMakefiles()\n"
if ($main::argv{debug});
my $mf = 'memory/mozalloc/Makefile.in';
my $work = createSandbox($mf);
my $obj = join('/', $work, 'obj');
my %args =
(
top => $work,
obj => $obj,
);
my $mf_src = join('/', $work, 'memory/mozalloc/Makefile.in');
my $mf_dst = join('/', $obj, 'memory/mozalloc/Makefile');
updateMakefiles('memory/mozalloc', \%args);
my $tlm0 = (stat $mf_dst)[9] || 0;
ok(-e $mf_dst ? 1 : 0, 1, "failed to generate makefile: $mf_dst");
#############################
## Regeneration will be a nop
#############################
updateMakefiles('memory/mozalloc', \%args);
my $tlm1 = (stat $mf_dst)[9] || -1;
ok($tlm1, $tlm0, "makefile should not have been modified");
#####################################################
## Modify template to verify makefile will regenerate
#####################################################
local *MF;
if (open(MF, ">> $mf_src"))
{
print MF map{ "# MODIFIED MAKEFILE\n" } 0..4;
close(MF);
}
updateMakefiles('memory/mozalloc', \%args);
my @data = makemakefile::cat($mf_dst);
## Check content to avoid a silly 'sleep [n]' call here
ok(grep(/^\# MODIFIED MAKEFILE/o, @data) ? 1 : 0,
1,
"template modified, makefile should have regenerated");
## VERIFY template expansion
my @gen = makemakefile::cat($mf_dst);
push(@errors, $@) if ($@);
foreach (@gen)
{
if (/\@[^\@]+\@/o)
{
push(@errors, join("\n",
"Unexpanded template string detected [$_]",
"Makefile: $mf_src",
));
last;
}
}
ok(scalar(@errors), 0, "Errors detected: @errors");
} # check_updateMakefiles
###########################################################################
## Intent: Verify makefile generation by updateMakefiles() when
## command line arguments --top and --obj were passed.
###########################################################################
sub check_updateMakefilesByTopObj
{
my @errors;
print STDERR "Running: check_updateMakefilesByTopObj()\n"
if ($main::argv{debug});
my $work = createSandbox();
my %args =
(
top => $work,
obj => $work,
);
## Grab a list of makefile templates to generate
my @all = glob('data/mf.*');
my @src = map{ /\.exp$/o ? () : $_ } @all;
foreach my $src (@src)
{
my $dst = join('/', $work, 'Makefile');
unlink $dst;
copy($src, "$work/Makefile.in");
updateMakefiles('.', \%args);
ok($@, '', '$@ should not be set');
my @dst = makemakefile::cat($dst);
my $exp = join('.', $src, 'exp');
my @exp = makemakefile::cat($exp);
ok("@dst", "@exp", "updateMakefile($dst) failed");
}
return;
} # check_updateMakefilesByTopObj
###########################################################################
## Intent: Smoke tests for the unittests module
###########################################################################
sub smoke
{
print STDERR "Running test: smoke()\n" if ($argv{debug});
} # smoke()
###########################################################################
## Intent: Intitialize global test objects and consts
###########################################################################
sub init
{
print "Running: init()\n" if ($argv{debug});
# testplan(24, 0);
my @path = split(m%/%, $FindBin::RealBin);
splice(@path, -3);
my $top = join('/', @path);
## Top set based on make-makefile startup directory so adjust for test/ use
getTopDir('_set_', $top);
} # init()
##----------------##
##---] MAIN [---##
##----------------##
unless(GetOptions(\%argv,
qw(
debug|d
manual
test=s@
verbose
)))
{
print "USAGE: $0\n";
print " --debug Enable script debug mode\n";
print " --manual Also run disabled tests\n";
print " --smoke Run smoke tests then exit\n";
print " --test Run a list of tests by function name\n";
print " --verbose Enable script verbose mode\n";
exit 1;
}
init();
smoke();
check_dirname_legacy();
check_getTopDir();
check_getObjDir();
check_getDepth();
check_getExclusions();
check_getRelPath();
check_mkdirr();
check_updateMakefiles();
check_update_makefiles_legacy();
check_updateMakefilesByTopObj();

View File

@ -0,0 +1,95 @@
#!/usr/bin/env perl
###########################################################################
## Intent:
## Test::Harness is a testing wrapper that will process output
## from Test.pm module tests. Sumarize results, report stats
## and exit with overall status for the testing suites.
##
## Run testing suite:
## % make clean test
## % perl runtest
##
## Run Individual tests
## % perl tUtils0
###########################################################################
##----------------------------##
##---] CORE/CPAN INCLUDES [---##
##----------------------------##
use strict;
use warnings;
use Getopt::Long;
use Test::Harness;
##-------------------##
##---] EXPORTS [---##
##-------------------##
our $VERSION = qw(1.0);
use FindBin;
##-------------------##
##---] GLOBALS [---##
##-------------------##
my %argv;
##----------------##
##---] MAIN [---##
##----------------##
unless(GetOptions(\%argv,
qw(debug|d)
))
{
print "Usage: $0\n";
print " --debug Enable debug mode\n";
exit 1;
}
if (2 > $Test::Harness::VERSION)
{
print "Unit tests will not be run, Test::Harness is too old\n"
if ($argv{debug});
exit 0;
}
my @tests;
########################################
## Gather a list of tests if none passed
########################################
unless (@tests = @ARGV)
{
local *D;
opendir(D, '.');
while($_ = readdir(D)) {
next unless /.t\S+$/;
next if (/\.ts$/);
push(@tests, $_);
}
closedir(D);
}
###############################################
## Glob a list of tests when directories passed
###############################################
my @tmp;
foreach (@tests)
{
local *D;
if (-d $_ && (my $dir = $_))
{
opendir(D, $_) || die "opendir(D) failed: $!";
my @tests = grep(/\.t[^\.\s]+/o, readdir(D));
closedir(D);
push(@tmp, map{ join('/', $dir, $_); } @tests);
} else {
push(@tmp, $_);
}
}
@tests = @tmp;
print "$0: @ARGV\n" if ($argv{debug});
runtests(@tests);
# EOF

View File

@ -16,5 +16,6 @@
__malloc_hook;
__realloc_hook;
__memalign_hook;
_IO_stdin_used;
local: *;
};

View File

@ -109,3 +109,10 @@ endif
endif # ! MOZ_DEBUG
endif # WIN32_REDIST_DIR
# run the binscope tool to make sure the binary and all libraries
# are using all available Windows OS-level security mechanisms
check::
$(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/firefox.exe $(DIST)/crashreporter-symbols/
$(PYTHON) $(srcdir)/autobinscope.py $(DIST)/bin/plugin-container.exe $(DIST)/crashreporter-symbols/

108
build/win32/autobinscope.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python
# ***** 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 mozilla.org code.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# imelven@mozilla.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 *****
# run Microsoft's Binscope tool (http://www.microsoft.com/download/en/details.aspx?id=11910)
# against a fresh Windows build. output a 'binscope.log' file with full details
# of the run and appropriate strings to integrate with the buildbots
# from the docs : "The error code returned when running under the command line is equal
# to the number of failures the tool reported plus the number of errors. BinScope will return
# 0 only if there are no errors or failures."
# the symbol dir should point to the symbol dir hierarchy created
# via running make buildsymbols in a windows build's objdir
import sys
import subprocess
import os
BINSCOPE_OUTPUT_LOGFILE = r".\binscope_xml_output.log"
# usage
if len(sys.argv) < 3:
print """usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]"
log_file_path is optional, log will be written to .\binscope_xml_output.log by default"""
sys.exit(0)
binary_path = sys.argv[1]
symbol_path = sys.argv[2]
if len(sys.argv) == 4:
log_file_path = sys.argv[3]
else:
log_file_path = BINSCOPE_OUTPUT_LOGFILE
# execute binscope against the binary, using the BINSCOPE environment
# variable as the path to binscope.exe
try:
binscope_path = os.environ['BINSCOPE']
except KeyError:
print "BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status."
sys.exit(0)
try:
proc = subprocess.Popen([binscope_path, "/target", binary_path,
"/output", log_file_path, "/sympath", symbol_path,
"/c", "ATLVersionCheck", "/c", "ATLVulnCheck", "/c", "FunctionPointersCheck",
"/c", "SharedSectionCheck", "/c", "APTCACheck", "/c", "NXCheck",
"/c", "GSCheck", "/c", "GSFunctionSafeBuffersCheck", "/c", "GSFriendlyInitCheck",
"/c", "CompilerVersionCheck", "/c", "SafeSEHCheck", "/c", "SNCheck",
"/c", "DBCheck"], stdout=subprocess.PIPE)
except WindowsError, (errno, strerror):
if errno != 2 and errno != 3:
print "Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n"
sys.exit(0)
else:
print "Could not locate binscope at location : %s\n" % binscope_path
print "Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting..."
sys.exit(0)
proc.wait()
output = proc.communicate()[0]
# is this a PASS or a FAIL ?
if proc.returncode != 0:
print "TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path
else:
print "TEST-PASS | autobinscope.py | %s succeeded" % binary_path

View File

@ -1,73 +0,0 @@
#!/usr/bin/python
import sys
if not sys.platform == "win32":
raise Exception("This script was only meant for Windows.")
import os
def dos2unix(path):
print "dos2unix: %s" % path
inf = open(path, "r")
data = inf.read()
inf.close()
outf = open(path, "wb")
outf.write(data)
outf.close()
adminfiles = [
"Root",
"Repository",
"Entries",
"Entries.Log",
"Entries.Static",
"Tag",
"Notify",
"Template"
]
def walkdirectory(path):
if not os.path.exists(os.path.join(path, "CVS")):
return
print "Directory: %s" % path
for f in adminfiles:
cvsf = os.path.join(path, "CVS", f)
if os.path.exists(cvsf):
dos2unix(cvsf)
entries = open(os.path.join(path, "CVS", "Entries"), "r")
for entry in entries:
if entry == "D\n":
continue
(type, filename, rev, date, flags, extra) = entry.split('/')
if type == "D" or flags == "-kb" or rev[0] == "-":
continue
dos2unix(os.path.join(path, filename))
# Now walk subdirectories
for entry in os.listdir(path):
subdir = os.path.join(path, entry)
if os.path.isdir(subdir):
walkdirectory(subdir)
topsrcdir = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-3])
print """This command will convert the source tree at
%s
to an MSYS-compatible (unix mode) source tree. You can run this
command multiple times safely. Are you sure you want to continue (Y/N)? """ % topsrcdir,
sys.stdout.flush()
print
ask = raw_input()
if len(ask) == 0 or (ask[0] != "y" and ask[0] != "Y"):
raise Exception("User aborted action.")
walkdirectory(topsrcdir)

View File

@ -140,6 +140,7 @@ MOZ_UPDATE_PACKAGING = @MOZ_UPDATE_PACKAGING@
MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
NS_ENABLE_TSF = @NS_ENABLE_TSF@
MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@
MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@
MOZ_FEEDS = @MOZ_FEEDS@

View File

@ -122,6 +122,19 @@ testxpcobjdir = $(DEPTH)/_tests/xpcshell
ifdef ENABLE_TESTS
# Add test directories to the regular directories list. TEST_DIRS should
# arguably have the same status as TOOL_DIRS and other *_DIRS variables. It is
# coded this way until Makefiles stop using the "ifdef ENABLE_TESTS; DIRS +="
# convention.
#
# The current developer workflow expects tests to be updated when processing
# the default target. If we ever change this implementation, the behavior
# should be preserved or the change should be widely communicated. A
# consequence of not processing test dir targets during the default target is
# that changes to tests may not be updated and code could assume to pass
# locally against non-current test code.
DIRS += $(TEST_DIRS)
ifdef XPCSHELL_TESTS
ifndef relativesrcdir
$(error Must define relativesrcdir when defining XPCSHELL_TESTS.)

View File

@ -4681,7 +4681,7 @@ NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciw
USE_ARM_KUSER=
BUILD_CTYPES=1
MOZ_USE_NATIVE_POPUP_WINDOWS=
MOZ_ANDROID_HISTORY=
case "${target}" in
*android*|*darwin*)
@ -8464,6 +8464,7 @@ AC_SUBST(MOZ_D3DCOMPILER_CAB)
AC_SUBST(MOZ_D3DX9_DLL)
AC_SUBST(MOZ_D3DCOMPILER_DLL)
AC_SUBST(MOZ_ANDROID_HISTORY)
AC_SUBST(ENABLE_STRIP)
AC_SUBST(PKG_SKIP_STRIP)
AC_SUBST(USE_ELF_DYNSTR_GC)

View File

@ -245,7 +245,7 @@ protected:
friend class DataOwnerAdapter; // Needs to see DataOwner
class DataOwner {
public:
NS_INLINE_DECL_REFCOUNTING(DataOwner)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)
DataOwner(void* aMemoryBuffer)
: mData(aMemoryBuffer)
{

View File

@ -819,9 +819,7 @@ nsContentSink::ProcessLink(nsIContent* aElement,
const nsSubstring& aRel, const nsSubstring& aTitle,
const nsSubstring& aType, const nsSubstring& aMedia)
{
// XXX seems overkill to generate this string array
nsTArray<nsString> linkTypes;
nsStyleLinkElement::ParseLinkTypes(aRel, linkTypes);
PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(aRel);
// The link relation may apply to a different resource, specified
// in the anchor parameter. For the link relations supported so far,
@ -831,22 +829,22 @@ nsContentSink::ProcessLink(nsIContent* aElement,
return NS_OK;
}
bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch"));
bool hasPrefetch = linkTypes & PREFETCH;
// prefetch href if relation is "next" or "prefetch"
if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) {
if (hasPrefetch || (linkTypes & NEXT)) {
PrefetchHref(aHref, aElement, hasPrefetch);
}
if ((!aHref.IsEmpty()) && linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) {
if (!aHref.IsEmpty() && (linkTypes & DNS_PREFETCH)) {
PrefetchDNS(aHref);
}
// is it a stylesheet link?
if (!linkTypes.Contains(NS_LITERAL_STRING("stylesheet"))) {
if (!(linkTypes & STYLESHEET)) {
return NS_OK;
}
bool isAlternate = linkTypes.Contains(NS_LITERAL_STRING("alternate"));
bool isAlternate = linkTypes & ALTERNATE;
return ProcessStyleLink(aElement, aHref, isAlternate, aTitle, aType,
aMedia);
}

View File

@ -1782,31 +1782,38 @@ IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg)
}
static const char* kNSURIs[] = {
" ([none])",
" (xmlns)",
" (xml)",
" (xhtml)",
" (XLink)",
" (XSLT)",
" (XBL)",
" (MathML)",
" (RDF)",
" (XUL)"
"([none])",
"(xmlns)",
"(xml)",
"(xhtml)",
"(XLink)",
"(XSLT)",
"(XBL)",
"(MathML)",
"(RDF)",
"(XUL)"
};
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
if (NS_UNLIKELY(cb.WantDebugInfo())) {
char name[512];
nsCAutoString loadedAsData;
if (tmp->IsLoadedAsData()) {
loadedAsData.AssignLiteral("data");
} else {
loadedAsData.AssignLiteral("normal");
}
PRUint32 nsid = tmp->GetDefaultNamespaceID();
nsCAutoString uri;
if (tmp->mDocumentURI)
tmp->mDocumentURI->GetSpec(uri);
if (nsid < ArrayLength(kNSURIs)) {
PR_snprintf(name, sizeof(name), "nsDocument%s %s", kNSURIs[nsid],
uri.get());
PR_snprintf(name, sizeof(name), "nsDocument %s %s %s",
loadedAsData.get(), kNSURIs[nsid], uri.get());
}
else {
PR_snprintf(name, sizeof(name), "nsDocument %s", uri.get());
PR_snprintf(name, sizeof(name), "nsDocument %s %s",
loadedAsData.get(), uri.get());
}
cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsDocument), name);
}
@ -8428,7 +8435,7 @@ nsIDocument::SizeOf() const
}
static void
DispatchFullScreenChange(nsINode* aTarget)
DispatchFullScreenChange(nsIDocument* aTarget)
{
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(aTarget,
@ -8652,7 +8659,7 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
// element, and the full-screen-ancestor styles on ancestors of the element
// in this document.
if (SetFullScreenState(aElement, true)) {
DispatchFullScreenChange(aElement);
DispatchFullScreenChange(aElement->OwnerDoc());
}
// Propagate up the document hierarchy, setting the full-screen element as
@ -8665,7 +8672,7 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
while ((parent = child->GetParentDocument())) {
Element* element = parent->FindContentForSubDocument(child)->AsElement();
if (::SetFullScreenState(parent, element, true)) {
DispatchFullScreenChange(element);
DispatchFullScreenChange(element->OwnerDoc());
}
child = parent;
}

View File

@ -131,6 +131,8 @@ public:
ViewConfig aConfig = ViewConfig())
: mViewportSize(0, 0)
, mContentSize(0, 0)
, mParentScaleX(1.0)
, mParentScaleY(1.0)
, mFrameLoader(aFrameLoader)
, mScrollId(aScrollId)
, mConfig(aConfig)
@ -150,6 +152,8 @@ public:
nsSize mViewportSize;
nsSize mContentSize;
float mParentScaleX;
float mParentScaleY;
nsFrameLoader* mFrameLoader; // WEAK

View File

@ -107,6 +107,7 @@ static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
#ifdef ANDROID
#include "nsXULAppAPI.h"
#include "mozilla/Preferences.h"
#endif
class nsAsyncInstantiateEvent : public nsRunnable {
@ -1066,11 +1067,7 @@ nsObjectLoadingContent::ObjectState() const
case eType_Image:
return ImageState();
case eType_Plugin:
#ifdef ANDROID
if (XRE_GetProcessType() == GeckoProcessType_Content)
return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
#endif
case eType_Document:
case eType_Document:
// These are OK. If documents start to load successfully, they display
// something, and are thus not broken in this sense. The same goes for
// plugins.
@ -1966,8 +1963,10 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
{
#ifdef ANDROID
if (XRE_GetProcessType() == GeckoProcessType_Content)
return ePluginClickToPlay;
// if plugins are disabled, don't show the click to play message
if (!mozilla::Preferences::GetBool("plugin.disable", false) &&
XRE_GetProcessType() == GeckoProcessType_Content)
return ePluginClickToPlay;
#endif
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());

View File

@ -153,24 +153,40 @@ nsStyleLinkElement::SetLineNumber(PRUint32 aLineNumber)
mLineNumber = aLineNumber;
}
void nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes,
nsTArray<nsString>& aResult)
PRUint32 ToLinkMask(const nsAString& aLink)
{
if (aLink.EqualsLiteral("prefetch"))
return PREFETCH;
else if (aLink.EqualsLiteral("dns-prefetch"))
return DNS_PREFETCH;
else if (aLink.EqualsLiteral("stylesheet"))
return STYLESHEET;
else if (aLink.EqualsLiteral("next"))
return NEXT;
else if (aLink.EqualsLiteral("alternate"))
return ALTERNATE;
else
return 0;
}
PRUint32 nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes)
{
PRUint32 linkMask = 0;
nsAString::const_iterator start, done;
aTypes.BeginReading(start);
aTypes.EndReading(done);
if (start == done)
return;
return linkMask;
nsAString::const_iterator current(start);
bool inString = !nsCRT::IsAsciiSpace(*current);
nsAutoString subString;
while (current != done) {
if (nsCRT::IsAsciiSpace(*current)) {
if (inString) {
ToLowerCase(Substring(start, current), subString);
aResult.AppendElement(subString);
linkMask |= ToLinkMask(subString);
inString = false;
}
}
@ -184,8 +200,9 @@ void nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes,
}
if (inString) {
ToLowerCase(Substring(start, current), subString);
aResult.AppendElement(subString);
linkMask |= ToLinkMask(subString);
}
return linkMask;
}
NS_IMETHODIMP

View File

@ -53,6 +53,12 @@
#include "nsIURI.h"
#include "nsTArray.h"
#define PREFETCH 0x00000001
#define DNS_PREFETCH 0x00000002
#define STYLESHEET 0x00000004
#define NEXT 0x00000008
#define ALTERNATE 0x00000010
class nsIDocument;
class nsStyleLinkElement : public nsIDOMLinkStyle,
@ -80,8 +86,8 @@ public:
virtual void OverrideBaseURI(nsIURI* aNewBaseURI);
virtual void SetLineNumber(PRUint32 aLineNumber);
static void ParseLinkTypes(const nsAString& aTypes, nsTArray<nsString>& aResult);
static PRUint32 ParseLinkTypes(const nsAString& aTypes);
void UpdateStyleSheetInternal() { UpdateStyleSheetInternal(nsnull); }
protected:
/**

View File

@ -103,6 +103,7 @@
#include "nsStringBuffer.h"
#include "nsDOMFile.h"
#include "nsIFileChannel.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
@ -1485,6 +1486,8 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
// No optional arguments were passed in. Default async to true.
async = true;
}
Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC,
async ? 0 : 1);
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);

View File

@ -301,16 +301,17 @@ WebGLContext::WebGLContext()
mContextLost = false;
mAllowRestore = false;
mRobustnessTimerRunning = false;
mDrawSinceRobustnessTimerSet = false;
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
}
WebGLContext::~WebGLContext()
{
DestroyResourcesAndContext();
WebGLMemoryReporter::RemoveWebGLContext(this);
if (mContextRestorer) {
mContextRestorer->Cancel();
mContextRestorer = NULL;
}
TerminateRobustnessTimer();
mContextRestorer = nsnull;
}
static PLDHashOperator
@ -709,6 +710,8 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
mResetLayer = true;
mOptionsFrozen = true;
mHasRobustness = gl->HasRobustness();
// increment the generation number
++mGeneration;
@ -1147,13 +1150,8 @@ WebGLContext::EnsureBackbufferClearedAsNeeded()
NS_IMETHODIMP
WebGLContext::Notify(nsITimer* timer)
{
TerminateRobustnessTimer();
MaybeRestoreContext();
if (mContextRestorer) {
mContextRestorer->Cancel();
mContextRestorer = NULL;
}
return NS_OK;
}
@ -1163,6 +1161,7 @@ WebGLContext::MaybeRestoreContext()
if (mContextLost || mAllowRestore)
return;
gl->MakeCurrent();
GLContext::ContextResetARB resetStatus =
(GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
@ -1174,6 +1173,11 @@ WebGLContext::MaybeRestoreContext()
switch (resetStatus) {
case GLContext::CONTEXT_NO_ERROR:
// If there has been activity since the timer was set, it's possible
// that we did or are going to miss something, so clear this flag and
// run it again some time later.
if (mDrawSinceRobustnessTimerSet)
SetupRobustnessTimer();
return;
case GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB:
NS_WARNING("WebGL content on the page caused the graphics card to reset; not restoring the context");
@ -1191,10 +1195,7 @@ WebGLContext::MaybeRestoreContext()
void
WebGLContext::ForceLoseContext()
{
if (mContextRestorer) {
mContextRestorer->Cancel();
mContextRestorer = NULL;
}
TerminateRobustnessTimer();
mWebGLError = LOCAL_GL_CONTEXT_LOST;

View File

@ -449,17 +449,30 @@ public:
// Sets up the GL_ARB_robustness timer if it isn't already, so that if the
// driver gets restarted, the context may get reset with it.
void SetupRobustnessTimer() {
if (mContextLost)
if (mContextLost || !mHasRobustness)
return;
if (!mContextRestorer)
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
// If the timer was already running, don't restart it here. Instead,
// wait until the previous call is done, then fire it one more time.
// This is an optimization to prevent unnecessary cross-communication
// between threads.
if (mRobustnessTimerRunning) {
mDrawSinceRobustnessTimerSet = true;
return;
}
// As long as there's still activity, we reset the timer each time that
// this function gets called.
mContextRestorer->InitWithCallback(static_cast<nsITimerCallback*>(this),
PR_MillisecondsToInterval(1000),
nsITimer::TYPE_ONE_SHOT);
mRobustnessTimerRunning = true;
mDrawSinceRobustnessTimerSet = false;
}
void TerminateRobustnessTimer() {
if (mRobustnessTimerRunning) {
mContextRestorer->Cancel();
mRobustnessTimerRunning = false;
}
}
protected:
@ -504,6 +517,7 @@ protected:
bool mOptionsFrozen;
bool mMinCapability;
bool mDisableExtensions;
bool mHasRobustness;
WebGLuint mActiveTexture;
WebGLenum mWebGLError;
@ -723,6 +737,8 @@ protected:
nsCOMPtr<nsITimer> mContextRestorer;
bool mContextLost;
bool mAllowRestore;
bool mRobustnessTimerRunning;
bool mDrawSinceRobustnessTimerSet;
public:
// console logging helpers

View File

@ -1622,8 +1622,6 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
if (!ValidateBuffers(&maxAllowedCount, "drawArrays"))
return NS_OK;
SetupRobustnessTimer();
CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count;
if (!checked_firstPlusCount.valid())
@ -1645,6 +1643,7 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value()))
return NS_OK;
SetupRobustnessTimer();
gl->fDrawArrays(mode, first, count);
UndoFakeVertexAttrib0();
@ -1675,8 +1674,6 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
if (count == 0)
return NS_OK;
SetupRobustnessTimer();
CheckedUint32 checked_byteCount;
if (type == LOCAL_GL_UNSIGNED_SHORT) {
@ -1757,6 +1754,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
if (!DoFakeVertexAttrib0(checked_maxIndexPlusOne.value()))
return NS_OK;
SetupRobustnessTimer();
gl->fDrawElements(mode, count, type, (GLvoid*) (byteOffset));
UndoFakeVertexAttrib0();

View File

@ -61,7 +61,7 @@ NS_IMETHODIMP
WebGLExtensionLoseContext::LoseContext()
{
if (!mContext->LoseContext())
return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
return NS_OK;
}
@ -70,7 +70,7 @@ NS_IMETHODIMP
WebGLExtensionLoseContext::RestoreContext()
{
if (!mContext->RestoreContext())
return mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
return NS_OK;
}

View File

@ -116,6 +116,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/Preferences.h"
#ifdef XP_WIN
#include "gfxWindowsPlatform.h"
@ -989,9 +990,10 @@ nsresult
NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
{
#ifdef XP_WIN
if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
if ((gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
gfxWindowsPlatform::RENDER_DIRECT2D ||
!gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) {
!gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) &&
!Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
return NS_ERROR_NOT_AVAILABLE;
}
#elif !defined(XP_MACOSX) && !defined(ANDROID)
@ -3648,8 +3650,8 @@ nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1,
return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
// Ignore nsnull cairo surfaces! See bug 666312.
if (!res.mSurface->CairoSurface()) {
// Ignore cairo surfaces that are bad! See bug 666312.
if (res.mSurface->CairoStatus()) {
return NS_OK;
}

View File

@ -29,6 +29,18 @@ function IsAzureEnabled() {
return enabled;
}
function IsAzureSkia() {
var enabled = false;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureBackend;
enabled = (backend == "skia");
} catch (e) { }
return enabled;
}
</script>
<!-- Includes all the tests in the content/canvas/tests except for test_bug397524.html -->
@ -11985,7 +11997,7 @@ isPixel(ctx, 65,21, 0,255,0,255, 0);
isPixel(ctx, 72,28, 0,255,0,255, 0);
isPixel(ctx, 73,27, 0,255,0,255, 0);
isPixel(ctx, 78,36, 0,255,0,255, 0);
isPixel(ctx, 79,35, 0,255,0,255, 0);
isPixel(ctx, 79,35, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 80,44, 0,255,0,255, 0);
isPixel(ctx, 80,45, 0,255,0,255, 0);
isPixel(ctx, 80,46, 0,255,0,255, 0);
@ -12032,11 +12044,11 @@ isPixel(ctx, 50,25, 0,255,0,255, 0);
isPixel(ctx, 55,19, 0,255,0,255, 0);
isPixel(ctx, 55,20, 0,255,0,255, 0);
isPixel(ctx, 55,21, 0,255,0,255, 0);
isPixel(ctx, 64,22, 0,255,0,255, 0);
isPixel(ctx, 64,22, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 65,21, 0,255,0,255, 0);
isPixel(ctx, 72,28, 0,255,0,255, 0);
isPixel(ctx, 73,27, 0,255,0,255, 0);
isPixel(ctx, 78,36, 0,255,0,255, 0);
isPixel(ctx, 73,27, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 78,36, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 79,35, 0,255,0,255, 0);
isPixel(ctx, 80,44, 0,255,0,255, 0);
isPixel(ctx, 80,45, 0,255,0,255, 0);
@ -14339,8 +14351,11 @@ ctx.lineTo(50, 25);
ctx.closePath();
ctx.stroke();
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
if (IsAzureEnabled() && IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
}
}
</script>
@ -14412,7 +14427,11 @@ ctx.moveTo(50, 25);
ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
ctx.stroke();
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
if (IsAzureEnabled() && IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
}
}
@ -14445,8 +14464,11 @@ ctx.moveTo(50, 25);
ctx.lineTo(50, 25);
ctx.stroke();
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
if (IsAzureEnabled() && IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
}
}
</script>
@ -14479,8 +14501,11 @@ ctx.stroke();
ctx.strokeRect(50, 25, 0, 0);
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
if (IsAzureEnabled() && IsAzureSkia()) {
isPixel(ctx, 50,25, 0,255,0,255, 0);
} else {
todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
}
}
</script>
@ -19185,7 +19210,7 @@ isPixel(ctx, 21,11, 0,255,0,255, 0);
isPixel(ctx, 79,11, 0,255,0,255, 0);
isPixel(ctx, 21,39, 0,255,0,255, 0);
isPixel(ctx, 79,39, 0,255,0,255, 0);
isPixel(ctx, 39,19, 0,255,0,255, 0);
isPixel(ctx, 39,19, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 61,19, 0,255,0,255, 0);
isPixel(ctx, 39,31, 0,255,0,255, 0);
isPixel(ctx, 61,31, 0,255,0,255, 0);
@ -19393,7 +19418,7 @@ isPixel(ctx, 21,11, 0,255,0,255, 0);
isPixel(ctx, 79,11, 0,255,0,255, 0);
isPixel(ctx, 21,39, 0,255,0,255, 0);
isPixel(ctx, 79,39, 0,255,0,255, 0);
isPixel(ctx, 39,19, 0,255,0,255, 0);
isPixel(ctx, 39,19, 0,255,0,255, IsAzureSkia() ? 1 : 0);
isPixel(ctx, 61,19, 0,255,0,255, 0);
isPixel(ctx, 39,31, 0,255,0,255, 0);
isPixel(ctx, 61,31, 0,255,0,255, 0);

View File

@ -134,10 +134,9 @@ function testFailedRender(msg, ref, test, width, height)
testFailed(msg);
var data = 'REFTEST TEST-KNOWN-FAIL | ' + msg + ' | image comparison (==)\n' +
var data = 'REFTEST TEST-DEBUG-INFO | ' + msg + ' | image comparison (==)\n' +
'REFTEST IMAGE 1 (TEST): ' + testData + '\n' +
'REFTEST IMAGE 2 (REFERENCE): ' + refData;
dump('The following information is for debugging purposes only. It will always print TEST-KNOWN-FAIL, even if it is unexpected.');
dump('FAIL: ' + data + '\n');
dump('To view the differences between these image renderings, go to the following link: https://hg.mozilla.org/mozilla-central/raw-file/tip/layout/tools/reftest/reftest-analyzer.xhtml#log=' +
encodeURIComponent(encodeURIComponent(data)) + '\n');

View File

@ -307,9 +307,8 @@ nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
bool dropSheet = false;
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::rel &&
GetStyleSheet()) {
nsAutoTArray<nsString, 4> linkTypes;
nsStyleLinkElement::ParseLinkTypes(aValue, linkTypes);
dropSheet = !linkTypes.Contains(NS_LITERAL_STRING("stylesheet"));
PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(aValue);
dropSheet = !(linkTypes & STYLESHEET);
}
UpdateStyleSheetInternal(nsnull,
@ -413,11 +412,10 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
*aIsAlternate = false;
nsAutoString rel;
nsAutoTArray<nsString, 4> linkTypes;
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
nsStyleLinkElement::ParseLinkTypes(rel, linkTypes);
PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
// Is it a stylesheet link?
if (!linkTypes.Contains(NS_LITERAL_STRING("stylesheet"))) {
if (!(linkTypes & STYLESHEET)) {
return;
}
@ -427,7 +425,7 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
aTitle.Assign(title);
// If alternate, does it have title?
if (linkTypes.Contains(NS_LITERAL_STRING("alternate"))) {
if (linkTypes & ALTERNATE) {
if (aTitle.IsEmpty()) { // alternates must have title
return;
} else {

View File

@ -65,7 +65,7 @@ function fullScreenChange(event) {
switch (fullScreenChangeCount) {
case 0: {
ok(document.mozFullScreen, "Should be in full-screen mode (first time)");
is(event.target, fullScreenElement(), "Event target should be full-screen element");
is(event.target, document, "Event target should be full-screen document #1");
is(document.mozFullScreenElement, fullScreenElement(),
"Full-screen element should be div element.");
ok(document.mozFullScreenElement.mozMatchesSelector(":-moz-full-screen"),
@ -83,7 +83,7 @@ function fullScreenChange(event) {
}
case 1: {
ok(!document.mozFullScreen, "Should have left full-screen mode (first time)");
is(event.target, document, "Event target should be document when we exit via removing from doc");
is(event.target, document, "Event target should be full-screen document #2");
is(document.mozFullScreenElement, null, "Full-screen element should be null.");
iframe = document.createElement("iframe");
iframe.mozAllowFullScreen = true;
@ -93,8 +93,7 @@ function fullScreenChange(event) {
}
case 2: {
ok(document.mozFullScreen, "Should be back in full-screen mode (second time)");
is(event.target, iframe,
"Event target should be full-screen element container");
is(event.target, document, "Event target should be full-screen document #3");
is(document.mozFullScreenElement, iframe,
"Full-screen element should be iframe element.");
@ -126,8 +125,7 @@ function fullScreenChange(event) {
}
case 3: {
ok(!document.mozFullScreen, "Should be back in non-full-screen mode (second time)");
is(event.target, document,
"Event target should be full-screen element container");
is(event.target, document, "Event target should be full-screen document #4");
is(document.mozFullScreenElement, null, "Full-screen element should be null.");
document.body.removeChild(iframe);
iframe = null;
@ -155,7 +153,7 @@ function fullScreenChange(event) {
}
case 4: {
ok(document.mozFullScreen, "Should still be in full-screen mode (third time)");
is(event.target, inDocElement, "Event target should be inDocElement");
is(event.target, document, "Event target should be full-screen document #5");
ok(fullScreenErrorRun, "Should have run fullscreenerror handler from previous case.");
is(document.mozFullScreenElement, inDocElement,
"FSE should be inDocElement.");

View File

@ -2644,18 +2644,16 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
nsAutoString relVal;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
if (!relVal.IsEmpty()) {
// XXX seems overkill to generate this string array
nsAutoTArray<nsString, 4> linkTypes;
nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes);
bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch"));
if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) {
PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
bool hasPrefetch = linkTypes & PREFETCH;
if (hasPrefetch || (linkTypes & NEXT)) {
nsAutoString hrefVal;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, element, hasPrefetch);
}
}
if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) {
if (linkTypes & DNS_PREFETCH) {
nsAutoString hrefVal;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {

View File

@ -950,6 +950,7 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
// Set the parser as the stream listener for the document loader...
if (mParser) {
rv = NS_OK;
nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
listener.forget(aDocListener);

View File

@ -90,13 +90,12 @@ public:
// nsScriptElement
virtual bool HasScriptContent();
// nsSVGElement specializations:
virtual void DidChangeString(PRUint8 aAttrEnum);
// nsIContent specializations:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers);
virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
const nsAString* aValue, bool aNotify);
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
@ -252,16 +251,6 @@ nsSVGScriptElement::HasScriptContent()
//----------------------------------------------------------------------
// nsSVGElement methods
void
nsSVGScriptElement::DidChangeString(PRUint8 aAttrEnum)
{
nsSVGScriptElementBase::DidChangeString(aAttrEnum);
if (aAttrEnum == HREF) {
MaybeProcessScript();
}
}
nsSVGElement::StringAttributesInfo
nsSVGScriptElement::GetStringInfo()
{
@ -289,3 +278,13 @@ nsSVGScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
return NS_OK;
}
nsresult
nsSVGScriptElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
const nsAString* aValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
MaybeProcessScript();
}
return nsSVGScriptElementBase::AfterSetAttr(aNamespaceID, aName,
aValue, aNotify);
}

View File

@ -646,18 +646,16 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
nsAutoString relVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
if (!relVal.IsEmpty()) {
// XXX seems overkill to generate this string array
nsAutoTArray<nsString, 4> linkTypes;
nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes);
bool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch"));
if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) {
PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
bool hasPrefetch = linkTypes & PREFETCH;
if (hasPrefetch || (linkTypes & NEXT)) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, aContent, hasPrefetch);
}
}
if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) {
if (linkTypes & DNS_PREFETCH) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {

View File

@ -106,10 +106,4 @@ public:
static double toDouble(const nsAString& aStr);
};
// XXX These should go away eventually.
#define TxObject txObject
typedef txDouble Double;
// XXX
#endif

View File

@ -50,20 +50,20 @@
*/
//-- Initialize Double related constants
const dpun Double::NaN = DOUBLE_NaN;
const dpun txDouble::NaN = DOUBLE_NaN;
#ifdef IS_BIG_ENDIAN
const dpun Double::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}};
const dpun Double::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}};
const dpun txDouble::POSITIVE_INFINITY = {{DOUBLE_HI32_EXPMASK, 0}};
const dpun txDouble::NEGATIVE_INFINITY = {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT, 0}};
#else
const dpun Double::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}};
const dpun Double::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}};
const dpun txDouble::POSITIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK}};
const dpun txDouble::NEGATIVE_INFINITY = {{0, DOUBLE_HI32_EXPMASK | DOUBLE_HI32_SIGNBIT}};
#endif
/*
* Determines whether the given double represents positive or negative
* inifinity
*/
bool Double::isInfinite(double aDbl)
bool txDouble::isInfinite(double aDbl)
{
return ((DOUBLE_HI32(aDbl) & ~DOUBLE_HI32_SIGNBIT) == DOUBLE_HI32_EXPMASK &&
!DOUBLE_LO32(aDbl));
@ -72,7 +72,7 @@ bool Double::isInfinite(double aDbl)
/*
* Determines whether the given double is NaN
*/
bool Double::isNaN(double aDbl)
bool txDouble::isNaN(double aDbl)
{
return DOUBLE_IS_NaN(aDbl);
}
@ -80,7 +80,7 @@ bool Double::isNaN(double aDbl)
/*
* Determines whether the given double is negative
*/
bool Double::isNeg(double aDbl)
bool txDouble::isNeg(double aDbl)
{
return (DOUBLE_HI32(aDbl) & DOUBLE_HI32_SIGNBIT) != 0;
}
@ -170,7 +170,7 @@ public:
{
if (mState == eIllegal || mBuffer.IsEmpty() ||
(mBuffer.Length() == 1 && mBuffer[0] == '.')) {
return Double::NaN;
return txDouble::NaN;
}
return mSign*PR_strtod(mBuffer.get(), 0);
}
@ -189,7 +189,7 @@ private:
} mSign;
};
double Double::toDouble(const nsAString& aSrc)
double txDouble::toDouble(const nsAString& aSrc)
{
txStringToDouble sink;
nsAString::const_iterator fromBegin, fromEnd;
@ -202,7 +202,7 @@ double Double::toDouble(const nsAString& aSrc)
* The result into the destination String.
* @return the given dest string
*/
void Double::toString(double aValue, nsAString& aDest)
void txDouble::toString(double aValue, nsAString& aDest)
{
// check for special cases

View File

@ -46,7 +46,7 @@ class txListIterator;
/**
* Represents an ordered list of Object pointers. Modeled after a Java 2 List.
**/
class txList : public TxObject {
class txList : public txObject {
friend class txListIterator;

View File

@ -82,7 +82,7 @@ class ProcessingInstruction;
// Abstract Class defining the interface for a Node. See NodeDefinition below
// for the actual implementation of the WC3 node.
//
class Node : public TxObject
class Node : public txObject
{
public:
//Node type constants

View File

@ -396,8 +396,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
// check for NaN or +/-Inf
if (Double::isNaN(start) ||
Double::isInfinite(start) ||
if (txDouble::isNaN(start) ||
txDouble::isInfinite(start) ||
start >= src.Length() + 0.5) {
aContext->recycler()->getEmptyStringResult(aResult);
@ -412,7 +412,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
NS_ENSURE_SUCCESS(rv, rv);
end += start;
if (Double::isNaN(end) || end < 0) {
if (txDouble::isNaN(end) || end < 0) {
aContext->recycler()->getEmptyStringResult(aResult);
return NS_OK;
@ -546,7 +546,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
nsAutoString resultStr;
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
resultStr);
res = Double::toDouble(resultStr);
res = txDouble::toDouble(resultStr);
}
return aContext->recycler()->getNumberResult(res, aResult);
}
@ -556,8 +556,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
if (Double::isNeg(dbl) && dbl >= -0.5) {
if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) {
if (txDouble::isNeg(dbl) && dbl >= -0.5) {
dbl *= 0;
}
else {
@ -573,9 +573,9 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!Double::isNaN(dbl) &&
!Double::isInfinite(dbl) &&
!(dbl == 0 && Double::isNeg(dbl))) {
if (!txDouble::isNaN(dbl) &&
!txDouble::isInfinite(dbl) &&
!(dbl == 0 && txDouble::isNeg(dbl))) {
dbl = floor(dbl);
}
@ -587,8 +587,8 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
rv = evaluateToNumber(mParams[0], aContext, &dbl);
NS_ENSURE_SUCCESS(rv, rv);
if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
if (Double::isNeg(dbl) && dbl > -1) {
if (!txDouble::isNaN(dbl) && !txDouble::isInfinite(dbl)) {
if (txDouble::isNeg(dbl) && dbl > -1) {
dbl *= 0;
}
else {
@ -610,7 +610,7 @@ txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
for (i = 0; i < nodes->size(); ++i) {
nsAutoString resultStr;
txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
res += Double::toDouble(resultStr);
res += txDouble::toDouble(resultStr);
}
return aContext->recycler()->getNumberResult(res, aResult);
}

View File

@ -419,7 +419,7 @@ txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext,
break;
case Token::NUMBER:
{
expr = new txLiteralExpr(Double::toDouble(tok->Value()));
expr = new txLiteralExpr(txDouble::toDouble(tok->Value()));
break;
}
default:

View File

@ -103,7 +103,7 @@ txLiteralExpr::toString(nsAString& aStr)
}
case txAExprResult::NUMBER:
{
Double::toString(mValue->numberValue(), aStr);
txDouble::toString(mValue->numberValue(), aStr);
return;
}
case txAExprResult::STRING:

View File

@ -501,7 +501,7 @@ txNodeSet::numberValue()
nsAutoString str;
stringValue(str);
return Double::toDouble(str);
return txDouble::toDouble(str);
}
void

View File

@ -86,7 +86,7 @@ txNodeSetAdaptor::ItemAsNumber(PRUint32 aIndex, double *aResult)
nsAutoString result;
txXPathNodeUtils::appendNodeValue(NodeSet()->get(aIndex), result);
*aResult = Double::toDouble(result);
*aResult = txDouble::toDouble(result);
return NS_OK;
}

View File

@ -70,16 +70,16 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
if (rightDbl == 0) {
#if defined(XP_WIN)
/* XXX MSVC miscompiles such that (NaN == 0) */
if (Double::isNaN(rightDbl))
result = Double::NaN;
if (txDouble::isNaN(rightDbl))
result = txDouble::NaN;
else
#endif
if (leftDbl == 0 || Double::isNaN(leftDbl))
result = Double::NaN;
else if (Double::isNeg(leftDbl) ^ Double::isNeg(rightDbl))
result = Double::NEGATIVE_INFINITY;
if (leftDbl == 0 || txDouble::isNaN(leftDbl))
result = txDouble::NaN;
else if (txDouble::isNeg(leftDbl) ^ txDouble::isNeg(rightDbl))
result = txDouble::NEGATIVE_INFINITY;
else
result = Double::POSITIVE_INFINITY;
result = txDouble::POSITIVE_INFINITY;
}
else
result = leftDbl / rightDbl;
@ -87,12 +87,12 @@ txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
case MODULUS:
if (rightDbl == 0) {
result = Double::NaN;
result = txDouble::NaN;
}
else {
#if defined(XP_WIN)
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
if (!Double::isInfinite(leftDbl) && Double::isInfinite(rightDbl))
if (!txDouble::isInfinite(leftDbl) && txDouble::isInfinite(rightDbl))
result = leftDbl;
else
#endif

View File

@ -67,7 +67,7 @@ short NumberResult::getResultType() {
void
NumberResult::stringValue(nsString& aResult)
{
Double::toString(value, aResult);
txDouble::toString(value, aResult);
}
const nsString*
@ -80,7 +80,7 @@ bool NumberResult::booleanValue() {
// OG+
// As per the XPath spec, the boolean value of a number is true if and only if
// it is neither positive 0 nor negative 0 nor NaN
return (bool)(value != 0.0 && !Double::isNaN(value));
return (bool)(value != 0.0 && !txDouble::isNaN(value));
// OG-
} //-- booleanValue

View File

@ -84,6 +84,6 @@ bool StringResult::booleanValue() {
} //-- booleanValue
double StringResult::numberValue() {
return Double::toDouble(mValue);
return txDouble::toDouble(mValue);
} //-- numberValue

View File

@ -58,7 +58,7 @@ double
txUnionNodeTest::getDefaultPriority()
{
NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
return Double::NaN;
return txDouble::NaN;
}
bool

View File

@ -611,7 +611,7 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
if (nodes->isEmpty()) {
return aContext->recycler()->
getNumberResult(Double::NaN, aResult);
getNumberResult(txDouble::NaN, aResult);
}
bool findMax = mType == MAX;
@ -622,9 +622,9 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
for (i = 0; i < len; ++i) {
nsAutoString str;
txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
double val = Double::toDouble(str);
if (Double::isNaN(val)) {
res = Double::NaN;
double val = txDouble::toDouble(str);
if (txDouble::isNaN(val)) {
res = txDouble::NaN;
break;
}
@ -661,8 +661,8 @@ txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
nsAutoString str;
const txXPathNode& node = nodes->get(i);
txXPathNodeUtils::appendNodeValue(node, str);
double val = Double::toDouble(str);
if (Double::isNaN(val)) {
double val = txDouble::toDouble(str);
if (txDouble::isNaN(val)) {
resultSet->clear();
break;
}

View File

@ -112,16 +112,16 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
}
// Special cases
if (Double::isNaN(value)) {
if (txDouble::isNaN(value)) {
return aContext->recycler()->getStringResult(format->mNaN, aResult);
}
if (value == Double::POSITIVE_INFINITY) {
if (value == txDouble::POSITIVE_INFINITY) {
return aContext->recycler()->getStringResult(format->mInfinity,
aResult);
}
if (value == Double::NEGATIVE_INFINITY) {
if (value == txDouble::NEGATIVE_INFINITY) {
nsAutoString res;
res.Append(format->mMinusSign);
res.Append(format->mInfinity);
@ -143,7 +143,7 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
// Get right subexpression
inQuote = false;
if (Double::isNeg(value)) {
if (txDouble::isNeg(value)) {
while (pos < formatLen &&
(inQuote ||
formatStr.CharAt(pos) != format->mPatternSeparator)) {

View File

@ -51,7 +51,7 @@
class nsIAtom;
class txExecutionState;
class txInstruction : public TxObject
class txInstruction : public txObject
{
public:
txInstruction()

View File

@ -180,8 +180,8 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
PRUint32 len = static_cast<PRUint32>(aNodes->size());
// Limit resource use to something sane.
PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(TxObject*);
if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(TxObject*) ||
PRUint32 itemSize = sizeof(PRUint32) + mNKeys * sizeof(txObject*);
if (mNKeys > (PR_UINT32_MAX - sizeof(PRUint32)) / sizeof(txObject*) ||
len >= PR_UINT32_MAX / itemSize) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -190,13 +190,13 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY);
PRUint32* indexes = static_cast<PRUint32*>(mem);
TxObject** sortValues = reinterpret_cast<TxObject**>(indexes + len);
txObject** sortValues = reinterpret_cast<txObject**>(indexes + len);
PRUint32 i;
for (i = 0; i < len; ++i) {
indexes[i] = i;
}
memset(sortValues, 0, len * mNKeys * sizeof(TxObject*));
memset(sortValues, 0, len * mNKeys * sizeof(txObject*));
// Sort the indexarray
SortData sortData;
@ -248,9 +248,9 @@ txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB,
txListIterator iter(&sortData->mNodeSorter->mSortKeys);
PRUint32 indexA = *static_cast<const PRUint32*>(aIndexA);
PRUint32 indexB = *static_cast<const PRUint32*>(aIndexB);
TxObject** sortValuesA = sortData->mSortValues +
txObject** sortValuesA = sortData->mSortValues +
indexA * sortData->mNodeSorter->mNKeys;
TxObject** sortValuesB = sortData->mSortValues +
txObject** sortValuesB = sortData->mSortValues +
indexB * sortData->mNodeSorter->mNKeys;
unsigned int i;
@ -280,7 +280,7 @@ txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB,
//static
bool
txNodeSorter::calcSortValue(TxObject*& aSortValue, SortKey* aKey,
txNodeSorter::calcSortValue(txObject*& aSortValue, SortKey* aKey,
SortData* aSortData, PRUint32 aNodeIndex)
{
aSortData->mContext->setPosition(aNodeIndex + 1); // position is 1-based

View File

@ -46,7 +46,7 @@
class Expr;
class txExecutionState;
class txNodeSet;
class TxObject;
class txObject;
class txXPathResultComparator;
class txIEvalContext;
class txNodeSetContext;
@ -72,7 +72,7 @@ private:
{
txNodeSorter* mNodeSorter;
txNodeSetContext* mContext;
TxObject** mSortValues;
txObject** mSortValues;
nsresult mRv;
};
struct SortKey
@ -83,8 +83,8 @@ private:
static int compareNodes(const void* aIndexA, const void* aIndexB,
void* aSortData);
static bool calcSortValue(TxObject*& aSortValue, SortKey* aKey,
SortData* aSortData, PRUint32 aNodeIndex);
static bool calcSortValue(txObject*& aSortValue, SortKey* aKey,
SortData* aSortData, PRUint32 aNodeIndex);
txList mSortKeys;
unsigned int mNKeys;
};

View File

@ -77,7 +77,7 @@ double txResultTreeFragment::numberValue()
return 0;
}
return Double::toDouble(mBuffer->mStringValue);
return txDouble::toDouble(mBuffer->mStringValue);
}
nsresult txResultTreeFragment::flushToHandler(txAXMLEventHandler* aHandler)

View File

@ -442,9 +442,9 @@ txStylesheet::addTemplate(txTemplateItem* aTemplate,
PRUint32 unionPos = 1; // only used when unionPattern is set
while (simple) {
double priority = aTemplate->mPrio;
if (Double::isNaN(priority)) {
if (txDouble::isNaN(priority)) {
priority = simple->getDefaultPriority();
NS_ASSERTION(!Double::isNaN(priority),
NS_ASSERTION(!txDouble::isNaN(priority),
"simple pattern without default priority");
}

View File

@ -128,7 +128,7 @@ public:
ImportFrame* mFirstNotImported;
};
class GlobalVariable : public TxObject {
class GlobalVariable : public txObject {
public:
GlobalVariable(nsAutoPtr<Expr> aExpr,
nsAutoPtr<txInstruction> aFirstInstruction,

View File

@ -303,7 +303,7 @@ getNumberAttr(txStylesheetAttr* aAttributes,
txStylesheetCompilerState& aState,
double& aNumber)
{
aNumber = Double::NaN;
aNumber = txDouble::NaN;
txStylesheetAttr* attr = nsnull;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
aName, aRequired, &attr);
@ -311,8 +311,8 @@ getNumberAttr(txStylesheetAttr* aAttributes,
return rv;
}
aNumber = Double::toDouble(attr->mValue);
if (Double::isNaN(aNumber) && (aRequired || !aState.fcp())) {
aNumber = txDouble::toDouble(attr->mValue);
if (txDouble::isNaN(aNumber) && (aRequired || !aState.fcp())) {
// XXX ErrorReport: number parse failure
return NS_ERROR_XSLT_PARSE_FAILURE;
}
@ -552,7 +552,7 @@ txFnStartLREStylesheet(PRInt32 aNamespaceID,
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName nullExpr;
double prio = Double::NaN;
double prio = txDouble::NaN;
nsAutoPtr<txPattern> match(new txRootPattern());
NS_ENSURE_TRUE(match, NS_ERROR_OUT_OF_MEMORY);
@ -1145,7 +1145,7 @@ txFnStartTemplate(PRInt32 aNamespaceID,
aState, mode);
NS_ENSURE_SUCCESS(rv, rv);
double prio = Double::NaN;
double prio = txDouble::NaN;
rv = getNumberAttr(aAttributes, aAttrCount, nsGkAtoms::priority,
false, aState, prio);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -688,15 +688,15 @@ txStylesheetCompilerState::popChooseGotoList()
}
nsresult
txStylesheetCompilerState::pushObject(TxObject* aObject)
txStylesheetCompilerState::pushObject(txObject* aObject)
{
return mObjectStack.push(aObject);
}
TxObject*
txObject*
txStylesheetCompilerState::popObject()
{
return static_cast<TxObject*>(mObjectStack.pop());
return static_cast<txObject*>(mObjectStack.pop());
}
nsresult

View File

@ -60,7 +60,7 @@ class txPushNewContext;
class txStylesheetCompiler;
class txInScopeVariable;
class txElementContext : public TxObject
class txElementContext : public txObject
{
public:
txElementContext(const nsAString& aBaseURI);
@ -122,8 +122,8 @@ public:
void popSorter();
nsresult pushChooseGotoList();
void popChooseGotoList();
nsresult pushObject(TxObject* aObject);
TxObject* popObject();
nsresult pushObject(txObject* aObject);
txObject* popObject();
nsresult pushPtr(void* aPtr);
void* popPtr();

View File

@ -129,7 +129,7 @@ txResultStringComparator::createSortableValue(Expr *aExpr,
return NS_OK;
}
int txResultStringComparator::compareValues(TxObject* aVal1, TxObject* aVal2)
int txResultStringComparator::compareValues(txObject* aVal1, txObject* aVal2)
{
StringValue* strval1 = (StringValue*)aVal1;
StringValue* strval2 = (StringValue*)aVal2;
@ -223,7 +223,7 @@ txResultNumberComparator::txResultNumberComparator(bool aAscending)
nsresult
txResultNumberComparator::createSortableValue(Expr *aExpr,
txIEvalContext *aContext,
TxObject *&aResult)
txObject *&aResult)
{
nsAutoPtr<NumberValue> numval(new NumberValue);
if (!numval) {
@ -241,15 +241,15 @@ txResultNumberComparator::createSortableValue(Expr *aExpr,
return NS_OK;
}
int txResultNumberComparator::compareValues(TxObject* aVal1, TxObject* aVal2)
int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2)
{
double dval1 = ((NumberValue*)aVal1)->mVal;
double dval2 = ((NumberValue*)aVal2)->mVal;
if (Double::isNaN(dval1))
return Double::isNaN(dval2) ? 0 : -mAscending;
if (txDouble::isNaN(dval1))
return txDouble::isNaN(dval2) ? 0 : -mAscending;
if (Double::isNaN(dval2))
if (txDouble::isNaN(dval2))
return mAscending;
if (dval1 == dval2)

View File

@ -62,13 +62,13 @@ public:
* Compares two XPath results. Returns -1 if val1 < val2,
* 1 if val1 > val2 and 0 if val1 == val2.
*/
virtual int compareValues(TxObject* val1, TxObject* val2) = 0;
virtual int compareValues(txObject* val1, txObject* val2) = 0;
/*
* Create a sortable value.
*/
virtual nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext,
TxObject *&aResult) = 0;
txObject *&aResult) = 0;
};
/*
@ -80,9 +80,9 @@ public:
txResultStringComparator(bool aAscending, bool aUpperFirst,
const nsAFlatString& aLanguage);
int compareValues(TxObject* aVal1, TxObject* aVal2);
int compareValues(txObject* aVal1, txObject* aVal2);
nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext,
TxObject *&aResult);
txObject *&aResult);
private:
nsCOMPtr<nsICollation> mCollation;
nsresult init(const nsAFlatString& aLanguage);
@ -92,7 +92,7 @@ private:
PRUint32* aLength);
int mSorting;
class StringValue : public TxObject
class StringValue : public txObject
{
public:
StringValue();
@ -112,14 +112,14 @@ class txResultNumberComparator : public txXPathResultComparator
public:
txResultNumberComparator(bool aAscending);
int compareValues(TxObject* aVal1, TxObject* aVal2);
int compareValues(txObject* aVal1, txObject* aVal2);
nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext,
TxObject *&aResult);
txObject *&aResult);
private:
int mAscending;
class NumberValue : public TxObject
class NumberValue : public txObject
{
public:
double mVal;

View File

@ -122,9 +122,9 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
double value = result->numberValue();
if (Double::isInfinite(value) || Double::isNaN(value) ||
if (txDouble::isInfinite(value) || txDouble::isNaN(value) ||
value < 0.5) {
Double::toString(value, aValueString);
txDouble::toString(value, aValueString);
return NS_OK;
}
@ -318,7 +318,7 @@ txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
rv = aGroupSize->evaluateToString(aContext, sizeStr);
NS_ENSURE_SUCCESS(rv, rv);
double size = Double::toDouble(sizeStr);
double size = txDouble::toDouble(sizeStr);
groupSize = (PRInt32)size;
if ((double)groupSize != size) {
groupSize = 0;

View File

@ -54,7 +54,7 @@
double txUnionPattern::getDefaultPriority()
{
NS_ERROR("Don't call getDefaultPriority on txUnionPattern");
return Double::NaN;
return txDouble::NaN;
}
/*

View File

@ -73,6 +73,35 @@ DoomCachedStatements(const nsACString& aQuery,
return PL_DHASH_REMOVE;
}
// This runnable doesn't actually do anything beyond "prime the pump" and get
// transactions in the right order on the transaction thread pool.
class StartTransactionRunnable : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_IMETHOD Run()
{
// NOP
return NS_OK;
}
};
// Could really use those NS_REFCOUNTING_HAHA_YEAH_RIGHT macros here.
NS_IMETHODIMP_(nsrefcnt) StartTransactionRunnable::AddRef()
{
return 2;
}
NS_IMETHODIMP_(nsrefcnt) StartTransactionRunnable::Release()
{
return 1;
}
NS_IMPL_QUERY_INTERFACE1(StartTransactionRunnable, nsIRunnable)
StartTransactionRunnable gStartTransactionRunnable;
} // anonymous namespace
// static
@ -121,6 +150,11 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
transaction->mCreating = true;
}
if (aMode != nsIIDBTransaction::VERSION_CHANGE) {
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
}
return transaction.forget();
}

View File

@ -47,8 +47,7 @@
#include "nsServiceManagerUtils.h"
#include "nsXPCOMCIDInternal.h"
using mozilla::MutexAutoLock;
using mozilla::MutexAutoUnlock;
using mozilla::MonitorAutoLock;
USING_INDEXEDDB_NAMESPACE
@ -604,8 +603,7 @@ TransactionThreadPool::MaybeFireCallback(PRUint32 aCallbackIndex)
TransactionThreadPool::
TransactionQueue::TransactionQueue(IDBTransaction* aTransaction,
nsIRunnable* aRunnable)
: mMutex("TransactionQueue::mMutex"),
mCondVar(mMutex, "TransactionQueue::mCondVar"),
: mMonitor("TransactionQueue::mMonitor"),
mTransaction(aTransaction),
mShouldFinish(false)
{
@ -617,29 +615,26 @@ TransactionQueue::TransactionQueue(IDBTransaction* aTransaction,
void
TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable)
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
NS_ASSERTION(!mShouldFinish, "Dispatch called after Finish!");
if (!mQueue.AppendElement(aRunnable)) {
MutexAutoUnlock unlock(mMutex);
NS_RUNTIMEABORT("Out of memory!");
}
mQueue.AppendElement(aRunnable);
mCondVar.Notify();
mMonitor.Notify();
}
void
TransactionThreadPool::TransactionQueue::Finish(nsIRunnable* aFinishRunnable)
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
NS_ASSERTION(!mShouldFinish, "Finish called more than once!");
mShouldFinish = true;
mFinishRunnable = aFinishRunnable;
mCondVar.Notify();
mMonitor.Notify();
}
NS_IMPL_THREADSAFE_ISUPPORTS1(TransactionThreadPool::TransactionQueue,
@ -656,9 +651,9 @@ TransactionThreadPool::TransactionQueue::Run()
NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
{
MutexAutoLock lock(mMutex);
MonitorAutoLock lock(mMonitor);
while (!mShouldFinish && mQueue.IsEmpty()) {
if (NS_FAILED(mCondVar.Wait())) {
if (NS_FAILED(mMonitor.Wait())) {
NS_ERROR("Failed to wait!");
}
}

View File

@ -46,8 +46,7 @@
#include "nsIObserver.h"
#include "nsIRunnable.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
#include "mozilla/Monitor.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
@ -106,8 +105,7 @@ protected:
inline void Finish(nsIRunnable* aFinishRunnable);
private:
mozilla::Mutex mMutex;
mozilla::CondVar mCondVar;
mozilla::Monitor mMonitor;
IDBTransaction* mTransaction;
nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> mQueue;
nsCOMPtr<nsIRunnable> mFinishRunnable;

View File

@ -102,6 +102,7 @@ TEST_FILES = \
test_transaction_abort.html \
test_transaction_lifetimes.html \
test_transaction_lifetimes_nested.html \
test_transaction_ordering.html \
test_setVersion.html \
test_setVersion_abort.html \
test_setVersion_events.html \

View File

@ -0,0 +1,61 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = mozIndexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
request.onsuccess = continueToNextStep;
db.createObjectStore("foo");
yield;
let trans1 = db.transaction("foo", IDBTransaction.READ_WRITE);
let trans2 = db.transaction("foo", IDBTransaction.READ_WRITE);
let request1 = trans2.objectStore("foo").put("2", 42);
let request2 = trans1.objectStore("foo").put("1", 42);
request1.onerror = errorHandler;
request2.onerror = errorHandler;
trans1.oncomplete = grabEventAndContinueHandler;
trans2.oncomplete = grabEventAndContinueHandler;
yield;
yield;
let trans3 = db.transaction("foo", IDBTransaction.READ);
let request = trans3.objectStore("foo").get(42);
request.onsuccess = grabEventAndContinueHandler;
request.onerror = errorHandler;
let event = yield;
is(event.target.result, "2", "Transactions were ordered properly.");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -7,7 +7,7 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) =
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html # bug 629430
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html # bug 629430
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) skip-if(Android) == border-padding-3.html border-padding-3-ref.html # bug 629430
random-if(cocoaWidget||d2d) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html
random-if(cocoaWidget||d2d||/^Windows\x20NT\x205\.1/.test(http.oscpu)) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-1.html pluginproblemui-direction-1-ref.html # bug 567367
random-if(cocoaWidget) fails-if(!haveTestPlugin&&!Android) skip-if(!testPluginIsOOP()) == pluginproblemui-direction-2.html pluginproblemui-direction-2-ref.html
fails-if(!haveTestPlugin) == plugin-canvas-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) == plugin-transform-alpha-zindex.html div-alpha-zindex.html

View File

@ -203,7 +203,7 @@ WifiGeoPositionProvider.prototype = {
let accessToken = this.getAccessTokenForURL(providerUrlBase);
if (accessToken !== "")
providerUrl = providerUrl + "&access_token="+access_token;
providerUrl = providerUrl + "&access_token="+accessToken;
function sort(a, b) {
return b.signal - a.signal;

View File

@ -5155,6 +5155,7 @@ nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
// Init selection
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
// If the computed selection root isn't root content, we should set it
// as selection ancestor limit. However, if that is root element, it means

View File

@ -54,7 +54,9 @@ DIRS += test
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
ifeq ($(MOZ_BUILD_APP),mobile/xul)
DIRS += android
endif
endif
include $(topsrcdir)/config/rules.mk

View File

@ -18,10 +18,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-feature android:name="android.hardware.location" android:required="false"/>

527
gfx/2d/Blur.cpp Normal file
View File

@ -0,0 +1,527 @@
/* ***** 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 Mozilla gfx.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#include "mozilla/gfx/Blur.h"
#include <algorithm>
#include <math.h>
#include <string.h>
#include "CheckedInt.h"
#include "mozilla/Util.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace std;
namespace mozilla {
namespace gfx {
/**
* Box blur involves looking at one pixel, and setting its value to the average
* of its neighbouring pixels.
* @param aInput The input buffer.
* @param aOutput The output buffer.
* @param aLeftLobe The number of pixels to blend on the left.
* @param aRightLobe The number of pixels to blend on the right.
* @param aWidth The number of columns in the buffers.
* @param aRows The number of rows in the buffers.
* @param aSkipRect An area to skip blurring in.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurHorizontal(unsigned char* aInput,
unsigned char* aOutput,
int32_t aLeftLobe,
int32_t aRightLobe,
int32_t aWidth,
int32_t aRows,
const IntRect& aSkipRect)
{
MOZ_ASSERT(aWidth > 0);
int32_t boxSize = aLeftLobe + aRightLobe + 1;
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
for (int32_t y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
int32_t alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
for (int32_t x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
// Recalculate the neighbouring alpha values for
// our new point on the surface.
alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = x + i - aLeftLobe;
// See assertion above; if aWidth is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aWidth - 1);
alphaSum += aInput[aWidth * y + pos];
}
}
int32_t tmp = x - aLeftLobe;
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aWidth - 1);
aOutput[aWidth * y + x] = alphaSum / boxSize;
alphaSum += aInput[aWidth * y + next] -
aInput[aWidth * y + last];
}
}
}
/**
* Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
* left and right.
* XXX shouldn't we pass stride in separately here?
*/
static void
BoxBlurVertical(unsigned char* aInput,
unsigned char* aOutput,
int32_t aTopLobe,
int32_t aBottomLobe,
int32_t aWidth,
int32_t aRows,
const IntRect& aSkipRect)
{
MOZ_ASSERT(aRows > 0);
int32_t boxSize = aTopLobe + aBottomLobe + 1;
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
for (int32_t x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
int32_t alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
for (int32_t y = 0; y < aRows; y++) {
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
alphaSum = 0;
for (int32_t i = 0; i < boxSize; i++) {
int32_t pos = y + i - aTopLobe;
// See assertion above; if aRows is zero, then we would have no
// valid position to clamp to.
pos = max(pos, 0);
pos = min(pos, aRows - 1);
alphaSum += aInput[aWidth * pos + x];
}
}
int32_t tmp = y - aTopLobe;
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aRows - 1);
aOutput[aWidth * y + x] = alphaSum/boxSize;
alphaSum += aInput[aWidth * next + x] -
aInput[aWidth * last + x];
}
}
}
static void ComputeLobes(int32_t aRadius, int32_t aLobes[3][2])
{
int32_t major, minor, final;
/* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
* some notes about approximating the Gaussian blur with box-blurs.
* The comments below are in the terminology of that page.
*/
int32_t z = aRadius / 3;
switch (aRadius % 3) {
case 0:
// aRadius = z*3; choose d = 2*z + 1
major = minor = final = z;
break;
case 1:
// aRadius = z*3 + 1
// This is a tricky case since there is no value of d which will
// yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
// for some integer k, then the radius will be 3*k. If d is even,
// i.e. d=2*k, then the radius will be 3*k - 1.
// So we have to choose values that don't match the standard
// algorithm.
major = z + 1;
minor = final = z;
break;
case 2:
// aRadius = z*3 + 2; choose d = 2*z + 2
major = final = z + 1;
minor = z;
break;
default:
// Mathematical impossibility!
MOZ_ASSERT(false);
major = minor = final = 0;
}
MOZ_ASSERT(major + minor + final == aRadius);
aLobes[0][0] = major;
aLobes[0][1] = minor;
aLobes[1][0] = minor;
aLobes[1][1] = major;
aLobes[2][0] = final;
aLobes[2][1] = final;
}
static void
SpreadHorizontal(unsigned char* aInput,
unsigned char* aOutput,
int32_t aRadius,
int32_t aWidth,
int32_t aRows,
int32_t aStride,
const IntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride * aRows);
return;
}
bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
aWidth <= aSkipRect.XMost();
for (int32_t y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
// rect covers the whole surface in this row, we can avoid
// this row entirely (and any others along the skip rect).
bool inSkipRectY = y >= aSkipRect.y &&
y < aSkipRect.YMost();
if (inSkipRectY && skipRectCoversWholeRow) {
y = aSkipRect.YMost() - 1;
continue;
}
for (int32_t x = 0; x < aWidth; x++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectY && x >= aSkipRect.x &&
x < aSkipRect.XMost()) {
x = aSkipRect.XMost();
if (x >= aWidth)
break;
}
int32_t sMin = max(x - aRadius, 0);
int32_t sMax = min(x + aRadius, aWidth - 1);
int32_t v = 0;
for (int32_t s = sMin; s <= sMax; ++s) {
v = max<int32_t>(v, aInput[aStride * y + s]);
}
aOutput[aStride * y + x] = v;
}
}
}
static void
SpreadVertical(unsigned char* aInput,
unsigned char* aOutput,
int32_t aRadius,
int32_t aWidth,
int32_t aRows,
int32_t aStride,
const IntRect& aSkipRect)
{
if (aRadius == 0) {
memcpy(aOutput, aInput, aStride * aRows);
return;
}
bool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
aRows <= aSkipRect.YMost();
for (int32_t x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
x < aSkipRect.XMost();
if (inSkipRectX && skipRectCoversWholeColumn) {
x = aSkipRect.XMost() - 1;
continue;
}
for (int32_t y = 0; y < aRows; y++) {
// Check whether we are within the skip rect. If so, go
// to the next point outside the skip rect.
if (inSkipRectX && y >= aSkipRect.y &&
y < aSkipRect.YMost()) {
y = aSkipRect.YMost();
if (y >= aRows)
break;
}
int32_t sMin = max(y - aRadius, 0);
int32_t sMax = min(y + aRadius, aRows - 1);
int32_t v = 0;
for (int32_t s = sMin; s <= sMax; ++s) {
v = max<int32_t>(v, aInput[aStride * s + x]);
}
aOutput[aStride * y + x] = v;
}
}
}
static CheckedInt<int32_t>
RoundUpToMultipleOf4(int32_t aVal)
{
CheckedInt<int32_t> val(aVal);
val += 3;
val /= 4;
val *= 4;
return val;
}
AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
const Rect* aSkipRect)
: mSpreadRadius(aSpreadRadius),
mBlurRadius(aBlurRadius),
mData(NULL)
{
Rect rect(aRect);
rect.Inflate(Size(aBlurRadius + aSpreadRadius));
rect.RoundOut();
if (aDirtyRect) {
// If we get passed a dirty rect from layout, we can minimize the
// shadow size and make painting faster.
mHasDirtyRect = true;
mDirtyRect = *aDirtyRect;
Rect requiredBlurArea = mDirtyRect.Intersect(rect);
requiredBlurArea.Inflate(Size(aBlurRadius + aSpreadRadius));
rect = requiredBlurArea.Intersect(rect);
} else {
mHasDirtyRect = false;
}
if (rect.IsEmpty()) {
return;
}
if (aSkipRect) {
// If we get passed a skip rect, we can lower the amount of
// blurring/spreading we need to do. We convert it to IntRect to avoid
// expensive int<->float conversions if we were to use Rect instead.
Rect skipRect = *aSkipRect;
skipRect.RoundIn();
skipRect.Deflate(Size(aBlurRadius + aSpreadRadius));
mSkipRect = IntRect(skipRect.x, skipRect.y, skipRect.width, skipRect.height);
IntRect shadowIntRect(rect.x, rect.y, rect.width, rect.height);
mSkipRect.IntersectRect(mSkipRect, shadowIntRect);
if (mSkipRect.IsEqualInterior(shadowIntRect))
return;
mSkipRect -= shadowIntRect.TopLeft();
} else {
mSkipRect = IntRect(0, 0, 0, 0);
}
mRect = IntRect(rect.x, rect.y, rect.width, rect.height);
CheckedInt<int32_t> stride = RoundUpToMultipleOf4(mRect.width);
if (stride.valid()) {
mStride = stride.value();
CheckedInt<int32_t> size = CheckedInt<int32_t>(mStride) * mRect.height *
sizeof(unsigned char);
if (size.valid()) {
mData = static_cast<unsigned char*>(malloc(size.value()));
memset(mData, 0, size.value());
}
}
}
AlphaBoxBlur::~AlphaBoxBlur()
{
free(mData);
}
unsigned char*
AlphaBoxBlur::GetData()
{
return mData;
}
IntSize
AlphaBoxBlur::GetSize()
{
IntSize size(mRect.width, mRect.height);
return size;
}
int32_t
AlphaBoxBlur::GetStride()
{
return mStride;
}
IntRect
AlphaBoxBlur::GetRect()
{
return mRect;
}
Rect*
AlphaBoxBlur::GetDirtyRect()
{
if (mHasDirtyRect) {
return &mDirtyRect;
}
return NULL;
}
void
AlphaBoxBlur::Blur()
{
if (!mData) {
return;
}
// no need to do all this if not blurring or spreading
if (mBlurRadius != IntSize(0,0) || mSpreadRadius != IntSize(0,0)) {
int32_t stride = GetStride();
// No need to use CheckedInt here - we have validated it in the constructor.
size_t szB = stride * GetSize().height * sizeof(unsigned char);
unsigned char* tmpData = static_cast<unsigned char*>(malloc(szB));
if (!tmpData)
return; // OOM
memset(tmpData, 0, szB);
if (mSpreadRadius.width > 0 || mSpreadRadius.height > 0) {
SpreadHorizontal(mData, tmpData, mSpreadRadius.width, GetSize().width, GetSize().height, stride, mSkipRect);
SpreadVertical(tmpData, mData, mSpreadRadius.height, GetSize().width, GetSize().height, stride, mSkipRect);
}
if (mBlurRadius.width > 0) {
int32_t lobes[3][2];
ComputeLobes(mBlurRadius.width, lobes);
BoxBlurHorizontal(mData, tmpData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
BoxBlurHorizontal(tmpData, mData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
BoxBlurHorizontal(mData, tmpData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
} else {
memcpy(tmpData, mData, stride * GetSize().height);
}
if (mBlurRadius.height > 0) {
int32_t lobes[3][2];
ComputeLobes(mBlurRadius.height, lobes);
BoxBlurVertical(tmpData, mData, lobes[0][0], lobes[0][1], stride, GetSize().height, mSkipRect);
BoxBlurVertical(mData, tmpData, lobes[1][0], lobes[1][1], stride, GetSize().height, mSkipRect);
BoxBlurVertical(tmpData, mData, lobes[2][0], lobes[2][1], stride, GetSize().height, mSkipRect);
} else {
memcpy(mData, tmpData, stride * GetSize().height);
}
free(tmpData);
}
}
/**
* Compute the box blur size (which we're calling the blur radius) from
* the standard deviation.
*
* Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
* approximating a Gaussian using box blurs. This yields quite a good
* approximation for a Gaussian. Then we multiply this by 1.5 since our
* code wants the radius of the entire triple-box-blur kernel instead of
* the diameter of an individual box blur. For more details, see:
* http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
* https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
*/
static const Float GAUSSIAN_SCALE_FACTOR = (3 * sqrt(2 * M_PI) / 4) * 1.5;
IntSize
AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
{
IntSize size(static_cast<int32_t>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
static_cast<int32_t>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
return size;
}
}
}

185
gfx/2d/Blur.h Normal file
View File

@ -0,0 +1,185 @@
/* ***** 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 Mozilla gfx.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#ifndef MOZILLA_GFX_BLUR_H_
#define MOZILLA_GFX_BLUR_H_
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
namespace gfx {
/**
* Implementation of a triple box blur approximation of a Gaussian blur.
*
* A Gaussian blur is good for blurring because, when done independently
* in the horizontal and vertical directions, it matches the result that
* would be obtained using a different (rotated) set of axes. A triple
* box blur is a very close approximation of a Gaussian.
*
* Creates an 8-bit alpha channel context for callers to draw in,
* spreads the contents of that context, and blurs the contents.
*
* A spread N makes each output pixel the maximum value of all source
* pixels within a square of side length 2N+1 centered on the output pixel.
*
* A temporary surface is created in the Init function. The caller then draws
* any desired content onto the context acquired through GetContext, and lastly
* calls Paint to apply the blurred content as an alpha mask.
*/
class AlphaBoxBlur
{
public:
/** Constructs a box blur and initializes the backing surface.
*
* @param aRect The coordinates of the surface to create in device units.
*
* @param aBlurRadius The blur radius in pixels. This is the radius of the
* entire (triple) kernel function. Each individual box blur has radius
* approximately 1/3 this value, or diameter approximately 2/3 this value.
* This parameter should nearly always be computed using CalculateBlurRadius,
* below.
*
* @param aDirtyRect A pointer to a dirty rect, measured in device units, if
* available. This will be used for optimizing the blur operation. It is
* safe to pass NULL here.
*
* @param aSkipRect A pointer to a rect, measured in device units, that
* represents an area where blurring is unnecessary and shouldn't be done for
* speed reasons. It is safe to pass NULL here.
*/
AlphaBoxBlur(const Rect& aRect,
const IntSize& aSpreadRadius,
const IntSize& aBlurRadius,
const Rect* aDirtyRect,
const Rect* aSkipRect);
~AlphaBoxBlur();
/**
* Return the pointer to memory allocated by the constructor for the 8-bit
* alpha surface you need to be blurred. After you draw to this surface, call
* Blur(), below, to have its contents blurred.
*/
unsigned char* GetData();
/**
* Return the size, in pixels, of the 8-bit alpha surface backed by the
* pointer returned by GetData().
*/
IntSize GetSize();
/**
* Return the stride, in bytes, of the 8-bit alpha surface backed by the
* pointer returned by GetData().
*/
int32_t GetStride();
/**
* Returns the device-space rectangle the 8-bit alpha surface covers.
*/
IntRect GetRect();
/**
* Return a pointer to a dirty rect, as passed in to the constructor, or NULL
* if none was passed in.
*/
Rect* GetDirtyRect();
/**
* Perform the blur in-place on the surface backed by the pointer returned by
* GetData().
*/
void Blur();
/**
* Calculates a blur radius that, when used with box blur, approximates a
* Gaussian blur with the given standard deviation. The result of this
* function should be used as the aBlurRadius parameter to AlphaBoxBlur's
* constructor, above.
*/
static IntSize CalculateBlurRadius(const Point& aStandardDeviation);
private:
/**
* A rect indicating the area where blurring is unnecessary, and the blur
* algorithm should skip over it.
*/
IntRect mSkipRect;
/**
* The device-space rectangle the the backing 8-bit alpha surface covers.
*/
IntRect mRect;
/**
* A copy of the dirty rect passed to the constructor. This will only be valid if
* mHasDirtyRect is true.
*/
Rect mDirtyRect;
/**
* The spread radius, in pixels.
*/
IntSize mSpreadRadius;
/**
* The blur radius, in pixels.
*/
IntSize mBlurRadius;
/**
* A pointer to the backing 8-bit alpha surface.
*/
unsigned char* mData;
/**
* The stride of the data contained in mData.
*/
int32_t mStride;
/**
* Whether mDirtyRect contains valid data.
*/
bool mHasDirtyRect;
};
}
}
#endif /* MOZILLA_GFX_BLUR_H_ */

View File

@ -137,36 +137,6 @@ GfxOpToSkiaOp(CompositionOp op)
return SkXfermode::kSrcOver_Mode;
}
SkPaint::Cap
CapStyleToSkiaCap(CapStyle aCap)
{
switch (aCap)
{
case CAP_BUTT:
return SkPaint::kButt_Cap;
case CAP_ROUND:
return SkPaint::kRound_Cap;
case CAP_SQUARE:
return SkPaint::kSquare_Cap;
}
return SkPaint::kDefault_Cap;
}
SkPaint::Join
JoinStyleToSkiaJoin(JoinStyle aJoin)
{
switch (aJoin)
{
case JOIN_BEVEL:
return SkPaint::kBevel_Join;
case JOIN_ROUND:
return SkPaint::kRound_Join;
case JOIN_MITER:
case JOIN_MITER_OR_BEVEL:
return SkPaint::kMiter_Join;
}
return SkPaint::kDefault_Join;
}
SkRect
RectToSkRect(const Rect& aRect)
@ -201,7 +171,14 @@ DrawTargetSkia::DrawTargetSkia()
DrawTargetSkia::~DrawTargetSkia()
{
MarkChanged();
if (mSnapshots.size()) {
for (std::vector<SourceSurfaceSkia*>::iterator iter = mSnapshots.begin();
iter != mSnapshots.end(); iter++) {
(*iter)->DrawTargetDestroyed();
}
// All snapshots will now have copied data.
mSnapshots.clear();
}
}
TemporaryRef<SourceSurface>
@ -280,6 +257,7 @@ struct AutoPaintSetup {
mPaint.setAlpha(aOptions.mAlpha*255.0);
mAlpha = aOptions.mAlpha;
}
mPaint.setFilterBitmap(true);
}
void SetPattern(const Pattern& aPattern)
@ -336,27 +314,6 @@ struct AutoPaintSetup {
}
}
void SetStroke(const StrokeOptions &aOptions)
{
mPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth));
mPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit));
mPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap));
mPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin));
if (aOptions.mDashLength) {
std::vector<SkScalar> pattern;
pattern.resize(aOptions.mDashLength);
for (uint32_t i = 0; i < aOptions.mDashLength; i++) {
pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i]);
}
SkDashPathEffect* dash = new SkDashPathEffect(&pattern.front(),
aOptions.mDashLength,
SkFloatToScalar(aOptions.mDashOffset));
SkSafeUnref(mPaint.setPathEffect(dash));
}
mPaint.setStyle(SkPaint::kStroke_Style);
}
// TODO: Maybe add an operator overload to access this easier?
SkPaint mPaint;
bool mNeedsRestore;
@ -386,7 +343,6 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
MarkChanged();
NS_ASSERTION(aSurfOptions.mFilter == FILTER_LINEAR, "Only linear filtering supported currently!");
SkRect destRect = RectToSkRect(aDest);
SkRect sourceRect = RectToSkRect(aSource);
@ -399,6 +355,9 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
SkShader *shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
shader->setLocalMatrix(matrix);
SkSafeUnref(paint.mPaint.setShader(shader));
if (aSurfOptions.mFilter != FILTER_LINEAR) {
paint.mPaint.setFilterBitmap(false);
}
mCanvas->drawRect(destRect, paint.mPaint);
}
@ -492,7 +451,9 @@ DrawTargetSkia::Stroke(const Path *aPath,
AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
paint.SetStroke(aStrokeOptions);
if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
return;
}
mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint);
}
@ -505,7 +466,9 @@ DrawTargetSkia::StrokeRect(const Rect &aRect,
{
MarkChanged();
AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
paint.SetStroke(aStrokeOptions);
if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
return;
}
mCanvas->drawRect(RectToSkRect(aRect), paint.mPaint);
}
@ -519,7 +482,9 @@ DrawTargetSkia::StrokeLine(const Point &aStart,
{
MarkChanged();
AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
paint.SetStroke(aStrokeOptions);
if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
return;
}
mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y),
SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y),

View File

@ -46,6 +46,9 @@
#ifdef XP_MACOSX
#include "ScaledFontMac.h"
#endif
#ifdef WIN32
#include "ScaledFontWin.h"
#endif
#include "ScaledFontSkia.h"
#endif
@ -124,6 +127,12 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
{
return new ScaledFontMac(static_cast<CGFontRef>(aNativeFont.mFont), aSize);
}
#endif
#ifdef WIN32
case NATIVE_FONT_GDI_FONT_FACE:
{
return new ScaledFontWin(static_cast<gfxGDIFont*>(aNativeFont.mFont), aSize);
}
#endif
case NATIVE_FONT_SKIA_FONT_FACE:
{

View File

@ -40,6 +40,7 @@
#include "2D.h"
#include "skia/SkCanvas.h"
#include "skia/SkDashPathEffect.h"
namespace mozilla {
namespace gfx {
@ -72,6 +73,65 @@ GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval)
0, 0, SK_Scalar1);
}
static inline SkPaint::Cap
CapStyleToSkiaCap(CapStyle aCap)
{
switch (aCap)
{
case CAP_BUTT:
return SkPaint::kButt_Cap;
case CAP_ROUND:
return SkPaint::kRound_Cap;
case CAP_SQUARE:
return SkPaint::kSquare_Cap;
}
return SkPaint::kDefault_Cap;
}
static inline SkPaint::Join
JoinStyleToSkiaJoin(JoinStyle aJoin)
{
switch (aJoin)
{
case JOIN_BEVEL:
return SkPaint::kBevel_Join;
case JOIN_ROUND:
return SkPaint::kRound_Join;
case JOIN_MITER:
case JOIN_MITER_OR_BEVEL:
return SkPaint::kMiter_Join;
}
return SkPaint::kDefault_Join;
}
static inline bool
StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions)
{
// Skia rendewrs 0 width strokes with a width of 1 (and in black),
// so we should just skip the draw call entirely.
if (!aOptions.mLineWidth) {
return false;
}
aPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth));
aPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit));
aPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap));
aPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin));
if (aOptions.mDashLength > 1) {
std::vector<SkScalar> pattern;
pattern.resize(aOptions.mDashLength);
for (uint32_t i = 0; i < aOptions.mDashLength; i++) {
pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i]);
}
SkDashPathEffect* dash = new SkDashPathEffect(&pattern.front(),
aOptions.mDashLength,
SkFloatToScalar(aOptions.mDashOffset));
SkSafeUnref(aPaint.setPathEffect(dash));
}
aPaint.setStyle(SkPaint::kStroke_Style);
return true;
}
}
}

View File

@ -56,6 +56,7 @@ EXPORTS_mozilla/gfx = \
BaseMargin.h \
BaseRect.h \
BaseSize.h \
Blur.h \
PathHelpers.h \
Point.h \
Matrix.h \
@ -68,6 +69,7 @@ CPPSRCS = \
Matrix.cpp \
DrawTargetCairo.cpp \
SourceSurfaceCairo.cpp \
Blur.cpp \
$(NULL)
@ -107,9 +109,13 @@ CPPSRCS += \
SourceSurfaceD2DTarget.cpp \
PathD2D.cpp \
ScaledFontDWrite.cpp \
$(NULL)
DEFINES += -DWIN32
SourceSurfaceSkia.cpp \
DrawTargetSkia.cpp \
PathSkia.cpp \
ScaledFontSkia.cpp \
ScaledFontWin.cpp \
$(NULL)
DEFINES += -DWIN32 -DUSE_SKIA
endif
#ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)

View File

@ -196,8 +196,14 @@ Rect
PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const
{
NS_ASSERTION(false, "GetStrokedBounds not supported yet!");
return Rect(0, 0, 0, 0);
SkPaint paint;
StrokeOptionsToPaint(paint, aStrokeOptions);
SkPath result;
paint.getFillPath(mPath, &result);
Rect bounds = SkRectToRect(result.getBounds());
return aTransform.TransformBounds(bounds);
}
}

53
gfx/2d/ScaledFontWin.cpp Normal file
View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** 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 Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Castelluccio <mar.castelluccio@studenti.unina.it>
*
* 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 ***** */
#include "ScaledFontWin.h"
#include "skia/SkTypeface_win.h"
namespace mozilla {
namespace gfx {
ScaledFontWin::ScaledFontWin(gfxGDIFont* aFont, Float aSize)
: ScaledFontSkia(aSize)
{
LOGFONT lf;
GetObject(aFont->GetHFONT(), sizeof(LOGFONT), &lf);
mTypeface = SkCreateTypefaceFromLOGFONT(lf);
}
}
}

61
gfx/2d/ScaledFontWin.h Normal file
View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** 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 Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Castelluccio <mar.castelluccio@studenti.unina.it>
*
* 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 ***** */
#ifndef MOZILLA_GFX_SCALEDFONTWIN_H_
#define MOZILLA_GFX_SCALEDFONTWIN_H_
#include "ScaledFontSkia.h"
#include "gfxGDIFont.h"
namespace mozilla {
namespace gfx {
class ScaledFontWin : public ScaledFontSkia
{
public:
ScaledFontWin(gfxGDIFont* aFont, Float aSize);
virtual FontType GetType() const { return FONT_GDI; }
private:
friend class DrawTargetSkia;
};
}
}
#endif /* MOZILLA_GFX_SCALEDFONTWIN_H_ */

View File

@ -129,6 +129,12 @@ SourceSurfaceSkia::DrawTargetWillChange()
}
}
void
SourceSurfaceSkia::DrawTargetDestroyed()
{
mDrawTarget = NULL;
}
void
SourceSurfaceSkia::MarkIndependent()
{
@ -138,6 +144,5 @@ SourceSurfaceSkia::MarkIndependent()
}
}
}
}

View File

@ -82,6 +82,7 @@ private:
friend class DrawTargetSkia;
void DrawTargetWillChange();
void DrawTargetDestroyed();
void MarkIndependent();
SkBitmap mBitmap;

View File

@ -43,7 +43,7 @@
namespace mozilla {
namespace gfx {
bool
static inline bool
IsOperatorBoundByMask(CompositionOp aOp) {
switch (aOp) {
case OP_IN:

View File

@ -91,6 +91,7 @@ enum BackendType
enum FontType
{
FONT_DWRITE,
FONT_GDI,
FONT_MAC,
FONT_SKIA
};
@ -103,6 +104,7 @@ enum NativeSurfaceType
enum NativeFontType
{
NATIVE_FONT_DWRITE_FONT_FACE,
NATIVE_FONT_GDI_FONT_FACE,
NATIVE_FONT_MAC_FONT_FACE,
NATIVE_FONT_SKIA_FONT_FACE
};

View File

@ -48,9 +48,9 @@ ifdef MOZ_TREE_CAIRO
DIRS = cairo
endif
DIRS += 2d ycbcr angle src qcms layers harfbuzz/src ots/src thebes ipc
DIRS += 2d ycbcr angle src qcms gl layers harfbuzz/src ots/src thebes ipc
ifeq (,$(filter-out cocoa android,$(MOZ_WIDGET_TOOLKIT)))
ifeq (,$(filter-out cocoa android windows,$(MOZ_WIDGET_TOOLKIT)))
DIRS += skia
endif

View File

@ -1,6 +1,6 @@
This is the ANGLE project, from http://code.google.com/p/angleproject/
Current revision: r809
Current revision: r885
== Applied local patches ==

View File

@ -1,5 +1,5 @@
# HG changeset patch
# Parent b5604c321da4e3b5d6b0a940d18022a827061579
# Parent d9b887da80f5bc18854fb3e5e43637c18d2a25ae
diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp
--- a/gfx/angle/src/libGLESv2/Texture.cpp
+++ b/gfx/angle/src/libGLESv2/Texture.cpp

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