mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge.
This commit is contained in:
commit
72137223d8
@ -380,7 +380,6 @@
|
||||
@BINPATH@/components/nsPrompter.js
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
@BINPATH@/components/SyncComponents.manifest
|
||||
@BINPATH@/components/FormNotifier.js
|
||||
@BINPATH@/components/Weave.js
|
||||
@BINPATH@/components/WeaveCrypto.manifest
|
||||
@BINPATH@/components/WeaveCrypto.js
|
||||
|
@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# cvsco-fast-update.pl cvs co ...
|
||||
#
|
||||
# This command parses a "cvs co ..." command and converts it to
|
||||
# fast-update.pl commands
|
||||
#
|
||||
use Getopt::Long;
|
||||
|
||||
my $filename = ".fast-update";
|
||||
my $start_time = time();
|
||||
|
||||
my $branch;
|
||||
my @modules;
|
||||
my @dirs;
|
||||
my $dirlocal = 0;
|
||||
|
||||
print "$0: (".join(')(',@ARGV).")\n";
|
||||
while (scalar(@ARGV)) {
|
||||
my $val = shift(@ARGV);
|
||||
if ( ($val eq '-A') || ($val eq 'co') || ($val eq 'cvs')
|
||||
|| ($val eq '-P') || ($val eq '-q')) {
|
||||
#print "ignore $val\n";
|
||||
next;
|
||||
}
|
||||
elsif (($val eq '-d') || ($val eq '-q') || ($val eq '-z')) {
|
||||
my $tmp = shift @ARGV;
|
||||
#print "ignore $val $tmp\n";
|
||||
next;
|
||||
}
|
||||
elsif ($val eq '-r') {
|
||||
$branch = shift @ARGV;
|
||||
#print "branch = $branch\n";
|
||||
next;
|
||||
}
|
||||
elsif ($val eq '-l') {
|
||||
$dirlocal = 1;
|
||||
#print "dirlocal = $dirlocal\n";
|
||||
next;
|
||||
}
|
||||
elsif ($val =~ /^-/) {
|
||||
print "*** unknown switch: $val\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
if ($val =~ /\//) {
|
||||
push @dirs, $val;
|
||||
#print "dir = $val\n";
|
||||
}
|
||||
else {
|
||||
push @modules, $val;
|
||||
#print "module = $val\n";
|
||||
}
|
||||
}
|
||||
|
||||
#print "dir = (".join(')(', @dirs)."), "
|
||||
# . "module = (".join(')(', @modules)."), "
|
||||
# . "branch = ($branch)\n";
|
||||
|
||||
if (!$branch) {
|
||||
$branch = 'HEAD';
|
||||
}
|
||||
|
||||
my $status = 0;
|
||||
foreach my $mod (@modules) {
|
||||
my $cmd = "config/fast-update.pl -r $branch -m $mod" . ($dirlocal ? " -l" : "");
|
||||
#print "system \"$cmd\"\n";
|
||||
$status |= system $cmd;
|
||||
}
|
||||
my $dirlist = join(' -d ', @dirs);
|
||||
my $cmd = "config/fast-update.pl -r $branch -d $dirlist -m all" . ($dirlocal ? " -l" : "");
|
||||
#print "system \"$cmd\"\n";
|
||||
$status |= system $cmd;
|
||||
|
||||
exit $status;
|
||||
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# ***** 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
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Stephen Lamm
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
sub usage {
|
||||
warn "usage: cvsco.pl <checkout_command>\n"
|
||||
." <checkout_command> is the entire cvs co command\n"
|
||||
." (e.g. cvs -q -z3 co SeaMonkeyAll).\n";
|
||||
}
|
||||
|
||||
usage(), die "Error: Not enough arguments\n" if $#ARGV < 0;
|
||||
usage(), die "Error: Wrong cwd. Must chdir to mozilla/..\n"
|
||||
unless -r 'mozilla/config/cvsco.pl';
|
||||
|
||||
$co_command = join ' ', @ARGV;
|
||||
|
||||
$logfile = 'cvslog.txt';
|
||||
$old_logfile = 'cvslog-old.txt';
|
||||
|
||||
sub dblprint {
|
||||
print LOG @_;
|
||||
print STDERR @_;
|
||||
}
|
||||
|
||||
if (-r $logfile) {
|
||||
rename $logfile, $old_logfile;
|
||||
print "rename $logfile, $old_logfile\n";
|
||||
}
|
||||
|
||||
open LOG, ">$logfile";
|
||||
open CVSCO, "$co_command|";
|
||||
|
||||
dblprint "\ncheckout start: ".scalar(localtime)."\n";
|
||||
dblprint "$co_command | tee cvslog.txt\n";
|
||||
|
||||
while (<CVSCO>) {
|
||||
dblprint $_;
|
||||
push @conflicts, $_ if /^C /;
|
||||
}
|
||||
|
||||
if (@conflicts) {
|
||||
print "Error: cvs conflicts during checkout:\n";
|
||||
die join('', @conflicts);
|
||||
}
|
||||
|
||||
close(CVSCO) or die "cvs error.\n";
|
||||
dblprint 'checkout finish: '.scalar(localtime)."\n";
|
||||
|
@ -1,312 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# fast-update.pl [-h hours] [-m module] [-r branch]
|
||||
#
|
||||
# This command, fast-update.pl, does a (fast) cvs update of the current
|
||||
# directory. It is fast because the cvs up command is only run on those
|
||||
# directories / sub-directories where changes have occurred since the
|
||||
# last fast-update.
|
||||
#
|
||||
# The last update time is stored in a ".fast-update" file in the current
|
||||
# directory. Thus one can choose to only fast-update a branch of the tree
|
||||
# and then fast-update the whole tree later.
|
||||
#
|
||||
# The first time this command is run in a directory the last cvs update
|
||||
# time is assumed to be the timestamp of the CVS/Entries file.
|
||||
#
|
||||
use Getopt::Long;
|
||||
|
||||
my $filename = ".fast-update";
|
||||
my $start_time = time();
|
||||
|
||||
my $branch;
|
||||
my $module="SeaMonkeyAll";
|
||||
my $maxdirs=5;
|
||||
my $rootdir = "";
|
||||
my $hours = 0;
|
||||
my @dirs = ();
|
||||
my $dirlocal = 0;
|
||||
|
||||
&GetOptions('d=s@' => \@dirs, 'h=s' => \$hours, 'm=s' => \$module, 'r=s' => \$branch, 'l' => \$dirlocal);
|
||||
|
||||
#print "dirs = (@dirs), hours = ($hours), module = ($module), branch = ($branch), dirlocal = ($dirlocal)\n";
|
||||
if (scalar(@dirs) > 0) {
|
||||
# put .fast-update in the first directory listed
|
||||
$filename = "$dirs[0]/$filename";
|
||||
$filename =~ s#mozilla/*##;
|
||||
}
|
||||
|
||||
if (!$hours) {
|
||||
$hours = get_hours_since_last_update();
|
||||
}
|
||||
if (!$hours) {
|
||||
$hours = 24;
|
||||
}
|
||||
|
||||
|
||||
# pull out the current directory
|
||||
# if there is no such file, this will all just fail, which is ok
|
||||
open REPOSITORY, "<CVS/Repository";
|
||||
$rootdir = <REPOSITORY>;
|
||||
$rootdir =~ tr/\r\n//d; # Remove newlines
|
||||
close REPOSITORY;
|
||||
|
||||
# try to guess the current branch by looking at all the
|
||||
# files in CVS/Entries
|
||||
if (!$branch) {
|
||||
my $foundbranch =0;
|
||||
|
||||
open ENTRIES, "<CVS/Entries";
|
||||
while (<ENTRIES>) {
|
||||
chop;
|
||||
@entry = split(/\//);
|
||||
my ($type, $file, $ver, $date, $unknown, $tag) = @entry;
|
||||
|
||||
# the tag usually starts with "T"
|
||||
$thisbranch = substr($tag, 1);
|
||||
|
||||
# look for more than one branch
|
||||
if ($type eq "") {
|
||||
|
||||
if ($foundbranch and ($lastbranch ne $thisbranch)) {
|
||||
die "Multiple branches in this directory, cannot determine branch\n";
|
||||
}
|
||||
$foundbranch = 1;
|
||||
$lastbranch = $thisbranch;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$branch = $lastbranch if ($foundbranch);
|
||||
|
||||
close ENTRIES;
|
||||
}
|
||||
|
||||
# check for a static Tag
|
||||
# (at least that is what I think this does)
|
||||
# (bonsai does not report changes when the Tag starts with 'N')
|
||||
# (I do not really understand all this)
|
||||
if ($branch) {
|
||||
open TAG, "<CVS/Tag";
|
||||
my $line = <TAG>;
|
||||
if ($line =~ /^N/) {
|
||||
print "static tag, ignore branch\n";
|
||||
$branch = '';
|
||||
}
|
||||
close TAG;
|
||||
}
|
||||
|
||||
|
||||
my $url = "http://bonsai.mozilla.org/cvsquery.cgi?module=${module}&branch=${branch}&branchtype=match&sortby=File&date=hours&hours=${hours}&cvsroot=%2Fcvsroot";
|
||||
|
||||
my $dir_string = "";
|
||||
if (scalar(@dirs) > 0) {
|
||||
$dir_string = join(' ', @dirs);
|
||||
my $esc_dir = escape($dir_string);
|
||||
$url .= "&dir=$esc_dir";
|
||||
}
|
||||
if ($dirlocal) {
|
||||
$url .= "&dirtype=local";
|
||||
}
|
||||
|
||||
print "Contacting bonsai for updates to ${module} ";
|
||||
print "on the ${branch} branch " if ($branch);
|
||||
print "in the last ${hours} hours ";
|
||||
print "within the $rootdir directory..\n" if ($rootdir);
|
||||
print "\n" unless ($rootdir);
|
||||
#print "url = $url\n";
|
||||
|
||||
# first try wget, then try lynx, then try curl
|
||||
|
||||
# this is my lame way of checking if a command succeeded AND getting
|
||||
# output from it. I'd love a better way. -alecf@netscape.com
|
||||
my $have_checkins = 0;
|
||||
open CHECKINS,"wget --quiet --output-document=- \"$url\"|" or
|
||||
die "Error opening wget: $!\n";
|
||||
|
||||
$header = <CHECKINS> and $have_checkins=1;
|
||||
|
||||
if (!$have_checkins) {
|
||||
|
||||
open CHECKINS, "lynx -source '$url'|" or die "Error opening lynx: $!\n";
|
||||
|
||||
$header = <CHECKINS> and $have_checkins = 1;
|
||||
}
|
||||
|
||||
if (!$have_checkins) {
|
||||
|
||||
open CHECKINS, "curl -s '$url'|" or die "Error opening curl $!\n";
|
||||
|
||||
$header = <CHECKINS> and $have_checkins = 1;
|
||||
}
|
||||
|
||||
$have_checkins || die "Couldn't get checkins\n";
|
||||
|
||||
open REALOUT, ">.fast-update.bonsai.html" || die "argh $!\n";
|
||||
print "Processing checkins...";
|
||||
while (<CHECKINS>) {
|
||||
print REALOUT $_;
|
||||
|
||||
if (/js_file_menu\((.*),\s*\'(.*)\'\s*,\s*(.*),\s*(.*),\s*(.*),\s*(.*)\)/) {
|
||||
my ($repos, $dir, $file, $rev, $branch, $event) =
|
||||
($1, $2, $3, $4, $5, $6);
|
||||
$dir =~ s/\/Attic$//;
|
||||
push @dirlist, $dir;
|
||||
}
|
||||
}
|
||||
|
||||
print "done.\n";
|
||||
close REALOUT;
|
||||
unlink '.fast-update.bonsai.html';
|
||||
|
||||
my $lastdir = "";
|
||||
my @uniquedirs;
|
||||
|
||||
foreach $dir (sort @dirlist) {
|
||||
next if ($lastdir eq $dir);
|
||||
|
||||
my $strippeddir = "";
|
||||
$lastdir = $dir;
|
||||
|
||||
# now strip out $rootdir
|
||||
if ($rootdir) {
|
||||
|
||||
# only deal with directories that start with $rootdir
|
||||
if (substr($dir, 0, (length $rootdir)) eq $rootdir) {
|
||||
|
||||
if ($dir eq $rootdir) {
|
||||
$strippeddir = ".";
|
||||
} else {
|
||||
$strippeddir = substr($dir,(length $rootdir) + 1 );
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
$strippeddir = $dir;
|
||||
}
|
||||
|
||||
if ($strippeddir) {
|
||||
push @uniquedirs, $strippeddir;
|
||||
}
|
||||
}
|
||||
|
||||
my $status = 0;
|
||||
if (scalar(@uniquedirs)) {
|
||||
print "Updating tree... (" . scalar(@uniquedirs) . " directories)\n";
|
||||
my $i=0;
|
||||
my $dirlist = "";
|
||||
foreach $dir (sort @uniquedirs) {
|
||||
if (!-d $dir) {
|
||||
cvs_up_parent($dir);
|
||||
}
|
||||
$dirlist .= "\"$dir\" ";
|
||||
$i++;
|
||||
if ($i == 5) {
|
||||
$status |= spawn("cvs -z3 -q -f up -l -d $dirlist\n");
|
||||
$dirlist = "";
|
||||
$i=0;
|
||||
}
|
||||
}
|
||||
if ($i) {
|
||||
$status |= spawn("cvs -z3 -q -f up -l -d $dirlist\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "No directories to update.\n";
|
||||
}
|
||||
|
||||
close CHECKINS;
|
||||
if ($status == 0) {
|
||||
set_last_update_time($filename, $start_time);
|
||||
print "successfully updated ";
|
||||
}
|
||||
else {
|
||||
print "error while updating ";
|
||||
}
|
||||
if ($module ne "all") {
|
||||
print "$module/";
|
||||
}
|
||||
if (scalar(@dirs) > 0) {
|
||||
print $dir_string;
|
||||
}
|
||||
print "\n";
|
||||
|
||||
exit $status;
|
||||
|
||||
sub cvs_up_parent {
|
||||
my ($dir) = @_;
|
||||
my $pdir = $dir;
|
||||
$pdir =~ s|/*[^/]*/*$||;
|
||||
#$pdir =~ s|/$||;
|
||||
#$pdir =~ s|[^/]*$||;
|
||||
#$pdir =~ s|/$||;
|
||||
if (!$pdir) {
|
||||
$pdir = '.';
|
||||
}
|
||||
if (!-d $pdir) {
|
||||
cvs_up_parent($pdir);
|
||||
}
|
||||
$status |= system "cvs -z3 -q -f up -d -l $pdir\n";
|
||||
}
|
||||
|
||||
sub get_hours_since_last_update {
|
||||
# get the last time this command was run
|
||||
my $last_time = get_last_update_time($filename);
|
||||
if (!defined($last_time)) {
|
||||
#
|
||||
# This must be the first use of fast-update.pl so use the timestamp
|
||||
# of a file that:
|
||||
# 1) is managed by cvs
|
||||
# 2) the user should not be tampering with
|
||||
# 3) that gets updated fairly frequently.
|
||||
#
|
||||
$last_time = (stat "CVS/Entries")[9];
|
||||
if (defined($last_time)) {
|
||||
$last_time -= 3600*24; # for safety go back a bit
|
||||
print "use fallback time of ".localtime($last_time)."\n";
|
||||
}
|
||||
}
|
||||
if(!defined($last_time)) {
|
||||
print "last_time not defined\n";
|
||||
}
|
||||
|
||||
# figure the hours (rounded up) since the last fast-update
|
||||
my $hours = int(($start_time - $last_time + 3600)/3600);
|
||||
print "last updated $hours hour(s) ago at ".localtime($last_time)."\n";
|
||||
return $hours;
|
||||
}
|
||||
|
||||
# returns time of last update if known
|
||||
sub get_last_update_time {
|
||||
my ($filename) = @_;
|
||||
if (!-r $filename) {
|
||||
return undef;
|
||||
}
|
||||
open FILE, "<$filename";
|
||||
my $line = <FILE>;
|
||||
if (!defined(line)) {
|
||||
return undef;
|
||||
}
|
||||
# print "line = $line";
|
||||
$line =~ /^(\d+):/;
|
||||
return $1;
|
||||
}
|
||||
|
||||
sub set_last_update_time {
|
||||
my ($filename, $time) = @_;
|
||||
my $time_str = localtime($time);
|
||||
open FILE, ">$filename";
|
||||
print FILE "$time: last fast-update.pl at ".localtime($time)."\n";
|
||||
}
|
||||
|
||||
# URL-encode data
|
||||
sub escape {
|
||||
my ($toencode) = @_;
|
||||
$toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
|
||||
return $toencode;
|
||||
}
|
||||
|
||||
sub spawn {
|
||||
my ($procname) = @_;
|
||||
return system "$procname";
|
||||
}
|
@ -113,7 +113,6 @@ _TEST_FILES = \
|
||||
test_load_candidates.html \
|
||||
test_load_source.html \
|
||||
test_media_selection.html \
|
||||
test_mixed_principals.html \
|
||||
test_mozLoadFrom.html \
|
||||
test_networkState.html \
|
||||
test_new_audio.html \
|
||||
@ -147,6 +146,8 @@ _TEST_FILES = \
|
||||
# test_videoDocumentTitle.html
|
||||
# Bug 493692:
|
||||
# test_preload_suspend.html
|
||||
# Bug 567954 and Bug 574586:
|
||||
# test_mixed_principals.html
|
||||
# Disabled since we don't play Wave files standalone, for now
|
||||
# test_audioDocumentTitle.html
|
||||
|
||||
|
@ -116,8 +116,10 @@ class GeckoAppShell
|
||||
if (!f.exists())
|
||||
f.mkdirs();
|
||||
GeckoAppShell.putenv("TMPDIR=" + f.getPath());
|
||||
|
||||
|
||||
|
||||
f = Environment.getDownloadCacheDirectory();
|
||||
GeckoAppShell.putenv("EXTERNAL_STORAGE" + f.getPath());
|
||||
|
||||
// NSPR
|
||||
System.loadLibrary("nspr4");
|
||||
System.loadLibrary("plc4");
|
||||
|
@ -61,6 +61,7 @@ typedef struct _cairo_os2_surface
|
||||
|
||||
/* General flags: */
|
||||
cairo_bool_t blit_as_changes;
|
||||
cairo_bool_t use_24bpp;
|
||||
} cairo_os2_surface_t;
|
||||
|
||||
#endif /* CAIRO_OS2_PRIVATE_H */
|
||||
|
@ -33,6 +33,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Peter Weilbacher <mozilla@Weilbacher.org>
|
||||
* Rich Walsh <dragtext@e-vertise.com>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
@ -66,7 +67,7 @@
|
||||
/* Initialization counter: */
|
||||
static int cairo_os2_initialization_count = 0;
|
||||
|
||||
static void inline
|
||||
static inline void
|
||||
DisableFPUException (void)
|
||||
{
|
||||
unsigned short usCW;
|
||||
@ -169,43 +170,35 @@ cairo_os2_fini (void)
|
||||
*/
|
||||
void *_buffer_alloc (size_t a, size_t b, const unsigned int size)
|
||||
{
|
||||
/* check length like in the _cairo_malloc_abc macro, but we can leave
|
||||
* away the unsigned casts as our arguments are unsigned already
|
||||
*/
|
||||
size_t nbytes = b &&
|
||||
a >= INT32_MAX / b ? 0 : size &&
|
||||
a*b >= INT32_MAX / size ? 0 : a * b * size;
|
||||
void *buffer = NULL;
|
||||
#ifdef OS2_USE_PLATFORM_ALLOC
|
||||
APIRET rc = NO_ERROR;
|
||||
size_t nbytes;
|
||||
void *buffer = NULL;
|
||||
|
||||
rc = DosAllocMem ((PPVOID)&buffer,
|
||||
nbytes,
|
||||
#ifdef OS2_HIGH_MEMORY /* only if compiled with high-memory support, */
|
||||
OBJ_ANY | /* we can allocate anywhere! */
|
||||
#endif
|
||||
PAG_READ | PAG_WRITE | PAG_COMMIT);
|
||||
if (rc != NO_ERROR) {
|
||||
/* should there for some reason be another error, let's return
|
||||
* a null surface and free the buffer again, because that's
|
||||
* how a malloc failure would look like
|
||||
*/
|
||||
if (rc != ERROR_NOT_ENOUGH_MEMORY && buffer) {
|
||||
DosFreeMem (buffer);
|
||||
}
|
||||
if (!a || !b || !size ||
|
||||
a >= INT32_MAX / b || a*b >= INT32_MAX / size) {
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
buffer = malloc (nbytes);
|
||||
nbytes = a * b * size;
|
||||
|
||||
#ifdef OS2_USE_PLATFORM_ALLOC
|
||||
/* Using OBJ_ANY on a machine that isn't configured for hi-mem
|
||||
* will cause ERROR_INVALID_PARAMETER. If this occurs, or this
|
||||
* build doesn't have hi-mem enabled, fall back to using lo-mem.
|
||||
*/
|
||||
#ifdef OS2_HIGH_MEMORY
|
||||
if (!DosAllocMem (&buffer, nbytes,
|
||||
OBJ_ANY | PAG_READ | PAG_WRITE | PAG_COMMIT))
|
||||
return buffer;
|
||||
#endif
|
||||
if (DosAllocMem (&buffer, nbytes,
|
||||
PAG_READ | PAG_WRITE | PAG_COMMIT))
|
||||
return NULL;
|
||||
#else
|
||||
/* Clear the malloc'd buffer the way DosAllocMem() does. */
|
||||
buffer = malloc (nbytes);
|
||||
if (buffer) {
|
||||
memset (buffer, 0, nbytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This does not seem to be needed, malloc'd space is usually
|
||||
* already zero'd out!
|
||||
*/
|
||||
/*
|
||||
* memset (buffer, 0x00, nbytes);
|
||||
*/
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -303,46 +296,38 @@ _cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
|
||||
PRECTL prcl_begin_paint_rect)
|
||||
{
|
||||
POINTL aptlPoints[4];
|
||||
LONG lOldYInversion, rc = GPI_OK;
|
||||
LONG lOldYInversion;
|
||||
LONG rc = GPI_OK;
|
||||
|
||||
/* Enable Y Inversion for the HPS, so the
|
||||
* GpiDrawBits will work with upside-top image, not with upside-down image!
|
||||
/* Check the limits (may not be necessary) */
|
||||
if (prcl_begin_paint_rect->xLeft < 0)
|
||||
prcl_begin_paint_rect->xLeft = 0;
|
||||
if (prcl_begin_paint_rect->yBottom < 0)
|
||||
prcl_begin_paint_rect->yBottom = 0;
|
||||
if (prcl_begin_paint_rect->xRight > (LONG) surface->bitmap_info.cx)
|
||||
prcl_begin_paint_rect->xRight = (LONG) surface->bitmap_info.cx;
|
||||
if (prcl_begin_paint_rect->yTop > (LONG) surface->bitmap_info.cy)
|
||||
prcl_begin_paint_rect->yTop = (LONG) surface->bitmap_info.cy;
|
||||
|
||||
/* Exit if the rectangle is empty */
|
||||
if (prcl_begin_paint_rect->xLeft >= prcl_begin_paint_rect->xRight ||
|
||||
prcl_begin_paint_rect->yBottom >= prcl_begin_paint_rect->yTop)
|
||||
return;
|
||||
|
||||
/* Set the Target & Source coordinates */
|
||||
*((PRECTL)&aptlPoints[0]) = *prcl_begin_paint_rect;
|
||||
*((PRECTL)&aptlPoints[2]) = *prcl_begin_paint_rect;
|
||||
|
||||
/* Make the Target coordinates non-inclusive */
|
||||
aptlPoints[1].x -= 1;
|
||||
aptlPoints[1].y -= 1;
|
||||
|
||||
/* Enable Y Inversion for the HPS, so GpiDrawBits will
|
||||
* work with upside-top image, not with upside-down image!
|
||||
*/
|
||||
lOldYInversion = GpiQueryYInversion (hps_begin_paint);
|
||||
GpiEnableYInversion (hps_begin_paint, surface->bitmap_info.cy-1);
|
||||
|
||||
/* Target coordinates (Noninclusive) */
|
||||
aptlPoints[0].x = prcl_begin_paint_rect->xLeft;
|
||||
aptlPoints[0].y = prcl_begin_paint_rect->yBottom;
|
||||
|
||||
aptlPoints[1].x = prcl_begin_paint_rect->xRight-1;
|
||||
aptlPoints[1].y = prcl_begin_paint_rect->yTop-1;
|
||||
|
||||
/* Source coordinates (Inclusive) */
|
||||
aptlPoints[2].x = prcl_begin_paint_rect->xLeft;
|
||||
aptlPoints[2].y = prcl_begin_paint_rect->yBottom;
|
||||
|
||||
aptlPoints[3].x = prcl_begin_paint_rect->xRight;
|
||||
aptlPoints[3].y = (prcl_begin_paint_rect->yTop);
|
||||
|
||||
/* Some extra checking for limits
|
||||
* (Dunno if really needed, but had some crashes sometimes without it,
|
||||
* while developing the code...)
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (aptlPoints[i].x < 0)
|
||||
aptlPoints[i].x = 0;
|
||||
if (aptlPoints[i].y < 0)
|
||||
aptlPoints[i].y = 0;
|
||||
if (aptlPoints[i].x > (LONG) surface->bitmap_info.cx)
|
||||
aptlPoints[i].x = (LONG) surface->bitmap_info.cx;
|
||||
if (aptlPoints[i].y > (LONG) surface->bitmap_info.cy)
|
||||
aptlPoints[i].y = (LONG) surface->bitmap_info.cy;
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug code to draw rectangle limits */
|
||||
#if 0
|
||||
{
|
||||
@ -364,63 +349,81 @@ _cairo_os2_surface_blit_pixels (cairo_os2_surface_t *surface,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rc = GpiDrawBits (hps_begin_paint,
|
||||
surface->pixels,
|
||||
&(surface->bitmap_info),
|
||||
4,
|
||||
aptlPoints,
|
||||
ROP_SRCCOPY,
|
||||
BBO_IGNORE);
|
||||
if (!surface->use_24bpp) {
|
||||
rc = GpiDrawBits (hps_begin_paint,
|
||||
surface->pixels,
|
||||
&(surface->bitmap_info),
|
||||
4,
|
||||
aptlPoints,
|
||||
ROP_SRCCOPY,
|
||||
BBO_IGNORE);
|
||||
if (rc != GPI_OK)
|
||||
surface->use_24bpp = TRUE;
|
||||
}
|
||||
|
||||
if (rc != GPI_OK) {
|
||||
/* if GpiDrawBits () failed then this is most likely because the
|
||||
if (surface->use_24bpp) {
|
||||
/* If GpiDrawBits () failed then this is most likely because the
|
||||
* display driver could not handle a 32bit bitmap. So we need to
|
||||
* - create a buffer that only contains 3 bytes per pixel
|
||||
* - change the bitmap info header to contain 24bit
|
||||
* - pass the new buffer to GpiDrawBits () again
|
||||
* - clean up the new buffer
|
||||
*/
|
||||
BITMAPINFOHEADER2 bmpheader;
|
||||
unsigned char *pchPixBuf, *pchPixSource;
|
||||
void *pBufStart;
|
||||
ULONG ulPixels;
|
||||
BITMAPINFO2 bmpinfo;
|
||||
unsigned char *pchPixBuf;
|
||||
unsigned char *pchTarget;
|
||||
ULONG *pulSource;
|
||||
ULONG ulX;
|
||||
ULONG ulY;
|
||||
ULONG ulPad;
|
||||
|
||||
/* allocate temporary pixel buffer */
|
||||
pchPixBuf = (unsigned char *) _buffer_alloc (surface->bitmap_info.cy,
|
||||
surface->bitmap_info.cx,
|
||||
3);
|
||||
pchPixSource = surface->pixels; /* start at beginning of pixel buffer */
|
||||
pBufStart = pchPixBuf; /* remember beginning of the new pixel buffer */
|
||||
/* Set up the bitmap header, but this time for 24bit depth. */
|
||||
bmpinfo = surface->bitmap_info;
|
||||
bmpinfo.cBitCount = 24;
|
||||
|
||||
/* copy the first three bytes for each pixel but skip over the fourth */
|
||||
for (ulPixels = 0; ulPixels < surface->bitmap_info.cx * surface->bitmap_info.cy; ulPixels++)
|
||||
{
|
||||
/* copy BGR from source buffer */
|
||||
*pchPixBuf++ = *pchPixSource++;
|
||||
*pchPixBuf++ = *pchPixSource++;
|
||||
*pchPixBuf++ = *pchPixSource++;
|
||||
pchPixSource++; /* jump over alpha channel in source buffer */
|
||||
/* The start of each row has to be DWORD aligned. Calculate the
|
||||
* of number aligned bytes per row, the total size of the bitmap,
|
||||
* and the number of padding bytes at the end of each row.
|
||||
*/
|
||||
ulX = (((bmpinfo.cx * bmpinfo.cBitCount) + 31) / 32) * 4;
|
||||
bmpinfo.cbImage = ulX * bmpinfo.cy;
|
||||
ulPad = ulX - bmpinfo.cx * 3;
|
||||
|
||||
/* Allocate temporary pixel buffer. If the rows don't need
|
||||
* padding, it has to be 1 byte larger than the size of the
|
||||
* bitmap or else the high-order byte from the last source
|
||||
* row will end up in unallocated memory.
|
||||
*/
|
||||
pchPixBuf = (unsigned char *)_buffer_alloc (1, 1,
|
||||
bmpinfo.cbImage + (ulPad ? 0 : 1));
|
||||
|
||||
if (pchPixBuf) {
|
||||
/* Copy 4 bytes from the source but advance the target ptr only
|
||||
* 3 bytes, so the high-order alpha byte will be overwritten by
|
||||
* the next copy. At the end of each row, skip over the padding.
|
||||
*/
|
||||
pchTarget = pchPixBuf;
|
||||
pulSource = (ULONG*)surface->pixels;
|
||||
for (ulY = bmpinfo.cy; ulY; ulY--) {
|
||||
for (ulX = bmpinfo.cx; ulX; ulX--) {
|
||||
*((ULONG*)pchTarget) = *pulSource++;
|
||||
pchTarget += 3;
|
||||
}
|
||||
pchTarget += ulPad;
|
||||
}
|
||||
|
||||
rc = GpiDrawBits (hps_begin_paint,
|
||||
pchPixBuf,
|
||||
&bmpinfo,
|
||||
4,
|
||||
aptlPoints,
|
||||
ROP_SRCCOPY,
|
||||
BBO_IGNORE);
|
||||
if (rc != GPI_OK)
|
||||
surface->use_24bpp = FALSE;
|
||||
|
||||
_buffer_free (pchPixBuf);
|
||||
}
|
||||
|
||||
/* jump back to start of the buffer for display and cleanup */
|
||||
pchPixBuf = pBufStart;
|
||||
|
||||
/* set up the bitmap header, but this time with 24bit depth only */
|
||||
memset (&bmpheader, 0, sizeof (bmpheader));
|
||||
bmpheader.cbFix = sizeof (BITMAPINFOHEADER2);
|
||||
bmpheader.cx = surface->bitmap_info.cx;
|
||||
bmpheader.cy = surface->bitmap_info.cy;
|
||||
bmpheader.cPlanes = surface->bitmap_info.cPlanes;
|
||||
bmpheader.cBitCount = 24;
|
||||
rc = GpiDrawBits (hps_begin_paint,
|
||||
pchPixBuf,
|
||||
(PBITMAPINFO2)&bmpheader,
|
||||
4,
|
||||
aptlPoints,
|
||||
ROP_SRCCOPY,
|
||||
BBO_IGNORE);
|
||||
|
||||
_buffer_free (pchPixBuf);
|
||||
}
|
||||
|
||||
/* Restore Y inversion */
|
||||
@ -434,7 +437,6 @@ _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
|
||||
{
|
||||
HPS hps;
|
||||
HDC hdc;
|
||||
HAB hab;
|
||||
SIZEL sizlTemp;
|
||||
HBITMAP hbmpTemp;
|
||||
BITMAPINFO2 bmi2Temp;
|
||||
@ -452,19 +454,10 @@ _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
|
||||
* -- Blit dirty pixels from screen to HBITMAP
|
||||
* - Copy HBITMAP lines (pixels) into our buffer
|
||||
* - Free resources
|
||||
*
|
||||
* These steps will require an Anchor Block (HAB). However,
|
||||
* WinQUeryAnchorBlock () documentation says that HAB is not
|
||||
* used in current OS/2 implementations, OS/2 deduces all information
|
||||
* it needs from the TID. Anyway, we'd be in trouble if we'd have to
|
||||
* get a HAB where we only know a HPS...
|
||||
* So, we'll simply use a fake HAB.
|
||||
*/
|
||||
|
||||
hab = (HAB) 1; /* OS/2 doesn't really use HAB... */
|
||||
|
||||
/* Create a memory device context */
|
||||
hdc = DevOpenDC (hab, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
|
||||
hdc = DevOpenDC (0, OD_MEMORY,"*",0L, NULL, NULLHANDLE);
|
||||
if (!hdc) {
|
||||
return;
|
||||
}
|
||||
@ -472,7 +465,7 @@ _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
|
||||
/* Create a memory PS */
|
||||
sizlTemp.cx = prcl_begin_paint_rect->xRight - prcl_begin_paint_rect->xLeft;
|
||||
sizlTemp.cy = prcl_begin_paint_rect->yTop - prcl_begin_paint_rect->yBottom;
|
||||
hps = GpiCreatePS (hab,
|
||||
hps = GpiCreatePS (0,
|
||||
hdc,
|
||||
&sizlTemp,
|
||||
PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
|
||||
@ -537,7 +530,7 @@ _cairo_os2_surface_get_pixels_from_screen (cairo_os2_surface_t *surface,
|
||||
GpiQueryBitmapBits (hps,
|
||||
sizlTemp.cy - y - 1, /* lScanStart */
|
||||
1, /* lScans */
|
||||
pchTemp,
|
||||
(PBYTE)pchTemp,
|
||||
&bmi2Temp);
|
||||
|
||||
/* Go for next line */
|
||||
@ -722,6 +715,14 @@ _cairo_os2_surface_get_extents (void *abstract_surface,
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
|
||||
local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
|
||||
if ((!local_os2_surface) ||
|
||||
(local_os2_surface->base.backend != &cairo_os2_surface_backend))
|
||||
{
|
||||
/* Invalid parameter (wrong surface)! */
|
||||
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
||||
}
|
||||
|
||||
rectangle->x = 0;
|
||||
rectangle->y = 0;
|
||||
rectangle->width = local_os2_surface->bitmap_info.cx;
|
||||
@ -737,14 +738,15 @@ _cairo_os2_surface_get_extents (void *abstract_surface,
|
||||
* @height: the height of the surface
|
||||
*
|
||||
* Create a Cairo surface which is bound to a given presentation space (HPS).
|
||||
* The surface will be created to have the given size.
|
||||
* By default every change to the surface will be made visible immediately by
|
||||
* blitting it into the window. This can be changed with
|
||||
* The caller retains ownership of the HPS and must dispose of it after the
|
||||
* the surface has been destroyed. The surface will be created to have the
|
||||
* given size. By default every change to the surface will be made visible
|
||||
* immediately by blitting it into the window. This can be changed with
|
||||
* cairo_os2_surface_set_manual_window_refresh().
|
||||
* Note that the surface will contain garbage when created, so the pixels have
|
||||
* to be initialized by hand first. You can use the Cairo functions to fill it
|
||||
* with black, or use cairo_surface_mark_dirty() to fill the surface with pixels
|
||||
* from the window/HPS.
|
||||
* Note that the surface will contain garbage when created, so the pixels
|
||||
* have to be initialized by hand first. You can use the Cairo functions to
|
||||
* fill it with black, or use cairo_surface_mark_dirty() to fill the surface
|
||||
* with pixels from the window/HPS.
|
||||
*
|
||||
* Return value: the newly created surface
|
||||
*
|
||||
@ -755,72 +757,48 @@ cairo_os2_surface_create (HPS hps_client_window,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
cairo_os2_surface_t *local_os2_surface = 0;
|
||||
cairo_status_t status;
|
||||
int rc;
|
||||
|
||||
/* Check the size of the window */
|
||||
if ((width <= 0) ||
|
||||
(height <= 0))
|
||||
{
|
||||
/* Invalid window size! */
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
|
||||
if ((width <= 0) || (height <= 0)) {
|
||||
status = _cairo_error (CAIRO_STATUS_INVALID_SIZE);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Allocate an OS/2 surface structure. */
|
||||
local_os2_surface = (cairo_os2_surface_t *) malloc (sizeof (cairo_os2_surface_t));
|
||||
if (!local_os2_surface) {
|
||||
/* Not enough memory! */
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Initialize the OS/2 specific parts of the surface! */
|
||||
memset(local_os2_surface, 0, sizeof(cairo_os2_surface_t));
|
||||
|
||||
/* Create mutex semaphore */
|
||||
rc = DosCreateMutexSem (NULL,
|
||||
&(local_os2_surface->hmtx_use_private_fields),
|
||||
0,
|
||||
FALSE);
|
||||
if (rc != NO_ERROR) {
|
||||
/* Could not create mutex semaphore! */
|
||||
free (local_os2_surface);
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
/* Allocate resources: mutex & event semaphores and the pixel buffer */
|
||||
if (DosCreateMutexSem (NULL,
|
||||
&(local_os2_surface->hmtx_use_private_fields),
|
||||
0,
|
||||
FALSE))
|
||||
{
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Save PS handle */
|
||||
local_os2_surface->hps_client_window = hps_client_window;
|
||||
|
||||
/* Defaults */
|
||||
local_os2_surface->hwnd_client_window = NULLHANDLE;
|
||||
local_os2_surface->blit_as_changes = TRUE;
|
||||
local_os2_surface->pixel_array_lend_count = 0;
|
||||
rc = DosCreateEventSem (NULL,
|
||||
&(local_os2_surface->hev_pixel_array_came_back),
|
||||
0,
|
||||
FALSE);
|
||||
|
||||
if (rc != NO_ERROR) {
|
||||
/* Could not create event semaphore! */
|
||||
DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
|
||||
free (local_os2_surface);
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
if (DosCreateEventSem (NULL,
|
||||
&(local_os2_surface->hev_pixel_array_came_back),
|
||||
0,
|
||||
FALSE))
|
||||
{
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Prepare BITMAPINFO2 structure for our buffer */
|
||||
memset (&(local_os2_surface->bitmap_info), 0, sizeof (local_os2_surface->bitmap_info));
|
||||
local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
|
||||
local_os2_surface->bitmap_info.cx = width;
|
||||
local_os2_surface->bitmap_info.cy = height;
|
||||
local_os2_surface->bitmap_info.cPlanes = 1;
|
||||
local_os2_surface->bitmap_info.cBitCount = 32;
|
||||
|
||||
/* Allocate memory for pixels */
|
||||
local_os2_surface->pixels = (unsigned char *) _buffer_alloc (height, width, 4);
|
||||
if (!(local_os2_surface->pixels)) {
|
||||
/* Not enough memory for the pixels! */
|
||||
DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
|
||||
DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
|
||||
free (local_os2_surface);
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
if (!local_os2_surface->pixels) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Create image surface from pixel array */
|
||||
@ -830,22 +808,91 @@ cairo_os2_surface_create (HPS hps_client_window,
|
||||
width, /* Width */
|
||||
height, /* Height */
|
||||
width * 4); /* Rowstride */
|
||||
|
||||
status = local_os2_surface->image_surface->base.status;
|
||||
if (status) {
|
||||
/* Could not create image surface! */
|
||||
_buffer_free (local_os2_surface->pixels);
|
||||
DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
|
||||
DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
|
||||
free (local_os2_surface);
|
||||
return _cairo_surface_create_in_error (status);
|
||||
}
|
||||
if (status)
|
||||
goto error_exit;
|
||||
|
||||
/* Set values for OS/2-specific data that aren't zero/NULL/FALSE.
|
||||
* Note: hps_client_window may be null if this was called by
|
||||
* cairo_os2_surface_create_for_window().
|
||||
*/
|
||||
local_os2_surface->hps_client_window = hps_client_window;
|
||||
local_os2_surface->blit_as_changes = TRUE;
|
||||
|
||||
/* Prepare BITMAPINFO2 structure for our buffer */
|
||||
local_os2_surface->bitmap_info.cbFix = sizeof (BITMAPINFOHEADER2);
|
||||
local_os2_surface->bitmap_info.cx = width;
|
||||
local_os2_surface->bitmap_info.cy = height;
|
||||
local_os2_surface->bitmap_info.cPlanes = 1;
|
||||
local_os2_surface->bitmap_info.cBitCount = 32;
|
||||
|
||||
/* Initialize base surface */
|
||||
_cairo_surface_init (&local_os2_surface->base,
|
||||
&cairo_os2_surface_backend,
|
||||
_cairo_content_from_format (CAIRO_FORMAT_ARGB32));
|
||||
|
||||
/* Successful exit */
|
||||
return (cairo_surface_t *)local_os2_surface;
|
||||
|
||||
error_exit:
|
||||
|
||||
/* This point will only be reached if an error occured */
|
||||
|
||||
if (local_os2_surface) {
|
||||
if (local_os2_surface->pixels)
|
||||
_buffer_free (local_os2_surface->pixels);
|
||||
if (local_os2_surface->hev_pixel_array_came_back)
|
||||
DosCloseEventSem (local_os2_surface->hev_pixel_array_came_back);
|
||||
if (local_os2_surface->hmtx_use_private_fields)
|
||||
DosCloseMutexSem (local_os2_surface->hmtx_use_private_fields);
|
||||
free (local_os2_surface);
|
||||
}
|
||||
|
||||
return _cairo_surface_create_in_error (status);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_os2_surface_create_for_window:
|
||||
* @hwnd_client_window: the window handle to bind the surface to
|
||||
* @width: the width of the surface
|
||||
* @height: the height of the surface
|
||||
*
|
||||
* Create a Cairo surface which is bound to a given window; the caller retains
|
||||
* ownership of the window. This is a convenience function for use with
|
||||
* windows that will only be updated when cairo_os2_surface_refresh_window()
|
||||
* is called (usually in response to a WM_PAINT message). It avoids the need
|
||||
* to create a persistent HPS for every window and assumes that one will be
|
||||
* supplied by the caller when a cairo function needs one. If it isn't, an
|
||||
* HPS will be created on-the-fly and released before the function which needs
|
||||
* it returns.
|
||||
*
|
||||
* Return value: the newly created surface
|
||||
*
|
||||
* Since: 1.10
|
||||
**/
|
||||
cairo_surface_t *
|
||||
cairo_os2_surface_create_for_window (HWND hwnd_client_window,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
|
||||
/* A window handle must be provided. */
|
||||
if (!hwnd_client_window) {
|
||||
return _cairo_surface_create_in_error (
|
||||
_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
}
|
||||
|
||||
/* Create the surface. */
|
||||
local_os2_surface = (cairo_os2_surface_t *)
|
||||
cairo_os2_surface_create (0, width, height);
|
||||
|
||||
/* If successful, save the hwnd & turn off automatic repainting. */
|
||||
if (!local_os2_surface->image_surface->base.status) {
|
||||
local_os2_surface->hwnd_client_window = hwnd_client_window;
|
||||
local_os2_surface->blit_as_changes = FALSE;
|
||||
}
|
||||
|
||||
return (cairo_surface_t *)local_os2_surface;
|
||||
}
|
||||
|
||||
@ -1014,6 +1061,7 @@ cairo_os2_surface_refresh_window (cairo_surface_t *surface,
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
RECTL rclTemp;
|
||||
HPS hpsTemp = 0;
|
||||
|
||||
local_os2_surface = (cairo_os2_surface_t *) surface;
|
||||
if ((!local_os2_surface) ||
|
||||
@ -1023,9 +1071,19 @@ cairo_os2_surface_refresh_window (cairo_surface_t *surface,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Manage defaults (NULLs) */
|
||||
if (!hps_begin_paint)
|
||||
/* If an HPS wasn't provided, see if we can get one. */
|
||||
if (!hps_begin_paint) {
|
||||
hps_begin_paint = local_os2_surface->hps_client_window;
|
||||
if (!hps_begin_paint) {
|
||||
if (local_os2_surface->hwnd_client_window) {
|
||||
hpsTemp = WinGetPS(local_os2_surface->hwnd_client_window);
|
||||
hps_begin_paint = hpsTemp;
|
||||
}
|
||||
/* No HPS & no way to get one, so exit */
|
||||
if (!hps_begin_paint)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (prcl_begin_paint_rect == NULL) {
|
||||
/* Update the whole window! */
|
||||
@ -1046,6 +1104,8 @@ cairo_os2_surface_refresh_window (cairo_surface_t *surface,
|
||||
!= NO_ERROR)
|
||||
{
|
||||
/* Could not get mutex! */
|
||||
if (hpsTemp)
|
||||
WinReleasePS(hpsTemp);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1073,6 +1133,9 @@ cairo_os2_surface_refresh_window (cairo_surface_t *surface,
|
||||
}
|
||||
|
||||
DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
|
||||
|
||||
if (hpsTemp)
|
||||
WinReleasePS(hpsTemp);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
@ -1109,10 +1172,10 @@ _cairo_os2_surface_finish (void *abstract_surface)
|
||||
* @surface: the cairo surface to associate with the window handle
|
||||
* @hwnd_client_window: the window handle of the client window
|
||||
*
|
||||
* Sets window handle for surface. If Cairo wants to blit into the window
|
||||
* because it is set to blit as the surface changes (see
|
||||
* cairo_os2_surface_set_manual_window_refresh()), then there are two ways it
|
||||
* can choose:
|
||||
* Sets window handle for surface; the caller retains ownership of the window.
|
||||
* If Cairo wants to blit into the window because it is set to blit as the
|
||||
* surface changes (see cairo_os2_surface_set_manual_window_refresh()), then
|
||||
* there are two ways it can choose:
|
||||
* If it knows the HWND of the surface, then it invalidates that area, so the
|
||||
* application will get a WM_PAINT message and it can call
|
||||
* cairo_os2_surface_refresh_window() to redraw that area. Otherwise cairo itself
|
||||
@ -1214,6 +1277,74 @@ cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface)
|
||||
return !(local_os2_surface->blit_as_changes);
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_os2_surface_get_hps:
|
||||
* @surface: the cairo surface to be querued
|
||||
* @hps: HPS currently associated with the surface (if any)
|
||||
*
|
||||
* This API retrieves the HPS associated with the surface.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS if the hps could be retrieved,
|
||||
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
|
||||
* %CAIRO_STATUS_NULL_POINTER if the hps argument is null
|
||||
*
|
||||
* Since: 1.10
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_os2_surface_get_hps (cairo_surface_t *surface,
|
||||
HPS *hps)
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
|
||||
local_os2_surface = (cairo_os2_surface_t *) surface;
|
||||
if ((!local_os2_surface) ||
|
||||
(local_os2_surface->base.backend != &cairo_os2_surface_backend))
|
||||
{
|
||||
/* Invalid parameter (wrong surface)! */
|
||||
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
||||
}
|
||||
if (!hps)
|
||||
{
|
||||
return _cairo_error (CAIRO_STATUS_NULL_POINTER);
|
||||
}
|
||||
*hps = local_os2_surface->hps_client_window;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_os2_surface_set_hps:
|
||||
* @surface: the cairo surface to associate with the HPS
|
||||
* @hps: new HPS to be associated with the surface (the HPS may be null)
|
||||
*
|
||||
* This API replaces the HPS associated with the surface with a new one.
|
||||
* The caller retains ownership of the HPS and must dispose of it after
|
||||
* the surface has been destroyed or it has been replaced by another
|
||||
* call to this function.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS if the hps could be replaced,
|
||||
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface is not an OS/2 surface,
|
||||
*
|
||||
* Since: 1.10
|
||||
**/
|
||||
cairo_status_t
|
||||
cairo_os2_surface_set_hps (cairo_surface_t *surface,
|
||||
HPS hps)
|
||||
{
|
||||
cairo_os2_surface_t *local_os2_surface;
|
||||
|
||||
local_os2_surface = (cairo_os2_surface_t *) surface;
|
||||
if ((!local_os2_surface) ||
|
||||
(local_os2_surface->base.backend != &cairo_os2_surface_backend))
|
||||
{
|
||||
/* Invalid parameter (wrong surface)! */
|
||||
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
||||
}
|
||||
local_os2_surface->hps_client_window = hps;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_os2_surface_mark_dirty_rectangle (void *surface,
|
||||
int x,
|
||||
@ -1331,5 +1462,11 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = {
|
||||
NULL, /* stroke */
|
||||
NULL, /* fill */
|
||||
NULL, /* show_glyphs */
|
||||
NULL /* snapshot */
|
||||
NULL, /* snapshot */
|
||||
NULL, /* is_similar */
|
||||
NULL, /* fill_stroke */
|
||||
NULL, /* create_solid_pattern_surface */
|
||||
NULL, /* can_repaint_solid_pattern_surface */
|
||||
NULL, /* has_show_text_glyphs */
|
||||
NULL /* show_text_glyphs */
|
||||
};
|
||||
|
@ -33,6 +33,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Peter Weilbacher <mozilla@Weilbacher.org>
|
||||
* Rich Walsh <dragtext@e-vertise.com>
|
||||
*/
|
||||
|
||||
#ifndef _CAIRO_OS2_H_
|
||||
@ -65,6 +66,11 @@ cairo_os2_surface_create (HPS hps_client_window,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
cairo_public cairo_surface_t *
|
||||
cairo_os2_surface_create_for_window (HWND hwnd_client_window,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
cairo_public void
|
||||
cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
|
||||
HWND hwnd_client_window);
|
||||
@ -87,6 +93,14 @@ cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
|
||||
cairo_public cairo_bool_t
|
||||
cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_os2_surface_get_hps (cairo_surface_t *surface,
|
||||
HPS *hps);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_os2_surface_set_hps (cairo_surface_t *surface,
|
||||
HPS hps);
|
||||
|
||||
#else /* CAIRO_HAS_OS2_SURFACE */
|
||||
# error Cairo was not compiled with support for the OS/2 backend
|
||||
#endif /* CAIRO_HAS_OS2_SURFACE */
|
||||
|
@ -114,11 +114,14 @@
|
||||
#define cairo_os2_fini _moz_cairo_os2_fini
|
||||
#define cairo_os2_init _moz_cairo_os2_init
|
||||
#define cairo_os2_surface_create _moz_cairo_os2_surface_create
|
||||
#define cairo_os2_surface_create_for_window _moz_cairo_os2_surface_create_for_window
|
||||
#define cairo_os2_surface_get_manual_window_refresh _moz_cairo_os2_surface_get_manual_window_refresh
|
||||
#define cairo_os2_surface_refresh_window _moz_cairo_os2_surface_refresh_window
|
||||
#define cairo_os2_surface_set_hwnd _moz_cairo_os2_surface_set_hwnd
|
||||
#define cairo_os2_surface_set_manual_window_refresh _moz_cairo_os2_surface_set_manual_window_refresh
|
||||
#define cairo_os2_surface_set_size _moz_cairo_os2_surface_set_size
|
||||
#define cairo_os2_surface_get_hps _moz_cairo_os2_surface_get_hps
|
||||
#define cairo_os2_surface_set_hps _moz_cairo_os2_surface_set_hps
|
||||
#define cairo_paint _moz_cairo_paint
|
||||
#define cairo_paint_with_alpha _moz_cairo_paint_with_alpha
|
||||
#define cairo_path_destroy _moz_cairo_path_destroy
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
gfxOS2Surface::gfxOS2Surface(const gfxIntSize& aSize,
|
||||
gfxASurface::gfxImageFormat aImageFormat)
|
||||
: mHasWnd(PR_FALSE), mSize(aSize)
|
||||
: mWnd(0), mSize(aSize)
|
||||
{
|
||||
#ifdef DEBUG_thebes_2
|
||||
printf("gfxOS2Surface[%#x]::gfxOS2Surface(Size=%dx%d, %d)\n", (unsigned int)this,
|
||||
@ -97,40 +97,35 @@ gfxOS2Surface::gfxOS2Surface(const gfxIntSize& aSize,
|
||||
}
|
||||
|
||||
gfxOS2Surface::gfxOS2Surface(HWND aWnd)
|
||||
: mHasWnd(PR_TRUE), mDC(nsnull), mBitmap(nsnull)
|
||||
: mWnd(aWnd), mDC(nsnull), mPS(nsnull), mBitmap(nsnull)
|
||||
{
|
||||
#ifdef DEBUG_thebes_2
|
||||
printf("gfxOS2Surface[%#x]::gfxOS2Surface(HWND=%#x)\n", (unsigned int)this,
|
||||
(unsigned int)aWnd);
|
||||
#endif
|
||||
|
||||
mPS = WinGetPS(aWnd);
|
||||
|
||||
RECTL rectl;
|
||||
WinQueryWindowRect(aWnd, &rectl);
|
||||
mSize.width = rectl.xRight - rectl.xLeft;
|
||||
mSize.height = rectl.yTop - rectl.yBottom;
|
||||
if (mSize.width == 0) mSize.width = 1; // fake a minimal surface area to let
|
||||
if (mSize.height == 0) mSize.height = 1; // cairo_os2_surface_create() return something
|
||||
cairo_surface_t *surf = cairo_os2_surface_create(mPS, mSize.width, mSize.height);
|
||||
|
||||
// This variation on cairo_os2_surface_create() avoids creating a
|
||||
// persistent HPS that may never be used. It also enables manual
|
||||
// refresh so nsWindow::OnPaint() controls when the screen is updated.
|
||||
cairo_surface_t *surf =
|
||||
cairo_os2_surface_create_for_window(mWnd, mSize.width, mSize.height);
|
||||
#ifdef DEBUG_thebes_2
|
||||
printf(" type(%#x)=%d (ID=%#x, h/w=%d/%d)\n", (unsigned int)surf,
|
||||
cairo_surface_get_type(surf), (unsigned int)mPS, mSize.width, mSize.height);
|
||||
#endif
|
||||
// Normally, OS/2 cairo surfaces have to be forced to redraw completely
|
||||
// by calling cairo_surface_mark_dirty(surf), but Mozilla paints them in
|
||||
// full, so that is not necessary here.
|
||||
|
||||
// record the window handle in the cairo surface, so that refresh works
|
||||
cairo_os2_surface_set_hwnd(surf, aWnd);
|
||||
// manual refresh is done from nsWindow::OnPaint
|
||||
cairo_os2_surface_set_manual_window_refresh(surf, 1);
|
||||
|
||||
Init(surf);
|
||||
}
|
||||
|
||||
gfxOS2Surface::gfxOS2Surface(HDC aDC, const gfxIntSize& aSize)
|
||||
: mHasWnd(PR_FALSE), mDC(aDC), mBitmap(nsnull), mSize(aSize)
|
||||
: mWnd(0), mDC(aDC), mBitmap(nsnull), mSize(aSize)
|
||||
{
|
||||
#ifdef DEBUG_thebes_2
|
||||
printf("gfxOS2Surface[%#x]::gfxOS2Surface(HDC=%#x, Size=%dx%d)\n", (unsigned int)this,
|
||||
@ -180,7 +175,7 @@ gfxOS2Surface::~gfxOS2Surface()
|
||||
// release it again with WinReleasePS. Memory or printer surfaces on the
|
||||
// other hand were created on device contexts with the GPI functions, so
|
||||
// use those to clean up stuff.
|
||||
if (mHasWnd) {
|
||||
if (mWnd) {
|
||||
if (mPS) {
|
||||
WinReleasePS(mPS);
|
||||
}
|
||||
@ -206,7 +201,7 @@ void gfxOS2Surface::Refresh(RECTL *aRect, HPS aPS)
|
||||
aRect->xLeft, aRect->xRight, aRect->yBottom, aRect->yTop,
|
||||
(unsigned int)aPS, (unsigned int)mPS);
|
||||
#endif
|
||||
cairo_os2_surface_refresh_window(CairoSurface(), aPS, aRect);
|
||||
cairo_os2_surface_refresh_window(CairoSurface(), (aPS ? aPS : mPS), aRect);
|
||||
}
|
||||
|
||||
int gfxOS2Surface::Resize(const gfxIntSize& aSize)
|
||||
@ -219,3 +214,22 @@ int gfxOS2Surface::Resize(const gfxIntSize& aSize)
|
||||
// hardcode mutex timeout to 50ms for now
|
||||
return cairo_os2_surface_set_size(CairoSurface(), mSize.width, mSize.height, 50);
|
||||
}
|
||||
|
||||
HPS gfxOS2Surface::GetPS()
|
||||
{
|
||||
// Creating an HPS on-the-fly should never be needed because GetPS()
|
||||
// is only called for printing surfaces & mPS should only be null for
|
||||
// window surfaces. It would be a bug if Cairo had an HPS but Thebes
|
||||
// didn't, but we'll check anyway to avoid leakage. As a last resort,
|
||||
// if this is a window surface we'll create one & hang on to it.
|
||||
if (!mPS) {
|
||||
cairo_os2_surface_get_hps(CairoSurface(), &mPS);
|
||||
if (!mPS && mWnd) {
|
||||
mPS = WinGetPS(mWnd);
|
||||
cairo_os2_surface_set_hps(CairoSurface(), mPS);
|
||||
}
|
||||
}
|
||||
|
||||
return mPS;
|
||||
}
|
||||
|
||||
|
@ -66,11 +66,11 @@ public:
|
||||
// Reset the cairo surface to the given size.
|
||||
int Resize(const gfxIntSize& aSize);
|
||||
|
||||
HPS GetPS() { return mPS; }
|
||||
HPS GetPS();
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
private:
|
||||
PRBool mHasWnd; // indicates if created through the HWND constructor
|
||||
HWND mWnd; // non-null if created through the HWND constructor
|
||||
HDC mDC; // memory device context
|
||||
HPS mPS; // presentation space connected to window or memory device
|
||||
HBITMAP mBitmap; // bitmap for initialization of memory surface
|
||||
|
1
netwerk/cache/nsCacheRequest.h
vendored
1
netwerk/cache/nsCacheRequest.h
vendored
@ -54,6 +54,7 @@ class nsCacheRequest : public PRCList
|
||||
private:
|
||||
friend class nsCacheService;
|
||||
friend class nsCacheEntry;
|
||||
friend class nsProcessRequestEvent;
|
||||
|
||||
nsCacheRequest( nsCString * key,
|
||||
nsICacheListener * listener,
|
||||
|
92
netwerk/cache/nsCacheService.cpp
vendored
92
netwerk/cache/nsCacheService.cpp
vendored
@ -614,6 +614,44 @@ nsCacheProfilePrefObserver::MemoryCacheCapacity()
|
||||
return capacity;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsProcessRequestEvent
|
||||
*****************************************************************************/
|
||||
|
||||
class nsProcessRequestEvent : public nsRunnable {
|
||||
public:
|
||||
nsProcessRequestEvent(nsCacheRequest *aRequest)
|
||||
{
|
||||
mRequest = aRequest;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(mRequest->mListener,
|
||||
"Sync OpenCacheEntry() posted to background thread!");
|
||||
|
||||
nsCacheServiceAutoLock lock;
|
||||
rv = nsCacheService::gService->ProcessRequest(mRequest,
|
||||
PR_FALSE,
|
||||
nsnull);
|
||||
|
||||
// Don't delete the request if it was queued
|
||||
if (rv != NS_ERROR_CACHE_WAIT_FOR_VALIDATION)
|
||||
delete mRequest;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsProcessRequestEvent() {}
|
||||
|
||||
private:
|
||||
nsCacheRequest *mRequest;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* nsCacheService
|
||||
*****************************************************************************/
|
||||
@ -681,8 +719,13 @@ nsCacheService::Init()
|
||||
|
||||
CACHE_LOG_INIT();
|
||||
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mCacheIOThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Can't create cache IO thread");
|
||||
}
|
||||
|
||||
// initialize hashtable for active cache entries
|
||||
nsresult rv = mActiveEntries.Init();
|
||||
rv = mActiveEntries.Init();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// create profile/preference observer
|
||||
@ -703,6 +746,9 @@ nsCacheService::Init()
|
||||
void
|
||||
nsCacheService::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIThread> cacheIOThread;
|
||||
|
||||
{
|
||||
nsCacheServiceAutoLock lock;
|
||||
NS_ASSERTION(mInitialized,
|
||||
"can't shutdown nsCacheService unless it has been initialized.");
|
||||
@ -734,7 +780,13 @@ nsCacheService::Shutdown()
|
||||
#if defined(NECKO_DISK_CACHE) && defined(PR_LOGGING)
|
||||
LogCacheStatistics();
|
||||
#endif
|
||||
|
||||
mCacheIOThread.swap(cacheIOThread);
|
||||
}
|
||||
} // lock
|
||||
|
||||
if (cacheIOThread)
|
||||
cacheIOThread->Shutdown();
|
||||
}
|
||||
|
||||
|
||||
@ -947,6 +999,17 @@ NS_IMETHODIMP nsCacheService::EvictEntries(nsCacheStoragePolicy storagePolicy)
|
||||
return EvictEntriesForClient(nsnull, storagePolicy);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCacheService::GetCacheIOTarget(nsIEventTarget * *aCacheIOTarget)
|
||||
{
|
||||
nsCacheServiceAutoLock lock;
|
||||
|
||||
if (!mCacheIOThread)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
NS_ADDREF(*aCacheIOTarget = mCacheIOThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal Methods
|
||||
*/
|
||||
@ -1235,11 +1298,28 @@ nsCacheService::OpenCacheEntry(nsCacheSession * session,
|
||||
|
||||
CACHE_LOG_DEBUG(("Created request %p\n", request));
|
||||
|
||||
rv = gService->ProcessRequest(request, PR_TRUE, result);
|
||||
// Process the request on the background thread if we are on the main thread
|
||||
// and the the request is asynchronous
|
||||
if (NS_IsMainThread() && listener && gService->mCacheIOThread) {
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new nsProcessRequestEvent(request);
|
||||
if (ev) {
|
||||
rv = gService->mCacheIOThread->Dispatch(ev, NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// delete requests that have completed
|
||||
if (!(listener && (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)))
|
||||
delete request;
|
||||
// delete request if we didn't post the event
|
||||
if (NS_FAILED(rv))
|
||||
delete request;
|
||||
}
|
||||
else {
|
||||
rv = gService->ProcessRequest(request, PR_TRUE, result);
|
||||
|
||||
// delete requests that have completed
|
||||
if (!(listener && (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION)))
|
||||
delete request;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -1779,7 +1859,7 @@ nsCacheService::ReleaseObject_Locked(nsISupports * obj,
|
||||
NS_ASSERTION(gService->mLockedThread == PR_GetCurrentThread(), "oops");
|
||||
|
||||
PRBool isCur;
|
||||
if (!target || NS_SUCCEEDED(target->IsOnCurrentThread(&isCur)) && isCur) {
|
||||
if (!target || (NS_SUCCEEDED(target->IsOnCurrentThread(&isCur)) && isCur)) {
|
||||
gService->mDoomedObjects.AppendElement(obj);
|
||||
} else {
|
||||
NS_ProxyRelease(target, obj);
|
||||
|
3
netwerk/cache/nsCacheService.h
vendored
3
netwerk/cache/nsCacheService.h
vendored
@ -166,6 +166,7 @@ public:
|
||||
private:
|
||||
friend class nsCacheServiceAutoLock;
|
||||
friend class nsOfflineCacheDevice;
|
||||
friend class nsProcessRequestEvent;
|
||||
|
||||
/**
|
||||
* Internal Methods
|
||||
@ -245,6 +246,8 @@ private:
|
||||
PRThread * mLockedThread; // The thread holding mLock
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIThread> mCacheIOThread;
|
||||
|
||||
nsTArray<nsISupports*> mDoomedObjects;
|
||||
|
||||
PRBool mInitialized;
|
||||
|
78
netwerk/cache/nsDiskCacheDeviceSQL.cpp
vendored
78
netwerk/cache/nsDiskCacheDeviceSQL.cpp
vendored
@ -54,6 +54,7 @@
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozIStorageService.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
@ -171,7 +172,7 @@ DCacheHash(const char * key)
|
||||
* nsOfflineCacheEvictionFunction
|
||||
*/
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsOfflineCacheEvictionFunction, mozIStorageFunction)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsOfflineCacheEvictionFunction, mozIStorageFunction)
|
||||
|
||||
// helper function for directly exposing the same data file binding
|
||||
// path algorithm used in nsOfflineCacheBinding::Create
|
||||
@ -768,11 +769,37 @@ nsApplicationCache::GetUsage(PRUint32 *usage)
|
||||
return mDevice->GetUsage(mClientID, usage);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* nsCloseDBEvent
|
||||
*****************************************************************************/
|
||||
|
||||
class nsCloseDBEvent : public nsRunnable {
|
||||
public:
|
||||
nsCloseDBEvent(mozIStorageConnection *aDB)
|
||||
{
|
||||
mDB = aDB;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mDB->Close();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsCloseDBEvent() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<mozIStorageConnection> mDB;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* nsOfflineCacheDevice
|
||||
*/
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsOfflineCacheDevice, nsIApplicationCacheService)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsOfflineCacheDevice, nsIApplicationCacheService)
|
||||
|
||||
nsOfflineCacheDevice::nsOfflineCacheDevice()
|
||||
: mDB(nsnull)
|
||||
@ -986,6 +1013,8 @@ nsOfflineCacheDevice::Init()
|
||||
rv = ss->OpenDatabase(indexFile, getter_AddRefs(mDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mInitThread = do_GetCurrentThread();
|
||||
|
||||
mDB->ExecuteSimpleSQL(NS_LITERAL_CSTRING("PRAGMA synchronous = OFF;"));
|
||||
|
||||
// XXX ... other initialization steps
|
||||
@ -1201,6 +1230,7 @@ nsOfflineCacheDevice::Shutdown()
|
||||
if (mCaches.IsInitialized())
|
||||
mCaches.EnumerateRead(ShutdownApplicationCache, this);
|
||||
|
||||
{
|
||||
EvictionObserver evictionObserver(mDB, mEvictionFunction);
|
||||
|
||||
// Delete all rows whose clientID is not an active clientID.
|
||||
@ -1227,9 +1257,51 @@ nsOfflineCacheDevice::Shutdown()
|
||||
if (NS_FAILED(rv))
|
||||
NS_WARNING("Failed to clean up namespaces.");
|
||||
|
||||
mDB = 0;
|
||||
mEvictionFunction = 0;
|
||||
|
||||
mStatement_CacheSize = nsnull;
|
||||
mStatement_ApplicationCacheSize = nsnull;
|
||||
mStatement_EntryCount = nsnull;
|
||||
mStatement_UpdateEntry = nsnull;
|
||||
mStatement_UpdateEntrySize = nsnull;
|
||||
mStatement_UpdateEntryFlags = nsnull;
|
||||
mStatement_DeleteEntry = nsnull;
|
||||
mStatement_FindEntry = nsnull;
|
||||
mStatement_BindEntry = nsnull;
|
||||
mStatement_ClearDomain = nsnull;
|
||||
mStatement_MarkEntry = nsnull;
|
||||
mStatement_UnmarkEntry = nsnull;
|
||||
mStatement_GetTypes = nsnull;
|
||||
mStatement_FindNamespaceEntry = nsnull;
|
||||
mStatement_InsertNamespaceEntry = nsnull;
|
||||
mStatement_CleanupUnmarked = nsnull;
|
||||
mStatement_GatherEntries = nsnull;
|
||||
mStatement_ActivateClient = nsnull;
|
||||
mStatement_DeactivateGroup = nsnull;
|
||||
mStatement_FindClient = nsnull;
|
||||
mStatement_FindClientByNamespace = nsnull;
|
||||
mStatement_EnumerateGroups = nsnull;
|
||||
}
|
||||
|
||||
// Close Database on the correct thread
|
||||
PRBool isOnCurrentThread = PR_TRUE;
|
||||
if (mInitThread)
|
||||
mInitThread->IsOnCurrentThread(&isOnCurrentThread);
|
||||
|
||||
if (!isOnCurrentThread) {
|
||||
nsCOMPtr<nsIRunnable> ev = new nsCloseDBEvent(mDB);
|
||||
|
||||
if (ev) {
|
||||
mInitThread->Dispatch(ev, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mDB->Close();
|
||||
}
|
||||
|
||||
mDB = nsnull;
|
||||
mInitThread = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
2
netwerk/cache/nsDiskCacheDeviceSQL.h
vendored
2
netwerk/cache/nsDiskCacheDeviceSQL.h
vendored
@ -275,6 +275,8 @@ private:
|
||||
nsInterfaceHashtable<nsCStringHashKey, nsIWeakReference> mCaches;
|
||||
nsClassHashtable<nsCStringHashKey, nsCString> mActiveCachesByGroup;
|
||||
nsCStringHashSet mActiveCaches;
|
||||
|
||||
nsCOMPtr<nsIThread> mInitThread;
|
||||
};
|
||||
|
||||
#endif // nsOfflineCacheDevice_h__
|
||||
|
8
netwerk/cache/nsICacheService.idl
vendored
8
netwerk/cache/nsICacheService.idl
vendored
@ -47,8 +47,9 @@ interface nsISimpleEnumerator;
|
||||
interface nsICacheListener;
|
||||
interface nsICacheSession;
|
||||
interface nsICacheVisitor;
|
||||
interface nsIEventTarget;
|
||||
|
||||
[scriptable, uuid(de114eb4-29fc-4959-b2f7-2d03eb9bc771)]
|
||||
[scriptable, uuid(14dbe1e9-f3bc-45af-92f4-2c574fcd4e39)]
|
||||
interface nsICacheService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -87,6 +88,11 @@ interface nsICacheService : nsISupports
|
||||
* everything.
|
||||
*/
|
||||
void evictEntries(in nsCacheStoragePolicy storagePolicy);
|
||||
|
||||
/**
|
||||
* Event target which is used for I/O operations
|
||||
*/
|
||||
readonly attribute nsIEventTarget cacheIOTarget;
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -115,6 +115,8 @@ nsHttpChannel::nsHttpChannel()
|
||||
, mCacheAccess(0)
|
||||
, mPostID(0)
|
||||
, mRequestTime(0)
|
||||
, mOnCacheEntryAvailableCallback(nsnull)
|
||||
, mAsyncCacheOpen(PR_FALSE)
|
||||
, mPendingAsyncCallOnResume(nsnull)
|
||||
, mSuspendCount(0)
|
||||
, mApplyConversion(PR_TRUE)
|
||||
@ -198,8 +200,6 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||
|
||||
// true when called from AsyncOpen
|
||||
if (firstTime) {
|
||||
PRBool delayed = PR_FALSE;
|
||||
|
||||
// are we offline?
|
||||
PRBool offline = gIOService->IsOffline();
|
||||
if (offline)
|
||||
@ -214,7 +214,7 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||
}
|
||||
|
||||
// open a cache entry for this channel...
|
||||
rv = OpenCacheEntry(offline, &delayed);
|
||||
rv = OpenCacheEntry();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("OpenCacheEntry failed [rv=%x]\n", rv));
|
||||
@ -238,7 +238,7 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && delayed)
|
||||
if (NS_SUCCEEDED(rv) && mAsyncCacheOpen)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -271,6 +271,14 @@ nsHttpChannel::Connect(PRBool firstTime)
|
||||
return NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
}
|
||||
}
|
||||
else if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
|
||||
// If we have a fallback URI (and we're not already
|
||||
// falling back), process the fallback asynchronously.
|
||||
if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncFallback);
|
||||
}
|
||||
return NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
}
|
||||
|
||||
// check to see if authorization headers should be included
|
||||
mAuthProvider->AddAuthorizationHeaders();
|
||||
@ -1680,11 +1688,11 @@ IsSubRangeRequest(nsHttpRequestHead &aRequestHead)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
nsHttpChannel::OpenCacheEntry()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
*delayed = PR_FALSE;
|
||||
mAsyncCacheOpen = PR_FALSE;
|
||||
mLoadedFromApplicationCache = PR_FALSE;
|
||||
|
||||
LOG(("nsHttpChannel::OpenCacheEntry [this=%p]", this));
|
||||
@ -1720,23 +1728,10 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
|
||||
GenerateCacheKey(mPostID, cacheKey);
|
||||
|
||||
// Get a cache session with appropriate storage policy
|
||||
nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
|
||||
|
||||
// Set the desired cache access mode accordingly...
|
||||
nsCacheAccessMode accessRequested;
|
||||
if (offline || (mLoadFlags & INHIBIT_CACHING)) {
|
||||
// If we have been asked to bypass the cache and not write to the
|
||||
// cache, then don't use the cache at all. Unless we're actually
|
||||
// offline, which takes precedence over BYPASS_LOCAL_CACHE.
|
||||
if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
accessRequested = nsICache::ACCESS_READ;
|
||||
}
|
||||
else if (BYPASS_LOCAL_CACHE(mLoadFlags))
|
||||
accessRequested = nsICache::ACCESS_WRITE; // replace cache entry
|
||||
else
|
||||
accessRequested = nsICache::ACCESS_READ_WRITE; // normal browsing
|
||||
rv = DetermineCacheAccess(&accessRequested);
|
||||
if NS_FAILED(rv) return rv;
|
||||
|
||||
if (!mApplicationCache && mInheritApplicationCache) {
|
||||
// Pick up an application cache from the notification
|
||||
@ -1765,10 +1760,6 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
|
||||
nsCOMPtr<nsICacheSession> session;
|
||||
|
||||
// Will be set to true if we've found the right session, but need
|
||||
// to open the cache entry asynchronously.
|
||||
PRBool waitingForValidation = PR_FALSE;
|
||||
|
||||
// If we have an application cache, we check it first.
|
||||
if (mApplicationCache) {
|
||||
nsCAutoString appCacheClientID;
|
||||
@ -1784,107 +1775,217 @@ nsHttpChannel::OpenCacheEntry(PRBool offline, PRBool *delayed)
|
||||
getter_AddRefs(session));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we'll try to synchronously open the cache entry... however,
|
||||
// it may be in use and not yet validated, in which case we'll
|
||||
// try asynchronously opening the cache entry.
|
||||
//
|
||||
// We open with ACCESS_READ only, because we don't want to
|
||||
// overwrite the offline cache entry non-atomically.
|
||||
// ACCESS_READ will prevent us from writing to the offline
|
||||
// cache as a normal cache entry.
|
||||
rv = session->OpenCacheEntry(cacheKey,
|
||||
nsICache::ACCESS_READ, PR_FALSE,
|
||||
getter_AddRefs(mCacheEntry));
|
||||
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
accessRequested = nsICache::ACCESS_READ;
|
||||
waitingForValidation = PR_TRUE;
|
||||
rv = NS_OK;
|
||||
if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
|
||||
// must use synchronous open for LOAD_BYPASS_LOCAL_CACHE_IF_BUSY
|
||||
rv = session->OpenCacheEntry(cacheKey,
|
||||
nsICache::ACCESS_READ, PR_FALSE,
|
||||
getter_AddRefs(mCacheEntry));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCacheEntry->GetAccessGranted(&mCacheAccess);
|
||||
LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]",
|
||||
this, mCacheAccess));
|
||||
mLoadedFromApplicationCache = PR_TRUE;
|
||||
return NS_OK;
|
||||
} else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
LOG(("bypassing local cache since it is busy\n"));
|
||||
// Don't try to load normal cache entry
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
} else {
|
||||
mOnCacheEntryAvailableCallback =
|
||||
&nsHttpChannel::OnOfflineCacheEntryAvailable;
|
||||
// We open with ACCESS_READ only, because we don't want to
|
||||
// overwrite the offline cache entry non-atomically.
|
||||
// ACCESS_READ will prevent us from writing to the offline
|
||||
// cache as a normal cache entry.
|
||||
rv = session->AsyncOpenCacheEntry(cacheKey,
|
||||
nsICache::ACCESS_READ,
|
||||
this);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mAsyncCacheOpen = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) && !mCacheForOfflineUse && !mFallbackChannel) {
|
||||
// Check for namespace match.
|
||||
nsCOMPtr<nsIApplicationCacheNamespace> namespaceEntry;
|
||||
rv = mApplicationCache->GetMatchingNamespace
|
||||
(cacheKey, getter_AddRefs(namespaceEntry));
|
||||
// sync or async opening failed
|
||||
return OnOfflineCacheEntryAvailable(nsnull, nsICache::ACCESS_NONE,
|
||||
rv, PR_TRUE);
|
||||
}
|
||||
|
||||
return OpenNormalCacheEntry(PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
|
||||
nsCacheAccessMode aAccess,
|
||||
nsresult aEntryStatus,
|
||||
PRBool aIsSync)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (NS_SUCCEEDED(aEntryStatus)) {
|
||||
// We successfully opened an offline cache session and the entry,
|
||||
// so indicate we will load from the offline cache.
|
||||
mLoadedFromApplicationCache = PR_TRUE;
|
||||
mCacheEntry = aEntry;
|
||||
mCacheAccess = aAccess;
|
||||
}
|
||||
|
||||
if (mCanceled && NS_FAILED(mStatus)) {
|
||||
LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(aEntryStatus))
|
||||
// Called from OnCacheEntryAvailable, advance to the next state
|
||||
return Connect(PR_FALSE);
|
||||
|
||||
if (!mCacheForOfflineUse && !mFallbackChannel) {
|
||||
nsCAutoString cacheKey;
|
||||
GenerateCacheKey(mPostID, cacheKey);
|
||||
|
||||
// Check for namespace match.
|
||||
nsCOMPtr<nsIApplicationCacheNamespace> namespaceEntry;
|
||||
rv = mApplicationCache->GetMatchingNamespace
|
||||
(cacheKey, getter_AddRefs(namespaceEntry));
|
||||
if (NS_FAILED(rv) && !aIsSync)
|
||||
return Connect(PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 namespaceType = 0;
|
||||
if (!namespaceEntry ||
|
||||
NS_FAILED(namespaceEntry->GetItemType(&namespaceType)) ||
|
||||
(namespaceType &
|
||||
(nsIApplicationCacheNamespace::NAMESPACE_FALLBACK |
|
||||
nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC |
|
||||
nsIApplicationCacheNamespace::NAMESPACE_BYPASS)) == 0) {
|
||||
// When loading from an application cache, only items
|
||||
// on the whitelist or matching a
|
||||
// fallback/opportunistic namespace should hit the
|
||||
// network...
|
||||
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
|
||||
|
||||
// ... and if there were an application cache entry,
|
||||
// we would have found it earlier.
|
||||
return aIsSync ? NS_ERROR_CACHE_KEY_NOT_FOUND : Connect(PR_FALSE);
|
||||
}
|
||||
|
||||
if (namespaceType &
|
||||
nsIApplicationCacheNamespace::NAMESPACE_FALLBACK) {
|
||||
rv = namespaceEntry->GetData(mFallbackKey);
|
||||
if (NS_FAILED(rv) && !aIsSync)
|
||||
return Connect(PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 namespaceType = 0;
|
||||
if (!namespaceEntry ||
|
||||
NS_FAILED(namespaceEntry->GetItemType(&namespaceType)) ||
|
||||
(namespaceType &
|
||||
(nsIApplicationCacheNamespace::NAMESPACE_FALLBACK |
|
||||
nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC |
|
||||
nsIApplicationCacheNamespace::NAMESPACE_BYPASS)) == 0) {
|
||||
// When loading from an application cache, only items
|
||||
// on the whitelist or matching a
|
||||
// fallback/opportunistic namespace should hit the
|
||||
// network...
|
||||
mLoadFlags |= LOAD_ONLY_FROM_CACHE;
|
||||
|
||||
// ... and if there were an application cache entry,
|
||||
// we would have found it earlier.
|
||||
return NS_ERROR_CACHE_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (namespaceType &
|
||||
nsIApplicationCacheNamespace::NAMESPACE_FALLBACK) {
|
||||
rv = namespaceEntry->GetData(mFallbackKey);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if ((namespaceType &
|
||||
nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC) &&
|
||||
mLoadFlags & LOAD_DOCUMENT_URI) {
|
||||
// Document loads for items in an opportunistic namespace
|
||||
// should be placed in the offline cache.
|
||||
nsCString clientID;
|
||||
mApplicationCache->GetClientID(clientID);
|
||||
|
||||
mCacheForOfflineUse = !clientID.IsEmpty();
|
||||
SetOfflineCacheClientID(clientID);
|
||||
mCachingOpportunistically = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv)) {
|
||||
// We successfully opened an offline cache session and the entry,
|
||||
// now indiciate we load from the offline cache.
|
||||
mLoadedFromApplicationCache = PR_TRUE;
|
||||
|
||||
if ((namespaceType &
|
||||
nsIApplicationCacheNamespace::NAMESPACE_OPPORTUNISTIC) &&
|
||||
mLoadFlags & LOAD_DOCUMENT_URI) {
|
||||
// Document loads for items in an opportunistic namespace
|
||||
// should be placed in the offline cache.
|
||||
nsCString clientID;
|
||||
mApplicationCache->GetClientID(clientID);
|
||||
|
||||
mCacheForOfflineUse = !clientID.IsEmpty();
|
||||
SetOfflineCacheClientID(clientID);
|
||||
mCachingOpportunistically = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCacheEntry && !waitingForValidation) {
|
||||
rv = gHttpHandler->GetCacheSession(storagePolicy,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return OpenNormalCacheEntry(aIsSync);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OpenNormalCacheEntry(PRBool aIsSync)
|
||||
{
|
||||
NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCAutoString cacheKey;
|
||||
GenerateCacheKey(mPostID, cacheKey);
|
||||
|
||||
nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
|
||||
|
||||
nsCOMPtr<nsICacheSession> session;
|
||||
rv = gHttpHandler->GetCacheSession(storagePolicy,
|
||||
getter_AddRefs(session));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCacheAccessMode accessRequested;
|
||||
rv = DetermineCacheAccess(&accessRequested);
|
||||
if NS_FAILED(rv) return rv;
|
||||
|
||||
if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
|
||||
if (!aIsSync) {
|
||||
// Unexpected state: we were called from OnCacheEntryAvailable(),
|
||||
// so LOAD_BYPASS_LOCAL_CACHE_IF_BUSY shouldn't be set. Unless
|
||||
// somebody altered mLoadFlags between OpenCacheEntry() and
|
||||
// OnCacheEntryAvailable()...
|
||||
NS_WARNING(
|
||||
"OpenNormalCacheEntry() called from OnCacheEntryAvailable() "
|
||||
"when LOAD_BYPASS_LOCAL_CACHE_IF_BUSY was specified");
|
||||
}
|
||||
|
||||
// must use synchronous open for LOAD_BYPASS_LOCAL_CACHE_IF_BUSY
|
||||
rv = session->OpenCacheEntry(cacheKey, accessRequested, PR_FALSE,
|
||||
getter_AddRefs(mCacheEntry));
|
||||
if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
waitingForValidation = PR_TRUE;
|
||||
rv = NS_OK;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCacheEntry->GetAccessGranted(&mCacheAccess);
|
||||
LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]",
|
||||
this, mCacheAccess));
|
||||
}
|
||||
else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
LOG(("bypassing local cache since it is busy\n"));
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mOnCacheEntryAvailableCallback =
|
||||
&nsHttpChannel::OnNormalCacheEntryAvailable;
|
||||
rv = session->AsyncOpenCacheEntry(cacheKey, accessRequested, this);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mAsyncCacheOpen = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (waitingForValidation) {
|
||||
// access to the cache entry has been denied (because the
|
||||
// cache entry is probably in use by another channel).
|
||||
if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
|
||||
LOG(("bypassing local cache since it is busy\n"));
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
rv = session->AsyncOpenCacheEntry(cacheKey, accessRequested, this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
// we'll have to wait for the cache entry
|
||||
*delayed = PR_TRUE;
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv)) {
|
||||
mCacheEntry->GetAccessGranted(&mCacheAccess);
|
||||
LOG(("nsHttpChannel::OpenCacheEntry [this=%p grantedAccess=%d]", this, mCacheAccess));
|
||||
}
|
||||
if (!aIsSync)
|
||||
// Called from OnCacheEntryAvailable, advance to the next state
|
||||
rv = Connect(PR_FALSE);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
|
||||
nsCacheAccessMode aAccess,
|
||||
nsresult aEntryStatus,
|
||||
PRBool aIsSync)
|
||||
{
|
||||
NS_ASSERTION(!aIsSync, "aIsSync should be false");
|
||||
|
||||
if (NS_SUCCEEDED(aEntryStatus)) {
|
||||
mCacheEntry = aEntry;
|
||||
mCacheAccess = aAccess;
|
||||
}
|
||||
|
||||
if (mCanceled && NS_FAILED(mStatus)) {
|
||||
LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if ((mLoadFlags & LOAD_ONLY_FROM_CACHE) && NS_FAILED(aEntryStatus))
|
||||
// if this channel is only allowed to pull from the cache, then
|
||||
// we must fail if we were unable to open a cache entry.
|
||||
return NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
|
||||
// advance to the next state...
|
||||
return Connect(PR_FALSE);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::OpenOfflineCacheEntryForWriting()
|
||||
@ -2711,20 +2812,26 @@ nsHttpChannel::InstallCacheListener(PRUint32 offset)
|
||||
do_CreateInstance(kStreamListenerTeeCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICacheService> serv =
|
||||
do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> cacheIOTarget;
|
||||
serv->GetCacheIOTarget(getter_AddRefs(cacheIOTarget));
|
||||
|
||||
nsCacheStoragePolicy policy;
|
||||
rv = mCacheEntry->GetStoragePolicy(&policy);
|
||||
|
||||
if (!gHttpHandler->mCacheWriteThread ||
|
||||
NS_FAILED(rv) ||
|
||||
policy == nsICache::STORE_ON_DISK_AS_FILE) {
|
||||
LOG(("nsHttpChannel::InstallCacheListener sync tee %p\n", tee.get()));
|
||||
if (NS_FAILED(rv) || policy == nsICache::STORE_ON_DISK_AS_FILE ||
|
||||
!cacheIOTarget) {
|
||||
LOG(("nsHttpChannel::InstallCacheListener sync tee %p rv=%x policy=%d "
|
||||
"cacheIOTarget=%p", tee.get(), rv, policy, cacheIOTarget.get()));
|
||||
rv = tee->Init(mListener, out, nsnull);
|
||||
} else {
|
||||
LOG(("nsHttpChannel::InstallCacheListener async tee %p\n",
|
||||
tee.get()));
|
||||
rv = tee->InitAsync(mListener, gHttpHandler->mCacheWriteThread, out, nsnull);
|
||||
LOG(("nsHttpChannel::InstallCacheListener async tee %p", tee.get()));
|
||||
rv = tee->InitAsync(mListener, cacheIOTarget, out, nsnull);
|
||||
}
|
||||
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mListener = tee;
|
||||
return NS_OK;
|
||||
@ -4077,6 +4184,8 @@ nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
|
||||
nsCacheAccessMode access,
|
||||
nsresult status)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p "
|
||||
"access=%x status=%x]\n", this, entry, access, status));
|
||||
|
||||
@ -4085,28 +4194,24 @@ nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
|
||||
if (!mIsPending)
|
||||
return NS_OK;
|
||||
|
||||
// otherwise, we have to handle this event.
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
mCacheEntry = entry;
|
||||
mCacheAccess = access;
|
||||
}
|
||||
nsOnCacheEntryAvailableCallback callback = mOnCacheEntryAvailableCallback;
|
||||
mOnCacheEntryAvailableCallback = nsnull;
|
||||
|
||||
nsresult rv;
|
||||
NS_ASSERTION(callback,
|
||||
"nsHttpChannel::OnCacheEntryAvailable called without callback");
|
||||
rv = ((*this).*callback)(entry, access, status, PR_FALSE);
|
||||
|
||||
if (mCanceled && NS_FAILED(mStatus)) {
|
||||
LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
|
||||
rv = mStatus;
|
||||
}
|
||||
else if ((mLoadFlags & LOAD_ONLY_FROM_CACHE) && NS_FAILED(status))
|
||||
// if this channel is only allowed to pull from the cache, then
|
||||
// we must fail if we were unable to open a cache entry.
|
||||
rv = NS_ERROR_DOCUMENT_NOT_CACHED;
|
||||
else
|
||||
// advance to the next state...
|
||||
rv = Connect(PR_FALSE);
|
||||
|
||||
// a failure from Connect means that we have to abort the channel.
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("AsyncOpenCacheEntry failed [rv=%x]\n", rv));
|
||||
if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
|
||||
// If we have a fallback URI (and we're not already
|
||||
// falling back), process the fallback asynchronously.
|
||||
if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
|
||||
rv = AsyncCall(&nsHttpChannel::HandleAsyncFallback);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
CloseCacheEntry(PR_TRUE);
|
||||
AsyncAbort(rv);
|
||||
}
|
||||
@ -4573,6 +4678,27 @@ nsHttpChannel::DetermineStoragePolicy()
|
||||
return policy;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::DetermineCacheAccess(nsCacheAccessMode *_retval)
|
||||
{
|
||||
PRBool offline = gIOService->IsOffline();
|
||||
|
||||
if (offline || (mLoadFlags & INHIBIT_CACHING)) {
|
||||
// If we have been asked to bypass the cache and not write to the
|
||||
// cache, then don't use the cache at all. Unless we're actually
|
||||
// offline, which takes precedence over BYPASS_LOCAL_CACHE.
|
||||
if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
*_retval = nsICache::ACCESS_READ;
|
||||
}
|
||||
else if (BYPASS_LOCAL_CACHE(mLoadFlags))
|
||||
*_retval = nsICache::ACCESS_WRITE; // replace cache entry
|
||||
else
|
||||
*_retval = nsICache::ACCESS_READ_WRITE; // normal browsing
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::AsyncOnExamineCachedResponse()
|
||||
{
|
||||
|
@ -216,7 +216,16 @@ private:
|
||||
nsresult ResolveProxy();
|
||||
|
||||
// cache specific methods
|
||||
nsresult OpenCacheEntry(PRBool offline, PRBool *delayed);
|
||||
nsresult OpenCacheEntry();
|
||||
nsresult OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
|
||||
nsCacheAccessMode aAccess,
|
||||
nsresult aResult,
|
||||
PRBool aSync);
|
||||
nsresult OpenNormalCacheEntry(PRBool aSync);
|
||||
nsresult OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
|
||||
nsCacheAccessMode aAccess,
|
||||
nsresult aResult,
|
||||
PRBool aSync);
|
||||
nsresult OpenOfflineCacheEntryForWriting();
|
||||
nsresult GenerateCacheKey(PRUint32 postID, nsACString &key);
|
||||
nsresult UpdateExpirationTime();
|
||||
@ -234,6 +243,7 @@ private:
|
||||
nsresult InstallOfflineCacheListener();
|
||||
void MaybeInvalidateCacheEntryForSubsequentGet();
|
||||
nsCacheStoragePolicy DetermineStoragePolicy();
|
||||
nsresult DetermineCacheAccess(nsCacheAccessMode *_retval);
|
||||
void AsyncOnExamineCachedResponse();
|
||||
|
||||
// Handle the bogus Content-Encoding Apache sometimes sends
|
||||
@ -264,6 +274,11 @@ private:
|
||||
PRUint32 mPostID;
|
||||
PRUint32 mRequestTime;
|
||||
|
||||
typedef nsresult (nsHttpChannel:: *nsOnCacheEntryAvailableCallback)(
|
||||
nsICacheEntryDescriptor *, nsCacheAccessMode, nsresult, PRBool);
|
||||
nsOnCacheEntryAvailableCallback mOnCacheEntryAvailableCallback;
|
||||
PRBool mAsyncCacheOpen;
|
||||
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
|
||||
nsCacheAccessMode mOfflineCacheAccess;
|
||||
nsCString mOfflineCacheClientID;
|
||||
|
@ -294,14 +294,6 @@ nsHttpHandler::Init()
|
||||
rv = InitConnectionMgr();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewThread(getter_AddRefs(mCacheWriteThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
mCacheWriteThread = nsnull;
|
||||
LOG(("Failed creating cache-write thread - writes will be synchronous"));
|
||||
} else {
|
||||
LOG(("Created cache-write thread = %p", mCacheWriteThread.get()));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXULAppInfo> appInfo =
|
||||
do_GetService("@mozilla.org/xre/app-info;1");
|
||||
if (appInfo)
|
||||
@ -321,7 +313,6 @@ nsHttpHandler::Init()
|
||||
mObserverService->AddObserver(this, "profile-change-net-restore", PR_TRUE);
|
||||
mObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
|
||||
mObserverService->AddObserver(this, "net:clear-active-logins", PR_TRUE);
|
||||
mObserverService->AddObserver(this, "xpcom-shutdown-threads", PR_TRUE);
|
||||
}
|
||||
|
||||
StartPruneDeadConnectionsTimer();
|
||||
@ -1780,18 +1771,6 @@ nsHttpHandler::Observe(nsISupports *subject,
|
||||
else if (strcmp(topic, "net:clear-active-logins") == 0) {
|
||||
mAuthCache.ClearAll();
|
||||
}
|
||||
else if (strcmp(topic, "xpcom-shutdown-threads") == 0) {
|
||||
// Shutdown the cache write thread. This must be done after shutting down
|
||||
// the cache service, because the (memory) cache entries' storage streams
|
||||
// get released on the thread on which they were first written to, which
|
||||
// is this thread.
|
||||
if (mCacheWriteThread) {
|
||||
LOG((" shutting down cache-write thread...\n"));
|
||||
mCacheWriteThread->Shutdown();
|
||||
LOG((" cache-write thread shutdown complete\n"));
|
||||
mCacheWriteThread = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -210,8 +210,6 @@ public:
|
||||
static nsresult GenerateHostPort(const nsCString& host, PRInt32 port,
|
||||
nsCString& hostLine);
|
||||
|
||||
// The thread used to implement async cache-writes
|
||||
nsCOMPtr<nsIThread> mCacheWriteThread;
|
||||
private:
|
||||
|
||||
//
|
||||
|
@ -116,12 +116,6 @@ libs:: $(_MOD_PYWEBSOCKET_FILES)
|
||||
libs:: $(_HANDSHAKE_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(_DEST_DIR)/pywebsocket/mod_pywebsocket/handshake
|
||||
|
||||
runtests.py: runtests.py.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(DEFINES) $(ACDEFINES) $^ > $@
|
||||
|
||||
GARBAGE += runtests.py
|
||||
|
||||
libs:: $(_SERV_FILES)
|
||||
$(INSTALL) $^ $(_DEST_DIR)
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
|
||||
<!ENTITY % aboutAboutDTD SYSTEM "chrome://global/locale/aboutAbout.dtd" >
|
||||
%aboutAboutDTD;
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
]>
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -92,7 +94,7 @@
|
||||
]]></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body dir="&locale.dir;">
|
||||
<h1>&aboutAbout.title;</h1>
|
||||
<p><em>&aboutAbout.note;</em></p>
|
||||
<ul id="abouts" class="columns"></ul>
|
||||
|
@ -42,11 +42,7 @@
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
|
||||
|
||||
nsMIMEInfoAndroid::~nsMIMEInfoAndroid()
|
||||
{
|
||||
}
|
||||
NS_IMPL_ISUPPORTS1(nsMIMEInfoAndroid, nsIMIMEInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
|
||||
@ -67,24 +63,29 @@ nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMIMEInfo>
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
|
||||
if (!bridge) {
|
||||
// we don't have access to the bridge, so just assume we can handle
|
||||
// the protocol for now and let the system deal with it
|
||||
return new nsMIMEInfoAndroid(aMimeType);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
|
||||
nsMIMEInfoAndroid** aMimeInfo)
|
||||
{
|
||||
nsRefPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
|
||||
mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
|
||||
// we don't have access to the bridge, so just assume we can handle
|
||||
// the mime type for now and let the system deal with it
|
||||
if (!bridge){
|
||||
info.forget(aMimeInfo);
|
||||
return PR_TRUE;
|
||||
}
|
||||
nsStringArray stringArray;
|
||||
bridge->GetHandlersForMimeType(nsCAutoString(aMimeType).get(), &stringArray);
|
||||
|
||||
nsString empty = EmptyString();
|
||||
PRInt32 len = stringArray.Count();
|
||||
if (len == 0)
|
||||
return nsnull;
|
||||
nsCOMPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
|
||||
if (len == 0) {
|
||||
info.forget(aMimeInfo);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
for (jsize i = 0; i < len; i+=4) {
|
||||
nsAndroidHandlerApp* app =
|
||||
new nsAndroidHandlerApp(*stringArray[i], empty, *stringArray[i + 2],
|
||||
@ -93,19 +94,20 @@ nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType)
|
||||
if (stringArray[i + 1] > 0)
|
||||
info->mPrefApp = app;
|
||||
}
|
||||
nsCOMPtr<nsIMIMEInfo> ret = do_QueryInterface(info);
|
||||
return ret.forget();
|
||||
|
||||
info.forget(aMimeInfo);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIMIMEInfo>
|
||||
nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt)
|
||||
|
||||
PRBool
|
||||
nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt,
|
||||
nsMIMEInfoAndroid **aMimeInfo)
|
||||
{
|
||||
if (!mozilla::AndroidBridge::Bridge())
|
||||
return nsnull;
|
||||
nsCString mimeType;
|
||||
mozilla::AndroidBridge::Bridge()->GetMimeTypeFromExtension(nsCString(aFileExt), mimeType);
|
||||
|
||||
return GetMimeInfoForMimeType(mimeType);
|
||||
if (mozilla::AndroidBridge::Bridge())
|
||||
mozilla::AndroidBridge::Bridge()->
|
||||
GetMimeTypeFromExtension(aFileExt, mimeType);
|
||||
return GetMimeInfoForMimeType(mimeType, aMimeInfo);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -116,11 +118,13 @@ nsMIMEInfoAndroid::GetMimeInfoForProtocol(const nsACString &aScheme,
|
||||
const nsString &empty = EmptyString();
|
||||
const nsCString &emptyC = EmptyCString();
|
||||
mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
|
||||
nsMIMEInfoAndroid *mimeinfo = new nsMIMEInfoAndroid(emptyC);
|
||||
NS_ADDREF(*info = mimeinfo);
|
||||
*found = PR_TRUE;
|
||||
|
||||
if (!bridge) {
|
||||
// we don't have access to the bridge, so just assume we can handle
|
||||
// the protocol for now and let the system deal with it
|
||||
*found = PR_TRUE;
|
||||
*info = new nsMIMEInfoAndroid(emptyC);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -130,21 +134,20 @@ nsMIMEInfoAndroid::GetMimeInfoForProtocol(const nsACString &aScheme,
|
||||
|
||||
PRInt32 len = stringArray.Count();
|
||||
if (len == 0) {
|
||||
// Code that calls this requires an object regardless if the OS has
|
||||
// something for us, so we return the empty object.
|
||||
*found = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
*found = PR_TRUE;
|
||||
nsMIMEInfoAndroid *mimeinfo = new nsMIMEInfoAndroid(emptyC);
|
||||
|
||||
for (jsize i = 0; i < len; i+=4) {
|
||||
nsAndroidHandlerApp* app =
|
||||
new nsAndroidHandlerApp(*stringArray[i], empty, *stringArray[i + 2],
|
||||
*stringArray[i + 3], emptyC);
|
||||
mimeinfo->mHandlerApps->AppendElement(app, PR_FALSE);
|
||||
if (!stringArray[i + 1]->IsEmpty()) {
|
||||
if (!stringArray[i + 1]->IsEmpty())
|
||||
mimeinfo->mPrefApp = app;
|
||||
}
|
||||
}
|
||||
*info = mimeinfo;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -382,10 +385,9 @@ nsMIMEInfoAndroid::LaunchWithFile(nsIFile *aFile)
|
||||
|
||||
nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType) :
|
||||
mMimeType(aMIMEType), mAlwaysAsk(PR_TRUE),
|
||||
mPrefAction(nsIMIMEInfo::useHelperApp),
|
||||
mSystemChooser(this)
|
||||
mPrefAction(nsIMIMEInfo::useHelperApp)
|
||||
{
|
||||
mPrefApp = &mSystemChooser;
|
||||
mPrefApp = new nsMIMEInfoAndroid::SystemChooser(this);
|
||||
nsresult rv;
|
||||
mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
|
||||
mHandlerApps->AppendElement(mPrefApp, PR_FALSE);
|
||||
|
@ -44,18 +44,21 @@
|
||||
class nsMIMEInfoAndroid : public nsIMIMEInfo
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<nsIMIMEInfo> GetMimeInfoForMimeType(const nsACString& aMimeType);
|
||||
static already_AddRefed<nsIMIMEInfo> GetMimeInfoForFileExt(const nsACString& aFileExt);
|
||||
static nsresult GetMimeInfoForProtocol(const nsACString &aScheme,
|
||||
PRBool *found,
|
||||
nsIHandlerInfo **info);
|
||||
static PRBool
|
||||
GetMimeInfoForMimeType(const nsACString& aMimeType,
|
||||
nsMIMEInfoAndroid** aMimeInfo);
|
||||
static PRBool
|
||||
GetMimeInfoForFileExt(const nsACString& aFileExt,
|
||||
nsMIMEInfoAndroid** aMimeInfo);
|
||||
static nsresult
|
||||
GetMimeInfoForProtocol(const nsACString &aScheme, PRBool *found,
|
||||
nsIHandlerInfo **info);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMIMEINFO
|
||||
NS_DECL_NSIHANDLERINFO
|
||||
private:
|
||||
|
||||
nsMIMEInfoAndroid(const nsACString& aMIMEType);
|
||||
virtual ~nsMIMEInfoAndroid();
|
||||
|
||||
protected:
|
||||
virtual NS_HIDDEN_(nsresult) LaunchDefaultWithFile(nsIFile* aFile);
|
||||
@ -78,7 +81,6 @@ protected:
|
||||
nsMIMEInfoAndroid* mOuter;
|
||||
|
||||
};
|
||||
SystemChooser mSystemChooser;
|
||||
};
|
||||
|
||||
#endif /* nsMIMEInfoAndroid_h */
|
||||
|
@ -52,19 +52,23 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt,
|
||||
PRBool* aFound)
|
||||
{
|
||||
// XXX Bug 579388 - need to remote this
|
||||
if (!mozilla::AndroidBridge::Bridge())
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<nsMIMEInfoAndroid> mimeInfo;
|
||||
*aFound = PR_FALSE;
|
||||
already_AddRefed<nsIMIMEInfo> mimeInfo =
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(aMIMEType);
|
||||
if (!mimeInfo.get())
|
||||
mimeInfo = nsMIMEInfoAndroid::GetMimeInfoForFileExt(aFileExt);
|
||||
if (!aMIMEType.IsEmpty())
|
||||
*aFound =
|
||||
nsMIMEInfoAndroid::GetMimeInfoForMimeType(aMIMEType,
|
||||
getter_AddRefs(mimeInfo));
|
||||
if (!*aFound)
|
||||
*aFound =
|
||||
nsMIMEInfoAndroid::GetMimeInfoForFileExt(aFileExt,
|
||||
getter_AddRefs(mimeInfo));
|
||||
|
||||
*aFound = !!mimeInfo.get();
|
||||
|
||||
return mimeInfo;
|
||||
// Code that calls this requires an object regardless if the OS has
|
||||
// something for us, so we return the empty object.
|
||||
if (!*aFound)
|
||||
mimeInfo = new nsMIMEInfoAndroid(aMIMEType);
|
||||
|
||||
return mimeInfo.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -456,6 +456,22 @@ static nsresult GetDownloadDirectory(nsIFile **_directory)
|
||||
getter_AddRefs(dir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
#elif defined(ANDROID)
|
||||
char* sdcard = getenv("EXTERNAL_STORAGE");
|
||||
nsresult rv;
|
||||
if (sdcard) {
|
||||
nsCOMPtr<nsILocalFile> ldir;
|
||||
rv = NS_NewNativeLocalFile(nsDependentCString(sdcard),
|
||||
PR_TRUE, getter_AddRefs(ldir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
dir = ldir;
|
||||
|
||||
}
|
||||
else {
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
#else
|
||||
// On all other platforms, we default to the systems temporary directory.
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dir));
|
||||
|
@ -343,7 +343,7 @@ AndroidBridge::OpenUriExternal(const nsACString& aUriSpec, const nsACString& aMi
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::GetMimeTypeFromExtension(const nsCString& aFileExt, nsCString& aMimeType) {
|
||||
AndroidBridge::GetMimeTypeFromExtension(const nsACString& aFileExt, nsCString& aMimeType) {
|
||||
AutoLocalJNIFrame jniFrame;
|
||||
NS_ConvertUTF8toUTF16 wFileExt(aFileExt);
|
||||
jstring jstrExt = mJNIEnv->NewString(wFileExt.get(), wFileExt.Length());
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
const nsAString& aPackageName = EmptyString(),
|
||||
const nsAString& aClassName = EmptyString());
|
||||
|
||||
void GetMimeTypeFromExtension(const nsCString& aFileExt, nsCString& aMimeType);
|
||||
void GetMimeTypeFromExtension(const nsACString& aFileExt, nsCString& aMimeType);
|
||||
|
||||
void MoveTaskToBack();
|
||||
|
||||
|
@ -448,8 +448,9 @@ nsJNIString::nsJNIString(jstring jstr)
|
||||
return;
|
||||
}
|
||||
const jchar* jCharPtr = JNI()->GetStringChars(jstr, false);
|
||||
int len = JNI()->GetStringLength(jstr);
|
||||
nsresult rv;
|
||||
Assign(jCharPtr);
|
||||
Assign(jCharPtr, len);
|
||||
JNI()->ReleaseStringChars(jstr, jCharPtr);
|
||||
|
||||
}
|
||||
|
@ -79,6 +79,8 @@
|
||||
#include "nsPrintSession.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(ChildWindow)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
|
||||
@ -91,7 +93,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
|
||||
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
|
||||
using namespace mozilla::widget;
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(WinTaskbar)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListBuilder)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(JumpListItem)
|
||||
|
@ -222,6 +222,7 @@ nsWindow::nsWindow() : nsBaseWidget()
|
||||
mOnDestroyCalled = PR_FALSE;
|
||||
mIsDestroying = PR_FALSE;
|
||||
mInSetFocus = PR_FALSE;
|
||||
mNoPaint = PR_FALSE;
|
||||
mDragHps = 0;
|
||||
mDragStatus = 0;
|
||||
mClipWnd = 0;
|
||||
@ -399,6 +400,15 @@ NS_METHOD nsWindow::Create(nsIWidget* aParent,
|
||||
if (aInitData) {
|
||||
mWindowType = aInitData->mWindowType;
|
||||
mBorderStyle = aInitData->mBorderStyle;
|
||||
|
||||
// Suppress creation of a Thebes surface for windows that will never
|
||||
// be painted because they're always covered by another window.
|
||||
if (mWindowType == eWindowType_toplevel ||
|
||||
mWindowType == eWindowType_invisible ||
|
||||
(mWindowType == eWindowType_child &&
|
||||
aInitData->mContentType == eContentTypeContent)) {
|
||||
mNoPaint = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// For toplevel windows, create an instance of our helper class,
|
||||
@ -701,6 +711,19 @@ gfxASurface* nsWindow::GetThebesSurface()
|
||||
return mThebesSurface;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal-only method that suppresses creation of a Thebes surface
|
||||
// for windows that aren't supposed to be visible. If one was created
|
||||
// by an external call to GetThebesSurface(), it will be returned.
|
||||
|
||||
gfxASurface* nsWindow::ConfirmThebesSurface()
|
||||
{
|
||||
if (!mThebesSurface && !mNoPaint && mWnd) {
|
||||
mThebesSurface = new gfxOS2Surface(mWnd);
|
||||
}
|
||||
return mThebesSurface;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Return some native data according to aDataType.
|
||||
|
||||
@ -1970,12 +1993,10 @@ PRBool nsWindow::OnReposition(PSWP pSwp)
|
||||
mBounds.width = pSwp->cx;
|
||||
mBounds.height = pSwp->cy;
|
||||
|
||||
// Resize the thebes surface to the new size. The first time we do
|
||||
// a resize, we may need to create a thebes surface for the window.
|
||||
if (!mThebesSurface) {
|
||||
mThebesSurface = new gfxOS2Surface(mWnd);
|
||||
// If the window is supposed to have a thebes surface, resize it.
|
||||
if (ConfirmThebesSurface()) {
|
||||
mThebesSurface->Resize(gfxIntSize(mBounds.width, mBounds.height));
|
||||
}
|
||||
mThebesSurface->Resize(gfxIntSize(mBounds.width, mBounds.height));
|
||||
|
||||
result = DispatchResizeEvent(mBounds.width, mBounds.height);
|
||||
}
|
||||
@ -2026,8 +2047,16 @@ do {
|
||||
WinQueryUpdateRegion(mWnd, hrgn);
|
||||
WinBeginPaint(mWnd, hPS, &rcl);
|
||||
|
||||
// Exit if the update rect is empty or mThebesSurface is null.
|
||||
if (WinIsRectEmpty(0, &rcl) || !GetThebesSurface()) {
|
||||
// Exit if the update rect is empty.
|
||||
if (WinIsRectEmpty(0, &rcl)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Exit if a thebes surface can not/should not be created,
|
||||
// but first fill the area with the default background color
|
||||
// to erase any visual artifacts.
|
||||
if (!ConfirmThebesSurface()) {
|
||||
WinDrawBorder(hPS, &rcl, 0, 0, 0, 0, DB_INTERIOR | DB_AREAATTRS);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2044,6 +2073,15 @@ do {
|
||||
nsRefPtr<gfxContext> thebesContext = new gfxContext(mThebesSurface);
|
||||
thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
|
||||
|
||||
// Intersect the update region with the paint rectangle to clip areas
|
||||
// that aren't visible (e.g. offscreen or covered by another window).
|
||||
HRGN hrgnPaint;
|
||||
hrgnPaint = GpiCreateRegion(hPS, 1, &rcl);
|
||||
if (hrgnPaint) {
|
||||
GpiCombineRegion(hPS, hrgn, hrgn, hrgnPaint, CRGN_AND);
|
||||
GpiDestroyRegion(hPS, hrgnPaint);
|
||||
}
|
||||
|
||||
// See how many rects comprise the update region. If there are 8
|
||||
// or fewer, update them individually. If there are more or the call
|
||||
// failed, update the bounding rectangle returned by WinBeginPaint().
|
||||
|
@ -228,6 +228,7 @@ protected:
|
||||
HWND aParentWnd,
|
||||
const nsIntRect& aRect,
|
||||
nsWidgetInitData* aInitData);
|
||||
gfxASurface* ConfirmThebesSurface();
|
||||
HWND GetMainWindow();
|
||||
static nsWindow* GetNSWindowPtr(HWND aWnd);
|
||||
static PRBool SetNSWindowPtr(HWND aWnd, nsWindow* aPtr);
|
||||
@ -286,6 +287,7 @@ protected:
|
||||
PRInt32 mWindowState; // current nsWindowState_* value
|
||||
PRBool mIsDestroying; // in destructor
|
||||
PRBool mInSetFocus; // prevent recursive calls
|
||||
PRBool mNoPaint; // true if window is never visible
|
||||
HPS mDragHps; // retrieved by DrgGetPS() during a drag
|
||||
PRUint32 mDragStatus; // set when object is being dragged over
|
||||
HWND mClipWnd; // used to clip plugin windows
|
||||
|
@ -193,12 +193,14 @@ nsUXThemeData::GetThemeDLL() {
|
||||
return sThemeDLL;
|
||||
}
|
||||
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
HMODULE
|
||||
nsUXThemeData::GetDwmDLL() {
|
||||
if (!sDwmDLL && sIsVistaOrLater)
|
||||
sDwmDLL = ::LoadLibraryW(kDwmLibraryName);
|
||||
return sDwmDLL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const wchar_t *nsUXThemeData::GetClassName(nsUXThemeClass cls) {
|
||||
switch(cls) {
|
||||
|
@ -121,7 +121,9 @@ public:
|
||||
static void Invalidate();
|
||||
static HANDLE GetTheme(nsUXThemeClass cls);
|
||||
static HMODULE GetThemeDLL();
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
static HMODULE GetDwmDLL();
|
||||
#endif
|
||||
|
||||
// nsWindow calls this to update desktop settings info
|
||||
static void InitTitlebarInfo();
|
||||
|
Loading…
Reference in New Issue
Block a user