This commit is contained in:
Dan Witte 2010-08-21 13:51:54 -07:00
commit 72137223d8
37 changed files with 988 additions and 942 deletions

View File

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

View File

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

View File

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

View File

@ -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";
}

View File

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

View File

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

View File

@ -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 */

View File

@ -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 */
};

View File

@ -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 */

View File

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

View File

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

View File

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

View File

@ -54,6 +54,7 @@ class nsCacheRequest : public PRCList
private:
friend class nsCacheService;
friend class nsCacheEntry;
friend class nsProcessRequestEvent;
nsCacheRequest( nsCString * key,
nsICacheListener * listener,

View File

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

View File

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

View File

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

View File

@ -275,6 +275,8 @@ private:
nsInterfaceHashtable<nsCStringHashKey, nsIWeakReference> mCaches;
nsClassHashtable<nsCStringHashKey, nsCString> mActiveCachesByGroup;
nsCStringHashSet mActiveCaches;
nsCOMPtr<nsIThread> mInitThread;
};
#endif // nsOfflineCacheDevice_h__

View File

@ -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++

View File

@ -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()
{

View File

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

View File

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

View File

@ -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:
//

View File

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

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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().

View File

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

View File

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

View File

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