Merge mozilla-central to tracemonkey.

This commit is contained in:
Robert Sayre 2009-04-09 21:24:00 -04:00
commit c05dbc60ec
204 changed files with 4628 additions and 5951 deletions

View File

@ -217,7 +217,6 @@ ACCESSIBILITY_ATOM(aria_busy, "aria-busy")
ACCESSIBILITY_ATOM(aria_checked, "aria-checked")
ACCESSIBILITY_ATOM(aria_controls, "aria-controls")
ACCESSIBILITY_ATOM(aria_describedby, "aria-describedby")
ACCESSIBILITY_ATOM(aria_droppable, "aria-droppable")
ACCESSIBILITY_ATOM(aria_disabled, "aria-disabled")
ACCESSIBILITY_ATOM(aria_dropeffect, "aria-dropeffect")
ACCESSIBILITY_ATOM(aria_expanded, "aria-expanded")

View File

@ -1131,8 +1131,7 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
if (aAttribute == nsAccessibilityAtoms::role ||
aAttribute == nsAccessibilityAtoms::href ||
aAttribute == nsAccessibilityAtoms::onclick ||
aAttribute == nsAccessibilityAtoms::aria_droppable) {
aAttribute == nsAccessibilityAtoms::onclick) {
// Not worth the expense to ensure which namespace these are in
// It doesn't kill use to recreate the accessible even if the attribute was used
// in the wrong namespace or an element that doesn't support it

View File

@ -96,6 +96,12 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
display: none;
}
/* Bug 483950 - Hide domain name in status bar pending removal */
#security-button > label {
display: none;
}
/* ::::: Fullscreen pseudo-toolbar ::::: */
#fullscr-toggler {
display: none;

View File

@ -901,10 +901,6 @@ var PlacesSearchBox = {
//scopeBtn.label = PlacesOrganizer._places.selectedNode.title;
break;
case "bookmarks":
// Make sure we're getting uri results.
// We do not yet support searching into grouped queries or into
// tag containers, so we must fall to the default case.
currentOptions.resultType = currentOptions.RESULT_TYPE_URI;
content.applyFilter(filterString, this.folders);
break;
case "history":
@ -912,6 +908,8 @@ var PlacesSearchBox = {
var query = PlacesUtils.history.getNewQuery();
query.searchTerms = filterString;
var options = currentOptions.clone();
// Make sure we're getting uri results.
options.resultType = currentOptions.RESULT_TYPE_URI;
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
content.load([query], options);
}

View File

@ -95,6 +95,14 @@
var queryNode = asQuery(this.getResultNode());
var options = queryNode.queryOptions.clone();
// Make sure we're getting uri results.
// We do not yet support searching into grouped queries or into
// tag containers, so we must fall to the default case.
if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
options.resultType == options.RESULTS_AS_TAG_QUERY ||
options.resultType == options.RESULTS_AS_TAG_CONTENTS)
options.resultType = options.RESULT_TYPE_URI;
var query = PlacesUtils.history.getNewQuery();
query.searchTerms = filterString;

View File

@ -59,6 +59,8 @@
* 6. if folder scope was clicked, searches again and ensures folder scope
* remains selected.
*/
const TEST_URL = "http://dummy.mozilla.org/";
// Add your tests here. Each is a function that's called by testHelper().
var testCases = [
@ -66,7 +68,7 @@ var testCases = [
// All Bookmarks
function () {
var defScope = getDefaultScope(PlacesUIUtils.allBookmarksFolderId);
search(PlacesUIUtils.allBookmarksFolderId, "dummy search", defScope);
search(PlacesUIUtils.allBookmarksFolderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
"Folder scope should be disabled for All Bookmarks");
resetSearch(defScope);
@ -75,7 +77,7 @@ var testCases = [
// History
function () {
defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["History"]);
search(PlacesUIUtils.leftPaneQueries["History"], "dummy search", defScope);
search(PlacesUIUtils.leftPaneQueries["History"], "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
"Folder scope should be disabled for History");
resetSearch(defScope);
@ -84,13 +86,13 @@ var testCases = [
// Toolbar folder
function () {
defScope = getDefaultScope(bmsvc.toolbarFolder);
search(bmsvc.toolbarFolder, "dummy search", defScope);
search(bmsvc.toolbarFolder, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
"Folder scope should be enabled for toolbar folder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(bmsvc.toolbarFolder, "dummy search", "scopeBarFolder");
search(bmsvc.toolbarFolder, "dummy", "scopeBarFolder");
},
// A regular non-root subfolder
@ -99,13 +101,13 @@ var testCases = [
"dummy folder",
bmsvc.DEFAULT_INDEX);
defScope = getDefaultScope(folderId);
search(folderId, "dummy search", defScope);
search(folderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
"Folder scope should be enabled for regular subfolder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(folderId, "dummy search", "scopeBarFolder");
search(folderId, "dummy", "scopeBarFolder");
bmsvc.removeItem(folderId);
},
];
@ -219,6 +221,15 @@ function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
"Content tree's searchTerms should be text in search box");
is(doc.getElementById("searchModifiers").hidden, false,
"Scope bar should not be hidden after searching");
if (getSelectedScopeButtonId() == "scopeBarHistory" ||
getSelectedScopeButtonId() == "scopeBarAll" ||
aFolderId == PlacesUtils.bookmarks.unfiledBookmarksFolder) {
// Check that search has returned a valid result.
contentTree.view.selection.select(0);
var foundNode = contentTree.selectedNode;
isnot(foundNode, null, "Found a valid node");
is(foundNode.uri, TEST_URL);
}
}
else {
is(query.hasSearchTerms, false,
@ -260,6 +271,12 @@ function testHelper(aLibraryWin) {
libraryWin = aLibraryWin;
testCases.forEach(function (aTest) aTest());
aLibraryWin.close();
// Cleanup.
PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.unfiledBookmarksFolder);
PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
finish();
}
@ -268,6 +285,18 @@ function testHelper(aLibraryWin) {
function test() {
waitForExplicitFinish();
// Sanity:
ok(PlacesUtils, "PlacesUtils in context");
// Add a visit, a bookmark and a tag.
PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URL),
Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_TYPED, false, 0);
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.unfiledBookmarksFolder,
PlacesUtils._uri(TEST_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"dummy");
PlacesUtils.tagging.tagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);

View File

@ -75,7 +75,7 @@
* locale/browser/netError.dtd (%chrome/overrides/netError.dtd)
* locale/browser/appstrings.properties (%chrome/overrides/appstrings.properties)
* locale/browser/downloads/settingsChange.dtd (%chrome/overrides/settingsChange.dtd)
% override chrome://global/locale/netErrorApp.dtd chrome://browser/locale/netError.dtd
% override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
% override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
% override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
#ifdef MOZ_USE_GENERIC_BRANDING

View File

@ -1293,6 +1293,7 @@ tabpanels {
.tabs-closebutton {
list-style-image: url("moz-icon://stock/gtk-close?size=menu");
border: none;
margin-bottom: 1px;
}
.tabs-closebutton > .toolbarbutton-icon {

View File

@ -247,6 +247,7 @@ user_pref("security.default_personal_cert", "Select Automatically"); // Need to
user_pref("network.http.prompt-temp-redirect", false);
user_pref("svg.smil.enabled", true); // Needed for SMIL mochitests until bug 482402 lands
user_pref("media.cache_size", 100);
user_pref("security.warn_viewing_mixed", false);
user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
"""

View File

@ -0,0 +1,368 @@
# ***** 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 build system.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# John Wolfe <wolfe@lobo.us>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
################################################################
#
# make-wince-cab.py --- Given a directory, walk it and make an
# installer based upon the contents of that directory
#
# Usage: python make-wince-inf.py CABWIZ_PATH SOURCE_DIR PROGRAM_NAME CAB_FINAL_NAME
#
# Walk through the relative directory SOURCE_DIR, parsing filenames
# Checks for duplicate filenames and renames where needed
# Then builds a WinMobile INF file based upon results
#
# Each directory in SOURCE_DIR may have a file named
# 'install-exceptions', which lists files in SOURCE_DIR that
# need not be placed into an installation CAB file. The
# 'install-exceptions' file itself is always ignored.
#
# Blank lines and '#' comments in the 'install-exceptions' file are
# ignored.
#
# EXAMPLE OF COMMAND LINE:
# python make_wince_inf.py /c/Program\ Files/Microsoft\ Visual\ Studio\ 9.0/SmartDevices/SDK/SDKTools/cabwiz.exe dist/fennec Fennec fennec-0.11.en-US.wince-arm.cab
#
# ARGS:
# cabiz_path - Path to CABWIZ.EXE executable inside Visual Studio
#
# source_dir - sub-directory which contains the target program
# NOTE: It is assumed that the application name is SOURCE_DIR.exe
# EXAMPLE: source_dir=fennec, there should be a fennec/fennec.exe application
#
# program_name - Name of the program to place inside the INF file
#
# cab_final_name - actual final name for the produced CAB file
#
# NOTE: In our example, "fennec" is the directory [source_name]
# "fennec.exe" is the application [$(source_name).exe], and
# "Fennec" is the shortcut name [program_name]
################################################################
import sys
import os
from os.path import join
from subprocess import call, STDOUT
import fnmatch
import string
import shutil
class FileEntry:
def __init__(self, dirpath, dircount, filename, filecount, actual_filename):
self.dirpath = dirpath
self.dircount = dircount
self.filename = filename
self.filecount = filecount
self.actual_filename = actual_filename
class DirEntry:
def __init__(self, dirpath, dircount, filecount):
self.dirpath = dirpath
self.dircount = dircount
self.filecount = filecount
# Ignore detritus left lying around by editing tools.
ignored_patterns = ['*~', '.#*', '#*#', '*.orig', '*.rej']
file_entry_count = 0
file_entries = []
fcount = 0
fnames = {}
directories = {}
files_in_directory = []
# Return the contents of FILENAME, a 'install-exceptions' file, as
# a dictionary whose keys are exactly the list of filenames, along
# with the basename of FILENAME itself. If FILENAME does not exist,
# return the empty dictionary.
def read_exceptions(filename):
exceptions = set()
if os.path.exists(filename):
f = file(filename)
for line in f:
line = line.strip()
if line and line[0] != '#':
exceptions.add(line)
exceptions.add( os.path.basename(filename) )
f.close()
return exceptions
# Sorts two items based first upon directory count (index of
# directory in list of directories), then upon filename. A way of
# getting a list sorted into directories, and then alphabetically by
# filename within each directory.
def sort_dircount_then_filename(item1, item2):
# First Compare dirpaths
if item1.dircount != item2.dircount:
return cmp(item1.dircount, item2.dircount)
# Next compare filenames
next_result = cmp(item1.filename, item2.filename)
if next_result != 0:
return next_result
# Lastly, compare filecounts
return cmp(item1.filecount, item2.filecount)
def handle_duplicate_filename(dirpath, filename, filecount):
if filecount == 1:
return filename
file_parts = os.path.splitext(filename)
new_filename = "%s_%d%s" % (file_parts[0], filecount, file_parts[1])
old_relative_filename = join(dirpath, filename)
new_relative_filename = join(dirpath, new_filename)
shutil.copyfile(old_relative_filename, new_relative_filename)
return new_filename
def add_new_entry(dirpath, dircount, filename, filecount):
global file_entries
global file_entry_count
actual_filename = handle_duplicate_filename(dirpath, filename, filecount)
file_entries.append( FileEntry(dirpath, dircount, filename, filecount, actual_filename) )
file_entry_count += 1
def walk_tree(start_dir, ignore):
global fcount
global fnames
global directories
global files_in_directory
dircount = 0;
files_in_directory = [0]
for (dirpath, dirnames, filenames) in os.walk(start_dir):
exceptions = read_exceptions(join(dirpath, 'install-exceptions'))
dircount += 1
directories[dirpath] = DirEntry(dirpath, dircount, len(filenames))
if len(filenames) < 1:
print "WARNING: No files in directory [%s]" % dirpath
for filename in filenames:
if len(exceptions) > 0 and filename in exceptions:
continue
if any(fnmatch.fnmatch(filename, p) for p in ignore):
continue
filecount = 1
if filename in fnames:
filecount = fnames[filename] + 1
fnames[filename] = filecount
add_new_entry(dirpath, dircount, filename, filecount)
def output_inf_file_header(f, program_name):
f.write("""; Duplicated Filenames ==> One of the two files
; needs renaming before packaging up the CAB
;
; Technique: Rename the second directory's file to XXXX_1 prior to starting the CABWIZ,
; then take care of the name in the File.xxxxx section
[Version]
Signature = "$Windows NT$" ; required as-is
Provider = "Mozilla" ; maximum of 30 characters, full app name will be \"<Provider> <AppName>\"
CESignature = "$Windows CE$" ; required as-is
[CEStrings]
AppName = "%s" ; maximum of 40 characters, full app name will be \"<Provider> <AppName>\"\n""" % program_name)
f.write("InstallDir = %CE1%\\%AppName% ; Program Files\Fennec\n\n")
def output_sourcedisksnames_section(f, dirs):
f.write("[SourceDisksNames] ; directory that holds the application's files\n")
for dir in dirs:
f.write("""%d = , "%s",,%s\n""" % (directories[dir].dircount, dir, dir))
f.write(" \n")
def output_sourcedisksfiles_section(f):
f.write("[SourceDisksFiles] ; list of files to be included in .cab\n")
for entry in sorted(file_entries, sort_dircount_then_filename):
f.write("%s=%d\n" % (entry.actual_filename, entry.dircount))
f.write("\n")
def output_defaultinstall_section(f, dirs):
copyfileslist = ""
copyfilesrawlist=[]
for dir in dirs:
if directories[dir].filecount < 1:
continue
copyfilesrawlist.append( "Files.%s" % '.'.join( dir.split('\\') ) )
prefix = ", "
copyfileslist = ','.join(copyfilesrawlist)
f.write("""[DefaultInstall] ; operations to be completed during install
CopyFiles = %s
AddReg = RegData
CEShortcuts = Shortcuts
\n""" % copyfileslist)
def output_destinationdirs_section(f, dirs):
f.write("[DestinationDirs] ; default destination directories for each operation section\n")
for dir in dirs:
dir_split = dir.split('\\')
mod_dir_string = '.'.join(dir_split)
if len(dir_split) > 1:
dir_minus_top_level = '\\'.join(dir_split[1:])
else:
dir_minus_top_level = ""
if dir_minus_top_level:
dir_minus_top_level = "\\%s" % dir_minus_top_level
if directories[dir].filecount < 1:
f.write(";Files.%s = 0, %%InstallDir%%%s ; NO FILES IN THIS DIRECTORY\n" % (mod_dir_string, dir_minus_top_level))
else:
f.write("Files.%s = 0, %%InstallDir%%%s\n" % (mod_dir_string, dir_minus_top_level))
f.write("Shortcuts = 0, %CE11% ; \Windows\Start Menu\Programs\n\n")
def output_directory_sections(f, dirs):
for dir in dirs:
if directories[dir].filecount < 1:
f.write(";[Files.%s]\n;===NO FILES===\n" % '.'.join( dir.split('\\') ))
else:
f.write("[Files.%s]\n" % '.'.join( dir.split('\\') ))
for entry in file_entries:
if entry.dirpath == dir:
f.write("\"%s\",%s\n" % (entry.filename, entry.actual_filename))
f.write("\n")
def output_registry_section(f):
f.write("""[RegData] ; registry key list
HKCU,Software\%AppName%,MajorVersion,0x00010001,1
HKCU,Software\%AppName%,MinorVersion,0x00010001,0
\n""")
def output_shortcuts_section(f, app_name):
f.write("[Shortcuts] ; Shortcut created in destination dir, %CE14%\n")
f.write("%%AppName%%,0,%s\n" % app_name)
def output_inf_file(program_name, app_name):
global files_in_directory
inf_name = "%s.inf" % program_name
f = open(inf_name, 'w')
output_inf_file_header(f, program_name)
dirs = sorted(directories)
output_sourcedisksnames_section(f, dirs)
output_sourcedisksfiles_section(f)
output_defaultinstall_section(f, dirs)
output_destinationdirs_section(f, dirs)
output_directory_sections(f, dirs)
output_registry_section(f)
output_shortcuts_section(f, app_name)
f.close()
def make_cab_file(cabwiz_path, program_name, cab_final_name):
make_cab_command = "\"%s\" %s.inf /compress" % (cabwiz_path, program_name)
print "INFORMATION: Executing command to make %s CAB file (only works on BASH)" % program_name
print " [%s]" % make_cab_command
sys.stdout.flush()
success = call([cabwiz_path, "%s.inf" % program_name, "/compress"],
stdout=open("NUL:","w"), stderr=STDOUT)
if not os.path.isfile("%s.CAB" % program_name):
print """***************************************************************************
ERROR: CAB FILE NOT CREATED.
You can try running the command by hand:
%s" % make_cab_comman
----
NOTE: If you see an error like this:
Error: File XXXXXXXXXX.inf contains DirIDs, which are not supported
--
this may mean that your PYTHON is outputting Windows files WITHOUT CR-LF
line endings. Please verify that your INF file has CR-LF line endings.
***************************************************************************"""
return
print "INFORMATION: Executing command to move %s.CAB to %s" % (program_name, cab_final_name)
sys.stdout.flush()
shutil.move("%s.CAB" % program_name, cab_final_name)
def purge_copied_files():
for entry in file_entries:
if entry.filename != entry.actual_filename:
new_relative_filename = join(entry.dirpath, entry.actual_filename)
os.remove(new_relative_filename)
def main():
if len(sys.argv) != 5:
print >> sys.stderr, "Usage: %s CABWIZ_PATH SOURCE_DIR PROGRAM_NAME CAB_FINAL_NAME" % sys.argv[0]
print >> sys.stderr, "Example: %s /c/Program\ Files/Microsoft\ Visual\ Studio\ 9.0/ fennec Fennec fennec-0.11.en-US.wince-arm.cab" % sys.argv[0]
sys.exit(1)
cabwiz_path = sys.argv[1]
source_dir = sys.argv[2]
program_name = sys.argv[3]
app_name = "%s.exe" % source_dir
cab_final_name = sys.argv[4]
if not os.path.isfile(cabwiz_path):
print """***************************************************************************
ERROR: CABWIZ_PATH is not a valid file!
Perhaps your VSINSTALLDIR is not properly set up?
EXITING...
***************************************************************************"""
sys.exit(2)
walk_tree(source_dir, ignored_patterns)
sys.stdout.flush()
output_inf_file(program_name, app_name)
sys.stdout.flush()
make_cab_file(cabwiz_path, program_name, cab_final_name)
purge_copied_files()
# run main if run directly
if __name__ == "__main__":
main()

View File

@ -72,6 +72,7 @@ LIBXUL_SDK = @LIBXUL_SDK@
L10NBASEDIR = @L10NBASEDIR@
LIBXUL_DIST = @LIBXUL_DIST@
SYSTEM_LIBXUL = @SYSTEM_LIBXUL@
XULRUNNER_STUB_NAME = @XULRUNNER_STUB_NAME@

View File

@ -1832,8 +1832,6 @@ case "$target" in
# logging code in nsObjCExceptions.h. Currently we only use that in debug
# builds.
MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling"
# set MACOSX to generate lib/mac/MoreFiles/Makefile
MACOSX=1
dnl DTrace and -dead_strip don't interact well. See bug 403132.
dnl ===================================================================

View File

@ -134,7 +134,14 @@ nsAsyncInstantiateEvent::Run()
// Also make sure that we still refer to the same data.
nsIObjectFrame* frame = mContent->
GetExistingFrame(nsObjectLoadingContent::eFlushContent);
if (mFrame.IsAlive() &&
#ifdef DEBUG
if (frame && mFrame.IsAlive()) {
nsIFrame* objectFrame = do_QueryFrame(frame);
NS_ASSERTION(objectFrame == mFrame.GetFrame(), "Wrong frame!");
}
#endif
if (frame &&
mFrame.IsAlive() &&
mContent->mURI == mURI &&
mContent->mContentType.Equals(mContentType)) {
if (LOG_ENABLED()) {

View File

@ -44,7 +44,7 @@
#include "nsGenericElement.h"
#include "nsMutationEvent.h"
#include "nsDOMCSSDeclaration.h"
#include "nsICSSOMFactory.h"
#include "nsDOMCSSAttrDeclaration.h"
#include "nsServiceManagerUtils.h"
#include "nsIDocument.h"
#include "nsICSSStyleRule.h"
@ -167,9 +167,6 @@ nsStyledElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// ---------------------------------------------------------------
// Others and helpers
static nsICSSOMFactory* gCSSOMFactory = nsnull;
static NS_DEFINE_CID(kCSSOMFactoryCID, NS_CSSOMFACTORY_CID);
nsresult
nsStyledElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
{
@ -180,15 +177,8 @@ nsStyledElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
// Just in case...
ReparseStyleAttribute(PR_TRUE);
nsresult rv;
if (!gCSSOMFactory) {
rv = CallGetService(kCSSOMFactoryCID, &gCSSOMFactory);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = gCSSOMFactory->CreateDOMCSSAttributeDeclaration(this,
getter_AddRefs(slots->mStyle));
NS_ENSURE_SUCCESS(rv, rv);
slots->mStyle = new nsDOMCSSAttributeDeclaration(this);
NS_ENSURE_TRUE(slots->mStyle, NS_ERROR_OUT_OF_MEMORY);
SetFlags(NODE_MAY_HAVE_STYLE);
}
@ -265,10 +255,3 @@ nsStyledElement::ParseStyleAttribute(nsIContent* aContent,
aResult.SetTo(aValue);
}
/* static */ void
nsStyledElement::Shutdown()
{
NS_IF_RELEASE(gCSSOMFactory);
}

View File

@ -89,8 +89,6 @@ public:
nsAttrValue& aResult,
PRBool aForceInDataDoc);
static void Shutdown();
protected:
virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,

View File

@ -39,10 +39,10 @@
#define nsICanvasElement_h___
#include "nsISupports.h"
#include "nsRect.h"
class gfxContext;
class nsIFrame;
struct gfxRect;
// {C234660C-BD06-493e-8583-939A5A158B37}
#define NS_ICANVASELEMENT_IID \
@ -91,9 +91,9 @@ public:
/*
* Ask the canvas frame to invalidate a portion of the frame; damageRect
* is relative to the origin of the canvas frame.
* is relative to the origin of the canvas frame in CSS pixels.
*/
NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect) = 0;
NS_IMETHOD InvalidateFrameSubrect (const gfxRect& damageRect) = 0;
/*
* Get the number of contexts in this canvas, and request a context at

View File

@ -318,6 +318,8 @@ public:
virtual ~nsCanvasRenderingContext2D();
nsresult Redraw();
// this rect is in CSS pixels
nsresult Redraw(const gfxRect& r);
// nsICanvasRenderingContextInternal
NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
@ -889,6 +891,20 @@ nsCanvasRenderingContext2D::Redraw()
return NS_OK;
}
nsresult
nsCanvasRenderingContext2D::Redraw(const gfxRect& r)
{
if (!mCanvasElement)
return NS_OK;
if (!mIsFrameInvalid) {
mIsFrameInvalid = PR_TRUE;
return mCanvasElement->InvalidateFrameSubrect(r);
}
return NS_OK;
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
{
@ -3397,7 +3413,9 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
}
// Flush layout updates
if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH))
PRBool skipFlush =
(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH) != 0;
if (!skipFlush)
FlushLayoutForTree(aWindow);
nsCOMPtr<nsPresContext> presContext;
@ -3427,13 +3445,23 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) {
renderDocFlags |= nsIPresShell::RENDER_CARET;
}
PRBool oldDisableValue = nsLayoutUtils::sDisableGetUsedXAssertions;
nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue || skipFlush;
presShell->RenderDocument(r, renderDocFlags, bgColor, mThebes);
nsLayoutUtils::sDisableGetUsedXAssertions = oldDisableValue;
// get rid of the pattern surface ref, just in case
mThebes->SetColor(gfxRGBA(1,1,1,1));
DirtyAllStyles();
Redraw();
// note that aX and aY are coordinates in the document that
// we're drawing; aX and aY are drawn to 0,0 in current user
// space.
gfxRect damageRect = mThebes->UserToDevice(gfxRect(0, 0, aW, aH));
damageRect.RoundOut();
Redraw(damageRect);
return rv;
}

View File

@ -93,7 +93,6 @@
#include "nsIDOMEvent.h"
#include "nsIDOMNSEvent.h"
#include "nsDOMCSSDeclaration.h"
#include "nsICSSOMFactory.h"
#include "nsITextControlFrame.h"
#include "nsIForm.h"
#include "nsIFormControl.h"

View File

@ -92,7 +92,7 @@ public:
virtual PRBool IsWriteOnly();
virtual void SetWriteOnly();
NS_IMETHOD InvalidateFrame ();
NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect);
NS_IMETHOD InvalidateFrameSubrect (const gfxRect& damageRect);
virtual PRInt32 CountContexts();
virtual nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index);
virtual PRBool GetIsOpaque();
@ -555,11 +555,29 @@ nsHTMLCanvasElement::InvalidateFrame()
}
NS_IMETHODIMP
nsHTMLCanvasElement::InvalidateFrameSubrect(const nsRect& damageRect)
nsHTMLCanvasElement::InvalidateFrameSubrect(const gfxRect& damageRect)
{
nsIFrame *frame = GetPrimaryFrame(Flush_Frames);
if (frame) {
frame->Invalidate(damageRect);
nsRect contentArea(frame->GetContentRect());
nsIntSize size = GetWidthHeight();
// damageRect and size are in CSS pixels; contentArea is in appunits
// We want a rect in appunits; so avoid doing pixels-to-appunits and
// vice versa conversion here.
gfxRect realRect(damageRect);
realRect.Scale(contentArea.width / gfxFloat(size.width),
contentArea.height / gfxFloat(size.height));
realRect.RoundOut();
// then make it a nsRect
nsRect invalRect(realRect.X(), realRect.Y(),
realRect.Width(), realRect.Height());
// account for border/padding
invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
frame->Invalidate(invalRect);
}
return NS_OK;

View File

@ -826,6 +826,7 @@ nsSVGElement::sViewportsMap[] = {
// PresentationAttributes-Makers
/* static */ const nsGenericElement::MappedAttributeEntry
nsSVGElement::sMarkersMap[] = {
{ &nsGkAtoms::marker },
{ &nsGkAtoms::marker_end },
{ &nsGkAtoms::marker_mid },
{ &nsGkAtoms::marker_start },

View File

@ -1422,51 +1422,105 @@ nsBindingManager::GetNestedSingleInsertionPoint(nsIContent* aParent,
return insertionElement;
}
nsXBLInsertionPoint*
nsBindingManager::FindInsertionPointAndIndex(nsIContent* aContainer,
nsIContent* aInsertionParent,
PRUint32 aIndexInContainer,
PRInt32 aAppend,
PRInt32* aInsertionIndex)
{
PRBool isAnonymousContentList;
nsINodeList* nodeList =
GetXBLChildNodesInternal(aInsertionParent, &isAnonymousContentList);
if (!nodeList || !isAnonymousContentList) {
return nsnull;
}
// Find a non-pseudo-insertion point and just jam ourselves in. This is
// not 100% correct, since there might be multiple insertion points under
// this insertion parent, and we should really be using the one that
// matches our content... Hack city, baby.
nsAnonymousContentList* contentList =
static_cast<nsAnonymousContentList*>(nodeList);
PRInt32 count = contentList->GetInsertionPointCount();
for (PRInt32 i = 0; i < count; i++) {
nsXBLInsertionPoint* point = contentList->GetInsertionPointAt(i);
if (point->GetInsertionIndex() != -1) {
// We're real. Jam the kid in.
// Find the right insertion spot. Can't just insert in the insertion
// point at aIndexInContainer since the point may contain anonymous
// content, not all of aContainer's kids, etc. So find the last
// child of aContainer that comes before aIndexInContainer and is in
// the insertion point and insert right after it.
PRInt32 pointSize = point->ChildCount();
for (PRInt32 parentIndex = aIndexInContainer - 1; parentIndex >= 0;
--parentIndex) {
nsIContent* currentSibling = aContainer->GetChildAt(parentIndex);
for (PRInt32 pointIndex = pointSize - 1; pointIndex >= 0;
--pointIndex) {
if (point->ChildAt(pointIndex) == currentSibling) {
*aInsertionIndex = pointIndex + 1;
return point;
}
}
}
// None of our previous siblings are in here... just stick
// ourselves in at the end of the insertion point if we're
// appending, and at the beginning otherwise.
// XXXbz if we ever start doing the filter thing right, this may be no
// good, since we may _still_ have anonymous kids in there and may need
// to get the ordering with those right. In fact, this is even wrong
// without the filter thing for nested insertion points, since they might
// contain anonymous content that needs to come after all explicit
// kids... but we have no way to know that here easily.
if (aAppend) {
*aInsertionIndex = pointSize;
} else {
*aInsertionIndex = 0;
}
return point;
}
}
return nsnull;
}
void
nsBindingManager::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{
// XXX This is hacked and not quite correct. See below.
if (aNewIndexInContainer != -1 &&
(mContentListTable.ops || mAnonymousNodesTable.ops)) {
// It's not anonymous.
NS_ASSERTION(aNewIndexInContainer >= 0, "Bogus index");
PRBool multiple;
nsIContent* ins = GetNestedSingleInsertionPoint(aContainer, &multiple);
if (multiple) {
// Do each kid individually
PRInt32 childCount = aContainer->GetChildCount();
NS_ASSERTION(aNewIndexInContainer >= 0, "Bogus index");
for (PRInt32 idx = aNewIndexInContainer; idx < childCount; ++idx) {
HandleChildInsertion(aContainer, aContainer->GetChildAt(idx),
idx, PR_TRUE);
}
}
else if (ins) {
PRBool isAnonymousContentList;
nsCOMPtr<nsIDOMNodeList> nodeList =
GetXBLChildNodesInternal(ins, &isAnonymousContentList);
if (nodeList && isAnonymousContentList) {
// Find the one non-pseudo-insertion point and just add ourselves.
nsAnonymousContentList* contentList =
static_cast<nsAnonymousContentList*>(nodeList.get());
PRInt32 count = contentList->GetInsertionPointCount();
for (PRInt32 i = 0; i < count; i++) {
nsXBLInsertionPoint* point = contentList->GetInsertionPointAt(i);
PRInt32 index = point->GetInsertionIndex();
if (index != -1) {
// We're real. Jam all the kids in.
PRInt32 childCount = aContainer->GetChildCount();
for (PRInt32 j = aNewIndexInContainer; j < childCount; j++) {
nsIContent* child = aContainer->GetChildAt(j);
point->AddChild(child);
SetInsertionParent(child, ins);
}
break;
}
PRInt32 insertionIndex;
nsXBLInsertionPoint* point =
FindInsertionPointAndIndex(aContainer, ins, aNewIndexInContainer,
PR_TRUE, &insertionIndex);
if (point) {
PRInt32 childCount = aContainer->GetChildCount();
for (PRInt32 j = aNewIndexInContainer; j < childCount;
j++, insertionIndex++) {
nsIContent* child = aContainer->GetChildAt(j);
point->InsertChildAt(insertionIndex, child);
SetInsertionParent(child, ins);
}
}
}
@ -1479,7 +1533,6 @@ nsBindingManager::ContentInserted(nsIDocument* aDocument,
nsIContent* aChild,
PRInt32 aIndexInContainer)
{
// XXX This is hacked just to make menus work again.
if (aIndexInContainer != -1 &&
(mContentListTable.ops || mAnonymousNodesTable.ops)) {
// It's not anonymous.
@ -1640,61 +1693,13 @@ nsBindingManager::HandleChildInsertion(nsIContent* aContainer,
nsIContent* ins = GetNestedInsertionPoint(aContainer, aChild);
if (ins) {
PRBool isAnonymousContentList;
nsCOMPtr<nsIDOMNodeList> nodeList =
GetXBLChildNodesInternal(ins, &isAnonymousContentList);
if (nodeList && isAnonymousContentList) {
// Find a non-pseudo-insertion point and just jam ourselves in. This is
// not 100% correct, since there might be multiple insertion points under
// this insertion parent, and we should really be using the one that
// matches our content... Hack city, baby.
nsAnonymousContentList* contentList =
static_cast<nsAnonymousContentList*>(nodeList.get());
PRInt32 count = contentList->GetInsertionPointCount();
for (PRInt32 i = 0; i < count; i++) {
nsXBLInsertionPoint* point = contentList->GetInsertionPointAt(i);
if (point->GetInsertionIndex() != -1) {
// We're real. Jam the kid in.
// Find the right insertion spot. Can't just insert in the insertion
// point at aIndexInContainer since the point may contain anonymous
// content, not all of aContainer's kids, etc. So find the last
// child of aContainer that comes before aIndexInContainer and is in
// the insertion point and insert right after it.
PRInt32 pointSize = point->ChildCount();
PRBool inserted = PR_FALSE;
for (PRInt32 parentIndex = aIndexInContainer - 1;
parentIndex >= 0 && !inserted; --parentIndex) {
nsIContent* currentSibling = aContainer->GetChildAt(parentIndex);
for (PRInt32 pointIndex = pointSize - 1; pointIndex >= 0;
--pointIndex) {
nsCOMPtr<nsIContent> currContent = point->ChildAt(pointIndex);
if (currContent == currentSibling) {
point->InsertChildAt(pointIndex + 1, aChild);
inserted = PR_TRUE;
break;
}
}
}
if (!inserted) {
// None of our previous siblings are in here... just stick
// ourselves in at the end of the insertion point if we're
// appending, and at the beginning otherwise.
// XXXbz if we ever start doing the filter thing right, this may be
// no good, since we may _still_ have anonymous kids in there and
// may need to get the ordering with those right.
if (aAppend) {
point->AddChild(aChild);
} else {
point->InsertChildAt(0, aChild);
}
}
SetInsertionParent(aChild, ins);
break;
}
}
PRInt32 insertionIndex;
nsXBLInsertionPoint* point =
FindInsertionPointAndIndex(aContainer, ins, aIndexInContainer, aAppend,
&insertionIndex);
if (point) {
point->InsertChildAt(insertionIndex, aChild);
SetInsertionParent(aChild, ins);
}
}
}

View File

@ -242,6 +242,19 @@ protected:
void HandleChildInsertion(nsIContent* aContainer, nsIContent* aChild,
PRUint32 aIndexInContainer, PRBool aAppend);
// For the given container under which a child is being added, given
// insertion parent and given index of the child being inserted, find the
// right nsXBLInsertionPoint and the right index in that insertion point to
// insert it at. If null is returned, aInsertionIndex might be garbage.
// aAppend controls what should be returned as the aInsertionIndex if the
// right index can't be found. If true, the length of the insertion point
// will be returned; otherwise 0 will be returned.
nsXBLInsertionPoint* FindInsertionPointAndIndex(nsIContent* aContainer,
nsIContent* aInsertionParent,
PRUint32 aIndexInContainer,
PRInt32 aAppend,
PRInt32* aInsertionIndex);
// Same as ProcessAttachedQueue, but also nulls out
// mProcessAttachedQueueEvent
void DoProcessAttachedQueue();

View File

@ -103,6 +103,7 @@
#include "nsIServiceManager.h"
#include "nsICSSStyleRule.h"
#include "nsIStyleSheet.h"
#include "nsDOMCSSAttrDeclaration.h"
#include "nsIURL.h"
#include "nsIViewManager.h"
#include "nsIWidget.h"
@ -159,7 +160,6 @@
// Global object maintenance
nsICSSParser* nsXULPrototypeElement::sCSSParser = nsnull;
nsIXBLService * nsXULElement::gXBLService = nsnull;
nsICSSOMFactory* nsXULElement::gCSSOMFactory = nsnull;
/**
* A tearoff class for nsXULElement to implement nsIScriptEventHandlerOwner.
@ -191,7 +191,6 @@ private:
//----------------------------------------------------------------------
static NS_DEFINE_CID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID);
static NS_DEFINE_CID(kCSSOMFactoryCID, NS_CSSOMFACTORY_CID);
//----------------------------------------------------------------------
@ -1929,14 +1928,8 @@ nsXULElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
if (!slots->mStyle) {
if (!gCSSOMFactory) {
rv = CallGetService(kCSSOMFactoryCID, &gCSSOMFactory);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = gCSSOMFactory->CreateDOMCSSAttributeDeclaration(this,
getter_AddRefs(slots->mStyle));
NS_ENSURE_SUCCESS(rv, rv);
slots->mStyle = new nsDOMCSSAttributeDeclaration(this);
NS_ENSURE_TRUE(slots->mStyle, NS_ERROR_OUT_OF_MEMORY);
SetFlags(NODE_MAY_HAVE_STYLE);
}

View File

@ -70,7 +70,6 @@
#include "nsIXULTemplateBuilder.h"
#include "nsIBoxObject.h"
#include "nsIXBLService.h"
#include "nsICSSOMFactory.h"
#include "nsLayoutCID.h"
#include "nsAttrAndChildArray.h"
#include "nsGkAtoms.h"
@ -490,13 +489,11 @@ public:
}
static void ReleaseGlobals() {
NS_IF_RELEASE(gXBLService);
NS_IF_RELEASE(gCSSOMFactory);
}
protected:
// pseudo-constants
static nsIXBLService* gXBLService;
static nsICSSOMFactory* gCSSOMFactory;
public:
static nsresult

View File

@ -752,29 +752,6 @@ nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
return p;
}
///////////////////////////////////////////////////////////////////////////
// HasSameBlockNodeParent: true if nodes have same block level ancestor
//
PRBool
nsHTMLEditor::HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
{
if (!aNode1 || !aNode2)
{
NS_NOTREACHED("null node passed to HasSameBlockNodeParent()");
return PR_FALSE;
}
if (aNode1 == aNode2)
return PR_TRUE;
nsCOMPtr<nsIDOMNode> p1 = GetBlockNodeParent(aNode1);
nsCOMPtr<nsIDOMNode> p2 = GetBlockNodeParent(aNode2);
return (p1 == p2);
}
///////////////////////////////////////////////////////////////////////////
// GetBlockSection: return leftmost/rightmost nodes in aChild's block
//
@ -2175,117 +2152,6 @@ nsHTMLEditor::SetParagraphFormat(const nsAString& aParagraphFormat)
return InsertBasicBlock(tag);
}
// XXX: ERROR_HANDLING -- this method needs a little work to ensure all error codes are
// checked properly, all null pointers are checked, and no memory leaks occur
NS_IMETHODIMP
nsHTMLEditor::GetParentBlockTags(nsTArray<nsString> *aTagList, PRBool aGetLists)
{
nsresult res;
nsCOMPtr<nsISelection>selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
// Find out if the selection is collapsed:
PRBool isCollapsed;
res = selection->GetIsCollapsed(&isCollapsed);
if (NS_FAILED(res)) return res;
if (isCollapsed)
{
nsCOMPtr<nsIDOMNode> node, blockParent;
PRInt32 offset;
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
if (!node) res = NS_ERROR_FAILURE;
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMElement> blockParentElem;
if (aGetLists)
{
// Get the "ol", "ul", or "dl" parent element
res = GetElementOrParentByTagName(NS_LITERAL_STRING("list"), node, getter_AddRefs(blockParentElem));
if (NS_FAILED(res)) return res;
}
else
{
PRBool isBlock (PR_FALSE);
NodeIsBlock(node, &isBlock);
if (isBlock) blockParent = node;
else blockParent = GetBlockNodeParent(node);
blockParentElem = do_QueryInterface(blockParent);
}
if (blockParentElem)
{
nsAutoString blockParentTag;
blockParentElem->GetTagName(blockParentTag);
aTagList->AppendElement(blockParentTag);
}
return res;
}
// else non-collapsed selection
nsCOMPtr<nsIEnumerator> enumerator;
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_NULL_POINTER;
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
//XXX: should be while loop?
if (currentItem)
{
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// scan the range for all the independent block content blockSections
// and get the block parent of each
nsCOMArray<nsIDOMRange> blockSections;
res = GetBlockSectionsForRange(range, blockSections);
if (NS_SUCCEEDED(res))
{
nsCOMPtr<nsIDOMRange> subRange = blockSections[0];
while (subRange)
{
nsCOMPtr<nsIDOMNode>startParent;
res = subRange->GetStartContainer(getter_AddRefs(startParent));
if (NS_SUCCEEDED(res) && startParent)
{
nsCOMPtr<nsIDOMElement> blockParent;
if (aGetLists)
{
// Get the "ol", "ul", or "dl" parent element
res = GetElementOrParentByTagName(NS_LITERAL_STRING("list"), startParent, getter_AddRefs(blockParent));
}
else
{
blockParent = do_QueryInterface(GetBlockNodeParent(startParent));
}
if (NS_SUCCEEDED(res) && blockParent)
{
nsAutoString blockParentTag;
blockParent->GetTagName(blockParentTag);
PRBool isRoot;
IsRootTag(blockParentTag, isRoot);
if ((!isRoot) && !aTagList->Contains(blockParentTag)) {
aTagList->AppendElement(blockParentTag);
}
}
}
if (NS_FAILED(res))
return res;
blockSections.RemoveObject(0);
if (blockSections.Count() == 0)
break;
subRange = blockSections[0];
}
}
}
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetParagraphState(PRBool *aMixed, nsAString &outFormat)
{
@ -2332,20 +2198,6 @@ nsHTMLEditor::GetHighlightColorState(PRBool *aMixed, nsAString &aOutColor)
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetHighlightColor(PRBool *aMixed, PRUnichar **_retval)
{
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
nsAutoString outColorString(NS_LITERAL_STRING("transparent"));
*aMixed = PR_FALSE;
nsresult err = NS_NOINTERFACE;
err = GetHighlightColorState(aMixed, outColorString);
*_retval = ToNewUnicode(outColorString);
return err;
}
nsresult
nsHTMLEditor::GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, PRBool aBlockLevel)
{
@ -4425,44 +4277,6 @@ nsHTMLEditor::IsRootTag(nsString &aTag, PRBool &aIsTag)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLEditor::IsSubordinateBlock(nsString &aTag, PRBool &aIsTag)
{
static char p[] = "p";
static char h1[] = "h1";
static char h2[] = "h2";
static char h3[] = "h3";
static char h4[] = "h4";
static char h5[] = "h5";
static char h6[] = "h6";
static char address[] = "address";
static char pre[] = "pre";
static char li[] = "li";
static char dt[] = "dt";
static char dd[] = "dd";
if (aTag.EqualsIgnoreCase(p) ||
aTag.EqualsIgnoreCase(h1) ||
aTag.EqualsIgnoreCase(h2) ||
aTag.EqualsIgnoreCase(h3) ||
aTag.EqualsIgnoreCase(h4) ||
aTag.EqualsIgnoreCase(h5) ||
aTag.EqualsIgnoreCase(h6) ||
aTag.EqualsIgnoreCase(address) ||
aTag.EqualsIgnoreCase(pre) ||
aTag.EqualsIgnoreCase(li) ||
aTag.EqualsIgnoreCase(dt) ||
aTag.EqualsIgnoreCase(dd) )
{
aIsTag = PR_TRUE;
}
else {
aIsTag = PR_FALSE;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////
// GetEnclosingTable: find ancestor who is a table, if any
//
@ -4587,50 +4401,6 @@ nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMRange *aInRange)
return result;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextElementByTagName(nsIDOMElement *aCurrentElement,
const nsAString *aTagName,
nsIDOMElement **aReturn)
{
nsresult res = NS_OK;
if (!aCurrentElement || !aTagName || !aReturn)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(*aTagName);
if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
if (tagAtom==nsEditProperty::th)
tagAtom=nsEditProperty::td;
nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(aCurrentElement);
if (!currentNode)
return NS_ERROR_FAILURE;
*aReturn = nsnull;
nsCOMPtr<nsIDOMNode> nextNode;
PRBool done = PR_FALSE;
do {
res = GetNextNode(currentNode, PR_TRUE, address_of(nextNode));
if (NS_FAILED(res)) return res;
if (!nextNode) break;
if (GetTag(currentNode) == tagAtom)
{
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(currentNode);
if (!element) return NS_ERROR_NULL_POINTER;
*aReturn = element;
NS_ADDREF(*aReturn);
done = PR_TRUE;
return NS_OK;
}
currentNode = nextNode;
} while (!done);
return res;
}
NS_IMETHODIMP
nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
{

View File

@ -172,14 +172,9 @@ public:
NS_IMETHOD LoadHTML(const nsAString &aInputString);
NS_IMETHOD GetParentBlockTags(nsTArray<nsString> *aTagList, PRBool aGetLists);
nsresult GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor,
PRBool aBlockLevel);
NS_IMETHOD GetHTMLBackgroundColorState(PRBool *aMixed, nsAString &outColor);
NS_IMETHOD GetHighlightColor(PRBool *mixed, PRUnichar **_retval);
NS_IMETHOD GetNextElementByTagName(nsIDOMElement *aCurrentElement, const nsAString *aTagName, nsIDOMElement **aReturn);
/* ------------ nsIEditorStyleSheets methods -------------- */
@ -231,8 +226,6 @@ public:
PRBool* aIsSelected);
NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMNode** aRowNode);
NS_IMETHOD GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode** aRowNode);
NS_IMETHOD GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode);
NS_IMETHOD GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aRowNode);
NS_IMETHOD GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode);
NS_IMETHOD SetSelectionAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol,
@ -265,7 +258,6 @@ public:
/* ------------ Block methods moved from nsEditor -------------- */
static nsCOMPtr<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
static PRBool HasSameBlockNodeParent(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
/** Determines the bounding nodes for the block section containing aNode.
* The calculation is based on some nodes intrinsically being block elements
* acording to HTML. Style sheets are not considered in this calculation.
@ -393,14 +385,6 @@ public:
PRInt32 &aStartOffset,
PRInt32 &aEndOffset);
nsresult GetAbsoluteOffsetsForPoints(nsIDOMNode *aInStartNode,
PRInt32 aInStartOffset,
nsIDOMNode *aInEndNode,
PRInt32 aInEndOffset,
nsIDOMNode *aInCommonParentNode,
PRInt32 &aOutStartOffset,
PRInt32 &aEndOffset);
// Use this to assure that selection is set after attribute nodes when
// trying to collapse selection at begining of a block node
// e.g., when setting at beginning of a table cell
@ -426,7 +410,6 @@ public:
PRBool *aSeenBR);
// Stylesheet-related methods that aren't part of nsIEditorStyleSheets.
nsresult AddCSSStyleSheet(nsICSSStyleSheet* aSheet);
nsresult GetCSSLoader(const nsAString& aURL, nsICSSLoader** aCSSLoader);
// Returns TRUE if sheet was loaded, false if it wasn't
@ -543,8 +526,6 @@ protected:
NS_IMETHOD IsRootTag(nsString &aTag, PRBool &aIsTag);
NS_IMETHOD IsSubordinateBlock(nsString &aTag, PRBool &aIsTag);
virtual PRBool IsBlockNode(nsIDOMNode *aNode);
static nsCOMPtr<nsIDOMNode> GetEnclosingTable(nsIDOMNode *aNode);
@ -572,11 +553,6 @@ protected:
nsIDOMNode **aStyleNode,
nsAString *outValue = nsnull);
void ResetTextSelectionForRange(nsIDOMNode *aParent,
PRInt32 aStartOffset,
PRInt32 aEndOffset,
nsISelection *aSelection);
// Methods for handling plaintext quotations
NS_IMETHOD PasteAsPlaintextQuotation(PRInt32 aSelectionType);

View File

@ -391,70 +391,6 @@ nsHTMLEditor::GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode **aRowNode)
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode)
{
if (!aCellNode) return NS_ERROR_NULL_POINTER;
*aCellNode = nsnull;
if (!aRowNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> rowChild;
nsresult res = aRowNode->GetFirstChild(getter_AddRefs(rowChild));
if (NS_FAILED(res)) return res;
while (rowChild && !nsHTMLEditUtils::IsTableCell(rowChild))
{
// Skip over textnodes
nsCOMPtr<nsIDOMNode> nextChild;
res = rowChild->GetNextSibling(getter_AddRefs(nextChild));
if (NS_FAILED(res)) return res;
rowChild = nextChild;
};
if (rowChild)
{
*aCellNode = rowChild.get();
NS_ADDREF(*aCellNode);
return NS_OK;
}
// If here, cell was not found
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aCellNode)
{
if (!aCellNode) return NS_ERROR_NULL_POINTER;
*aCellNode = nsnull;
if (!aCurrentCellNode) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> nextCell;
nsresult res = aCurrentCellNode->GetNextSibling(getter_AddRefs(nextCell));
if (NS_FAILED(res)) return res;
while (nextCell && !nsHTMLEditUtils::IsTableCell(nextCell))
{
// Skip over textnodes
nsCOMPtr<nsIDOMNode> nextChild;
res = nextCell->GetNextSibling(getter_AddRefs(nextChild));
if (NS_FAILED(res)) return res;
nextCell = nextChild;
};
if (nextCell)
{
*aCellNode = nextCell.get();
NS_ADDREF(*aCellNode);
return NS_OK;
}
// If here, cell was not found
return NS_EDITOR_ELEMENT_NOT_FOUND;
}
NS_IMETHODIMP
nsHTMLEditor::GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode)
{

View File

@ -76,16 +76,6 @@ public:
eBlockPartial // S begins or ends in TB but extends outside of TB.
} TSDBlockSelectionStatus;
/**
* Initializes the text services document to use a particular
* DOM document.
* @param aDOMDocument is the document to use. It is AddRef'd
* by this method.
* @param aPresShell is the presentation shell to use when
* setting the selection. It is AddRef'd by this method.
*/
NS_IMETHOD InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell) = 0;
/**
* Get the DOM document for the document in use.
* @return aDocument the dom document [OUT]
@ -103,26 +93,15 @@ public:
/**
* Sets the range/extent over which the text services document
* will iterate. Note that InitWithDocument() or InitWithEditor()
* should have been called prior to calling this method. If this
* method is never called, the text services defaults to iterating
* over the entire document.
* will iterate. Note that InitWithEditor() should have been called prior to
* calling this method. If this method is never called, the text services
* defaults to iterating over the entire document.
*
* @param aDOMRange is the range to use. aDOMRange must point to a
* valid range object.
*/
NS_IMETHOD SetExtent(nsIDOMRange* aDOMRange) = 0;
/**
* Gets the range that the text services document
* is currently iterating over. If SetExtent() was never
* called, this method will return a range that spans the
* entire body of the document.
*
* @param aDOMRange will contain an AddRef'd pointer to the range.
*/
NS_IMETHOD GetExtent(nsIDOMRange** aDOMRange) = 0;
/**
* Expands the end points of the range so that it spans complete words.
* This call does not change any internal state of the text services document.
@ -137,14 +116,6 @@ public:
*/
NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter) = 0;
/**
* Returns true if the document can be modified with calls
* to DeleteSelection() and InsertText().
* @param aCanEdit is true if the document can be modified,
* false if it can't.
*/
NS_IMETHOD CanEdit(PRBool *aCanEdit) = 0;
/**
* Returns the text in the current text block.
* @param aStr will contain the text.
@ -160,27 +131,6 @@ public:
NS_IMETHOD FirstBlock() = 0;
/**
* Tells the document to point to the last text block in the
* document. This method does not adjust the current cursor
* position or selection.
*/
NS_IMETHOD LastBlock() = 0;
/**
* Tells the document to point to the first text block that
* contains the current selection or caret.
* @param aSelectionStatus will contain the text block selection status
* @param aSelectionOffset will contain the offset into the
* string returned by GetCurrentTextBlock() where the selection
* begins.
* @param aLength will contain the number of characters that are
* selected in the string.
*/
NS_IMETHOD FirstSelectedBlock(TSDBlockSelectionStatus *aSelectionStatus, PRInt32 *aSelectionOffset, PRInt32 *aSelectionLength) = 0;
/**
* Tells the document to point to the last text block that
* contains the current selection or caret.
@ -259,21 +209,6 @@ public:
*/
NS_IMETHOD InsertText(const nsString *aText) = 0;
/**
* Sets the display style for the text selected by SetSelection().
* @param aStyle is the style to apply to the selected text.
*/
NS_IMETHOD SetDisplayStyle(TSDDisplayStyle aStyle) = 0;
/**
* Returns the DOM range for a given offset and length
* @param aOffset offset into string returned by GetCurrentTextBlock().
* @param aLength number characters selected.
* @return aDOMRange the DOM range that represents the offset and length
*/
NS_IMETHOD GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsITextServicesDocument,

View File

@ -171,46 +171,6 @@ NS_IMPL_RELEASE(nsTextServicesDocument)
NS_IMPL_QUERY_INTERFACE1(nsTextServicesDocument, nsITextServicesDocument)
NS_IMETHODIMP
nsTextServicesDocument::InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell)
{
nsresult result = NS_OK;
if (!aDOMDocument || !aPresShell)
return NS_ERROR_NULL_POINTER;
NS_ASSERTION(!mSelCon, "mSelCon already initialized!");
if (mSelCon)
return NS_ERROR_FAILURE;
NS_ASSERTION(!mDOMDocument, "mDOMDocument already initialized!");
if (mDOMDocument)
return NS_ERROR_FAILURE;
LOCK_DOC(this);
mSelCon = do_QueryInterface(aPresShell);
mDOMDocument = do_QueryInterface(aDOMDocument);
result = CreateDocumentContentIterator(getter_AddRefs(mIterator));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eIsDone;
result = FirstBlock();
UNLOCK_DOC(this);
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::InitWithEditor(nsIEditor *aEditor)
{
@ -358,27 +318,6 @@ nsTextServicesDocument::SetExtent(nsIDOMRange* aDOMRange)
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::GetExtent(nsIDOMRange** aDOMRange)
{
NS_ENSURE_ARG_POINTER(aDOMRange);
*aDOMRange = nsnull;
if (mExtent)
{
// We have an extent range, so just return a
// copy of it.
return mExtent->CloneRange(aDOMRange);
}
// We don't have an extent range, so we must be
// iterating over the entire document.
return CreateDocumentContentRange(aDOMRange);
}
NS_IMETHODIMP
nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange)
{
@ -555,19 +494,6 @@ nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter)
return NS_OK;
}
NS_IMETHODIMP
nsTextServicesDocument::CanEdit(PRBool *aCanEdit)
{
if (!aCanEdit)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
*aCanEdit = (editor) ? PR_TRUE : PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsTextServicesDocument::GetCurrentTextBlock(nsString *aStr)
{
@ -627,532 +553,6 @@ nsTextServicesDocument::FirstBlock()
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::LastBlock()
{
NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
LOCK_DOC(this);
// Position the iterator on the last text node
// in the tree, then walk backwards over adjacent
// text nodes until we hit a block boundary:
nsresult result = LastTextNode(mIterator, &mIteratorStatus);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
mIteratorStatus = nsTextServicesDocument::eIsDone;
// Keep track of prev and next blocks, just in case
// the text service blows away the current block.
if (mIteratorStatus == nsTextServicesDocument::eValid)
{
result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock));
mNextTextBlock = nsnull;
}
else
{
// There's no text block in the document!
mPrevTextBlock = nsnull;
mNextTextBlock = nsnull;
}
UNLOCK_DOC(this);
return result;
}
// XXX: CODE BLOAT ALERT. FirstSelectedBlock() and LastSelectedBlock()
// are almost identical! Later, when we have time, we should try
// and combine them into one method.
NS_IMETHODIMP
nsTextServicesDocument::FirstSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength)
{
nsresult result = NS_OK;
if (!aSelStatus || !aSelOffset || !aSelLength)
return NS_ERROR_NULL_POINTER;
LOCK_DOC(this);
mIteratorStatus = nsTextServicesDocument::eIsDone;
*aSelStatus = nsITextServicesDocument::eBlockNotFound;
*aSelOffset = *aSelLength = -1;
if (!mSelCon || !mIterator)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISelection> selection;
PRBool isCollapsed = PR_FALSE;
result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = selection->GetIsCollapsed( &isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
nsCOMPtr<nsIContentIterator> iter;
nsCOMPtr<nsIDOMRange> range;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 i, rangeCount, offset;
if (isCollapsed)
{
// We have a caret. Check if the caret is in a text node.
// If it is, make the text node's block the current block.
// If the caret isn't in a text node, search backwards in
// the document, till we find a text node.
result = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!range)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartContainer(getter_AddRefs(parent));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!parent)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartOffset(&offset);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (IsTextNode(parent))
{
// The caret is in a text node. Find the beginning
// of the text block containing this text node and
// return.
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (!content)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (*aSelStatus == nsITextServicesDocument::eBlockContains)
result = SetSelectionInternal(*aSelOffset, *aSelLength, PR_FALSE);
}
else
{
// The caret isn't in a text node. Create an iterator
// based on a range that extends from the beginning of
// the document, to the current caret position, then
// walk backwards till you find a text node, then find
// the beginning of the block.
result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, PR_TRUE, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = range->GetCollapsed(&isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (isCollapsed)
{
// If we get here, the range is collapsed because there is nothing before
// the caret! Just return NS_OK;
UNLOCK_DOC(this);
return NS_OK;
}
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->Last();
nsCOMPtr<nsIContent> content;
while (!iter->IsDone())
{
content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
break;
content = nsnull;
iter->Prev();
}
if (!content)
{
UNLOCK_DOC(this);
return NS_OK;
}
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
}
UNLOCK_DOC(this);
return result;
}
// If we get here, we have an uncollapsed selection!
// Look through each range in the selection till you
// find the first text node. If you find one, find the
// beginning of it's text block, and make it the current
// block.
result = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
NS_ASSERTION(rangeCount > 0, "Unexpected range count!");
if (rangeCount <= 0)
{
UNLOCK_DOC(this);
return NS_OK;
}
// XXX: We may need to add some code here to make sure
// the ranges are sorted in document appearance order!
for (i = 0; i < rangeCount; i++)
{
// Get the i'th range from the selection.
result = selection->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
// Create an iterator for the range.
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->First();
// Now walk through the range till we find a text node.
while (!iter->IsDone())
{
nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
{
// We found a text node, so position the document's
// iterator at the beginning of the block, then get
// the selection in terms of the string offset.
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
UNLOCK_DOC(this);
return result;
}
iter->Next();
}
}
// If we get here, we didn't find any text node in the selection!
// Create a range that extends from the beginning of the selection,
// to the beginning of the document, then iterate backwards through
// it till you find a text node!
result = selection->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!range)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartContainer(getter_AddRefs(parent));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (!parent)
{
UNLOCK_DOC(this);
return NS_ERROR_FAILURE;
}
result = range->GetStartOffset(&offset);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, PR_TRUE, getter_AddRefs(range));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = range->GetCollapsed(&isCollapsed);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
if (isCollapsed)
{
// If we get here, the range is collapsed because there is nothing before
// the current selection! Just return NS_OK;
UNLOCK_DOC(this);
return NS_OK;
}
result = CreateContentIterator(range, getter_AddRefs(iter));
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
iter->Last();
while (!iter->IsDone())
{
nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
if (IsTextNode(content))
{
// We found a text node! Adjust the document's iterator to point
// to the beginning of it's text block, then get the current selection.
result = mIterator->PositionAt(content);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = FirstTextNodeInCurrentBlock(mIterator);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
mIteratorStatus = nsTextServicesDocument::eValid;
result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
mExtent, nsnull);
if (NS_FAILED(result))
{
UNLOCK_DOC(this);
return result;
}
result = GetSelection(aSelStatus, aSelOffset, aSelLength);
UNLOCK_DOC(this);
return result;
}
iter->Prev();
}
// If we get here, we didn't find any block before or inside
// the selection! Just return OK.
UNLOCK_DOC(this);
return NS_OK;
}
// XXX: CODE BLOAT ALERT. FirstSelectedBlock() and LastSelectedBlock()
// are almost identical! Later, when we have time, we should try
// and combine them into one method.
NS_IMETHODIMP
nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus,
PRInt32 *aSelOffset,
@ -2416,75 +1816,6 @@ nsTextServicesDocument::InsertText(const nsString *aText)
return result;
}
NS_IMETHODIMP
nsTextServicesDocument::SetDisplayStyle(TSDDisplayStyle aStyle)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsTextServicesDocument::GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange)
{
if (!mSelCon || aOffset < 0 || aLength < 0)
return NS_ERROR_FAILURE;
nsIDOMNode *sNode = 0, *eNode = 0;
PRInt32 i, sOffset = 0, eOffset = 0;
OffsetEntry *entry;
// Find the start
for (i = 0; !sNode && i < mOffsetTable.Count(); i++)
{
entry = (OffsetEntry *)mOffsetTable[i];
if (entry->mIsValid)
{
if (entry->mIsInsertedText)
{
if (entry->mStrOffset == aOffset)
{
sNode = entry->mNode;
sOffset = entry->mNodeOffset + entry->mLength;
}
}
else if (aOffset >= entry->mStrOffset && aOffset <= entry->mStrOffset + entry->mLength)
{
sNode = entry->mNode;
sOffset = entry->mNodeOffset + aOffset - entry->mStrOffset;
}
}
}
if (!sNode)
return NS_ERROR_FAILURE;
// Now find the end
PRInt32 endOffset = aOffset + aLength;
for (i = mOffsetTable.Count() - 1; !eNode && i >= 0; i--)
{
entry = (OffsetEntry *)mOffsetTable[i];
if (entry->mIsValid)
{
if (entry->mIsInsertedText)
{
if (entry->mStrOffset == eOffset)
{
eNode = entry->mNode;
eOffset = entry->mNodeOffset + entry->mLength;
}
}
else if (endOffset >= entry->mStrOffset && endOffset <= entry->mStrOffset + entry->mLength)
{
eNode = entry->mNode;
eOffset = entry->mNodeOffset + endOffset - entry->mStrOffset;
}
}
}
return CreateRange(sNode, sOffset, eNode, eOffset, aRange);
}
nsresult
nsTextServicesDocument::InsertNode(nsIDOMNode *aNode,
nsIDOMNode *aParent,

View File

@ -138,18 +138,13 @@ public:
NS_DECL_ISUPPORTS
/* nsITextServicesDocument method implementations. */
NS_IMETHOD InitWithDocument(nsIDOMDocument *aDOMDocument, nsIPresShell *aPresShell);
NS_IMETHOD InitWithEditor(nsIEditor *aEditor);
NS_IMETHOD GetDocument(nsIDOMDocument **aDoc);
NS_IMETHOD SetExtent(nsIDOMRange* aDOMRange);
NS_IMETHOD GetExtent(nsIDOMRange** aDOMRange);
NS_IMETHOD ExpandRangeToWordBoundaries(nsIDOMRange *aRange);
NS_IMETHOD SetFilter(nsITextServicesFilter *aFilter);
NS_IMETHOD CanEdit(PRBool *aCanEdit);
NS_IMETHOD GetCurrentTextBlock(nsString *aStr);
NS_IMETHOD FirstBlock();
NS_IMETHOD LastBlock();
NS_IMETHOD FirstSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength);
NS_IMETHOD LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength);
NS_IMETHOD PrevBlock();
NS_IMETHOD NextBlock();
@ -158,8 +153,6 @@ public:
NS_IMETHOD ScrollSelectionIntoView();
NS_IMETHOD DeleteSelection();
NS_IMETHOD InsertText(const nsString *aText);
NS_IMETHOD SetDisplayStyle(TSDDisplayStyle aStyle);
NS_IMETHOD GetDOMRangeFor(PRInt32 aOffset, PRInt32 aLength, nsIDOMRange** aRange);
/* nsIEditActionListener method implementations. */
nsresult InsertNode(nsIDOMNode * aNode,

View File

@ -93,7 +93,8 @@ ifdef HAVE_ARM_SIMD
USE_ARM_SIMD_GCC=1
endif
ifdef HAVE_ARM_NEON
USE_ARM_NEON_GCC=1
# temporarily disabled to see if it fixes odd mobile build breakage
#USE_ARM_NEON_GCC=1
endif
endif

View File

@ -2217,8 +2217,8 @@ pixman_bool_t pixman_have_vmx (void) {
#if defined(_MSC_VER)
#if defined(USE_ARM_SIMD)
extern int pixman_msvc_try_arm_simd_op();
extern int pixman_msvc_try_arm_neon_op();
pixman_bool_t
pixman_have_arm_simd (void)
@ -2238,6 +2238,10 @@ pixman_have_arm_simd (void)
return have_arm_simd;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
extern int pixman_msvc_try_arm_neon_op();
pixman_bool_t
pixman_have_arm_neon (void)
@ -2257,6 +2261,7 @@ pixman_have_arm_neon (void)
return have_arm_neon;
}
#endif /* USE_ARM_NEON */
#else /* linux ELF */
@ -2317,6 +2322,7 @@ pixman_arm_read_auxv() {
arm_tests_initialized = TRUE;
}
#if defined(USE_ARM_SIMD)
pixman_bool_t
pixman_have_arm_simd (void)
{
@ -2325,7 +2331,9 @@ pixman_have_arm_simd (void)
return arm_has_v6;
}
#endif /* USE_ARM_SIMD */
#if defined(USE_ARM_NEON)
pixman_bool_t
pixman_have_arm_neon (void)
{
@ -2334,6 +2342,7 @@ pixman_have_arm_neon (void)
return arm_has_neon;
}
#endif /* USE_ARM_NEON */
#endif /* linux */

View File

@ -63,7 +63,6 @@ EXPORTS = \
nsIImage.h \
nsGfxCIID.h \
nsIRegion.h \
nsDeviceContext.h \
nsITheme.h \
nsThemeConstants.h \
$(NULL)

View File

@ -1,159 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
*
* 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 ***** */
#ifndef nsDeviceContext_h___
#define nsDeviceContext_h___
#include "nsIDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsWeakReference.h"
#include "gfxCore.h"
class nsIImageRequest;
class nsHashtable;
class NS_GFX nsFontCache
{
public:
nsFontCache();
virtual ~nsFontCache();
virtual nsresult Init(nsIDeviceContext* aContext);
virtual nsresult GetDeviceContext(nsIDeviceContext *&aContext) const;
virtual nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics *&aMetrics);
nsresult FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
nsresult Compact();
nsresult Flush();
/* printer device context classes may create their own
* subclasses of nsFontCache (and override this method) and override
* DeviceContextImpl::CreateFontCache (see bug 81311).
*/
virtual nsresult CreateFontMetricsInstance(nsIFontMetrics** fm);
protected:
nsTArray<nsIFontMetrics*> mFontMetrics;
nsIDeviceContext *mContext; // we do not addref this since
// ownership is implied. MMP.
};
// inherit visibility from the NS_GFX class declaration
#undef IMETHOD_VISIBILITY
#define IMETHOD_VISIBILITY
class NS_GFX DeviceContextImpl : public nsIDeviceContext,
public nsIObserver,
public nsSupportsWeakReference
{
public:
DeviceContextImpl();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_IMETHOD Init(nsNativeWidget aWidget);
NS_IMETHOD CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext);
NS_IMETHOD CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext);
NS_IMETHOD CreateRenderingContext(nsIRenderingContext *&aContext){return NS_ERROR_NOT_IMPLEMENTED;}
NS_IMETHOD CreateRenderingContextInstance(nsIRenderingContext *&aContext);
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics);
NS_IMETHOD GetMetricsFor(const nsFont& aFont,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics);
NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);
NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
PRBool& aAliased);
NS_IMETHOD CreateFontCache();
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
NS_IMETHOD FlushFontCache(void);
NS_IMETHOD GetDepth(PRUint32& aDepth);
NS_IMETHOD GetPaletteInfo(nsPaletteInfo& aPaletteInfo);
NS_IMETHOD PrepareDocument(PRUnichar * aTitle,
PRUnichar* aPrintToFileName) { return NS_OK; }
NS_IMETHOD AbortDocument(void) { return NS_OK; }
NS_IMETHOD PrepareNativeWidget(nsIWidget *aWidget, void **aOut);
NS_IMETHOD ClearCachedSystemFonts();
private:
/* Helper methods for |CreateRenderingContext|&co. */
nsresult InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWindow);
protected:
virtual ~DeviceContextImpl();
void CommonInit(void);
nsresult CreateIconILGroupContext();
virtual nsresult CreateFontAliasTable();
nsresult AliasFont(const nsString& aFont,
const nsString& aAlias, const nsString& aAltAlias,
PRBool aForceAlias);
void GetLocaleLangGroup(void);
nsFontCache *mFontCache;
nsCOMPtr<nsIAtom> mLocaleLangGroup; // XXX temp fix for performance bug - erik
nsHashtable* mFontAliasTable;
public:
nsNativeWidget mWidget;
#ifdef NS_DEBUG
PRBool mInitialized;
#endif
};
#undef IMETHOD_VISIBILITY
#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
#endif /* nsDeviceContext_h___ */

View File

@ -67,7 +67,6 @@ endif
CPPSRCS = \
nsColor.cpp \
nsDeviceContext.cpp \
nsFont.cpp \
nsRect.cpp \
nsRegion.cpp \

View File

@ -1,609 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
* IBM Corp.
*
* 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 ***** */
#include "nsDeviceContext.h"
#include "nsFont.h"
#include "nsIView.h"
#include "nsGfxCIID.h"
#include "nsIFontMetrics.h"
#include "nsHashtable.h"
#include "nsILanguageAtomService.h"
#include "nsIServiceManager.h"
#include "nsUnicharUtils.h"
#include "nsCRT.h"
#include "nsIRenderingContext.h"
#include "gfxUserFontSet.h"
#include "nsIThebesFontMetrics.h"
NS_IMPL_ISUPPORTS3(DeviceContextImpl, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
DeviceContextImpl::DeviceContextImpl()
{
mAppUnitsPerDevPixel = -1;
mAppUnitsPerInch = -1;
mAppUnitsPerDevNotScaledPixel = -1;
mPixelScale = 1.0f;
mFontCache = nsnull;
mWidget = nsnull;
mFontAliasTable = nsnull;
#ifdef NS_DEBUG
mInitialized = PR_FALSE;
#endif
}
static PRBool DeleteValue(nsHashKey* aKey, void* aValue, void* closure)
{
delete ((nsString*)aValue);
return PR_TRUE;
}
DeviceContextImpl::~DeviceContextImpl()
{
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
if (obs)
obs->RemoveObserver(this, "memory-pressure");
if (nsnull != mFontCache)
{
delete mFontCache;
mFontCache = nsnull;
}
if (nsnull != mFontAliasTable) {
mFontAliasTable->Enumerate(DeleteValue);
delete mFontAliasTable;
}
}
NS_IMETHODIMP
DeviceContextImpl::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
{
if (mFontCache && !nsCRT::strcmp(aTopic, "memory-pressure")) {
mFontCache->Compact();
}
return NS_OK;
}
NS_IMETHODIMP DeviceContextImpl::Init(nsNativeWidget aWidget)
{
mWidget = aWidget;
CommonInit();
return NS_OK;
}
void DeviceContextImpl::CommonInit(void)
{
#ifdef NS_DEBUG
NS_ASSERTION(!mInitialized, "device context is initialized twice!");
mInitialized = PR_TRUE;
#endif
// register as a memory-pressure observer to free font resources
// in low-memory situations.
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
if (obs)
obs->AddObserver(this, "memory-pressure", PR_TRUE);
}
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext)
{
nsresult rv;
aContext = nsnull;
nsCOMPtr<nsIRenderingContext> pContext;
rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
if (NS_SUCCEEDED(rv)) {
rv = InitRenderingContext(pContext, aView->GetWidget());
if (NS_SUCCEEDED(rv)) {
aContext = pContext;
NS_ADDREF(aContext);
}
}
return rv;
}
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext)
{
nsresult rv;
aContext = nsnull;
nsCOMPtr<nsIRenderingContext> pContext;
rv = CreateRenderingContextInstance(*getter_AddRefs(pContext));
if (NS_SUCCEEDED(rv)) {
rv = InitRenderingContext(pContext, aWidget);
if (NS_SUCCEEDED(rv)) {
aContext = pContext;
NS_ADDREF(aContext);
}
}
return rv;
}
NS_IMETHODIMP DeviceContextImpl::CreateRenderingContextInstance(nsIRenderingContext *&aContext)
{
static NS_DEFINE_CID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
nsresult rv;
nsCOMPtr<nsIRenderingContext> pContext = do_CreateInstance(kRenderingContextCID, &rv);
if (NS_SUCCEEDED(rv)) {
aContext = pContext;
NS_ADDREF(aContext);
}
return rv;
}
nsresult DeviceContextImpl::InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWin)
{
return aContext->Init(this, aWin);
}
NS_IMETHODIMP DeviceContextImpl::CreateFontCache()
{
mFontCache = new nsFontCache();
if (!mFontCache) {
return NS_ERROR_OUT_OF_MEMORY;
}
return mFontCache->Init(this);
}
NS_IMETHODIMP DeviceContextImpl::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
{
if (mFontCache) {
mFontCache->FontMetricsDeleted(aFontMetrics);
}
return NS_OK;
}
void
DeviceContextImpl::GetLocaleLangGroup(void)
{
if (!mLocaleLangGroup) {
nsCOMPtr<nsILanguageAtomService> langService;
langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
if (langService) {
mLocaleLangGroup = langService->GetLocaleLanguageGroup();
}
if (!mLocaleLangGroup) {
mLocaleLangGroup = do_GetAtom("x-western");
}
}
}
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
nsIAtom* aLangGroup, gfxUserFontSet *aUserFontSet, nsIFontMetrics*& aMetrics)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
if (NS_FAILED(rv)) {
aMetrics = nsnull;
return rv;
}
// XXX temporary fix for performance problem -- erik
GetLocaleLangGroup();
}
// XXX figure out why aLangGroup is NULL sometimes
if (!aLangGroup) {
aLangGroup = mLocaleLangGroup;
}
return mFontCache->GetMetricsFor(aFont, aLangGroup, aUserFontSet, aMetrics);
}
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
gfxUserFontSet *aUserFontSet,
nsIFontMetrics*& aMetrics)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
if (NS_FAILED(rv)) {
aMetrics = nsnull;
return rv;
}
// XXX temporary fix for performance problem -- erik
GetLocaleLangGroup();
}
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aUserFontSet,
aMetrics);
}
NS_IMETHODIMP DeviceContextImpl::GetDepth(PRUint32& aDepth)
{
aDepth = 24;
return NS_OK;
}
NS_IMETHODIMP DeviceContextImpl::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
{
aPaletteInfo.isPaletteDevice = PR_FALSE;
aPaletteInfo.sizePalette = 0;
aPaletteInfo.numReserved = 0;
aPaletteInfo.palette = nsnull;
return NS_OK;
}
struct FontEnumData {
FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName)
: mDC(aDC), mFaceName(aFaceName)
{}
nsIDeviceContext* mDC;
nsString& mFaceName;
};
static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
{
FontEnumData* data = (FontEnumData*)aData;
// XXX for now, all generic fonts are presumed to exist
// we may want to actually check if there's an installed conversion
if (aGeneric) {
data->mFaceName = aFamily;
return PR_FALSE; // found one, stop.
}
else {
nsAutoString local;
PRBool aliased;
data->mDC->GetLocalFontName(aFamily, local, aliased);
if (aliased || (NS_SUCCEEDED(data->mDC->CheckFontExistence(local)))) {
data->mFaceName = local;
return PR_FALSE; // found one, stop.
}
}
return PR_TRUE; // didn't exist, continue looking
}
NS_IMETHODIMP DeviceContextImpl::FirstExistingFont(const nsFont& aFont, nsString& aFaceName)
{
FontEnumData data(this, aFaceName);
if (aFont.EnumerateFamilies(FontEnumCallback, &data)) {
return NS_ERROR_FAILURE; // ran out
}
return NS_OK;
}
class FontAliasKey: public nsHashKey
{
public:
FontAliasKey(const nsString& aString)
{mString.Assign(aString);}
virtual PRUint32 HashCode(void) const;
virtual PRBool Equals(const nsHashKey *aKey) const;
virtual nsHashKey *Clone(void) const;
nsString mString;
};
PRUint32 FontAliasKey::HashCode(void) const
{
PRUint32 hash = 0;
const PRUnichar* string = mString.get();
PRUnichar ch;
while ((ch = *string++) != 0) {
// FYI: hash = hash*37 + ch
ch = ToUpperCase(ch);
hash = ((hash << 5) + (hash << 2) + hash) + ch;
}
return hash;
}
PRBool FontAliasKey::Equals(const nsHashKey *aKey) const
{
return mString.Equals(((FontAliasKey*)aKey)->mString, nsCaseInsensitiveStringComparator());
}
nsHashKey* FontAliasKey::Clone(void) const
{
return new FontAliasKey(mString);
}
nsresult DeviceContextImpl::CreateFontAliasTable()
{
nsresult result = NS_OK;
if (nsnull == mFontAliasTable) {
mFontAliasTable = new nsHashtable();
if (nsnull != mFontAliasTable) {
nsAutoString times; times.AssignLiteral("Times");
nsAutoString timesNewRoman; timesNewRoman.AssignLiteral("Times New Roman");
nsAutoString timesRoman; timesRoman.AssignLiteral("Times Roman");
nsAutoString arial; arial.AssignLiteral("Arial");
nsAutoString helvetica; helvetica.AssignLiteral("Helvetica");
nsAutoString courier; courier.AssignLiteral("Courier");
nsAutoString courierNew; courierNew.AssignLiteral("Courier New");
nsAutoString nullStr;
AliasFont(times, timesNewRoman, timesRoman, PR_FALSE);
AliasFont(timesRoman, timesNewRoman, times, PR_FALSE);
AliasFont(timesNewRoman, timesRoman, times, PR_FALSE);
AliasFont(arial, helvetica, nullStr, PR_FALSE);
AliasFont(helvetica, arial, nullStr, PR_FALSE);
AliasFont(courier, courierNew, nullStr, PR_TRUE);
AliasFont(courierNew, courier, nullStr, PR_FALSE);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
return result;
}
nsresult DeviceContextImpl::AliasFont(const nsString& aFont,
const nsString& aAlias, const nsString& aAltAlias,
PRBool aForceAlias)
{
nsresult result = NS_OK;
if (nsnull != mFontAliasTable) {
if (aForceAlias || NS_FAILED(CheckFontExistence(aFont))) {
if (NS_SUCCEEDED(CheckFontExistence(aAlias))) {
nsString* entry = new nsString(aAlias);
if (nsnull != entry) {
FontAliasKey key(aFont);
mFontAliasTable->Put(&key, entry);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
else if (!aAltAlias.IsEmpty() && NS_SUCCEEDED(CheckFontExistence(aAltAlias))) {
nsString* entry = new nsString(aAltAlias);
if (nsnull != entry) {
FontAliasKey key(aFont);
mFontAliasTable->Put(&key, entry);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
else {
result = NS_ERROR_FAILURE;
}
return result;
}
NS_IMETHODIMP DeviceContextImpl::GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
PRBool& aAliased)
{
nsresult result = NS_OK;
if (nsnull == mFontAliasTable) {
result = CreateFontAliasTable();
}
if (nsnull != mFontAliasTable) {
FontAliasKey key(aFaceName);
const nsString* alias = (const nsString*)mFontAliasTable->Get(&key);
if (nsnull != alias) {
aLocalName = *alias;
aAliased = PR_TRUE;
}
else {
aLocalName = aFaceName;
aAliased = PR_FALSE;
}
}
return result;
}
NS_IMETHODIMP DeviceContextImpl::FlushFontCache(void)
{
if (nsnull != mFontCache)
mFontCache->Flush();
return NS_OK;
}
/////////////////////////////////////////////////////////////
nsFontCache::nsFontCache()
{
MOZ_COUNT_CTOR(nsFontCache);
mContext = nsnull;
}
nsFontCache::~nsFontCache()
{
MOZ_COUNT_DTOR(nsFontCache);
Flush();
}
nsresult
nsFontCache::Init(nsIDeviceContext* aContext)
{
NS_PRECONDITION(nsnull != aContext, "null ptr");
// Note: we don't hold a reference to the device context, because it
// holds a reference to us and we don't want circular references
mContext = aContext;
return NS_OK;
}
nsresult
nsFontCache::GetDeviceContext(nsIDeviceContext *&aContext) const
{
aContext = mContext;
NS_IF_ADDREF(aContext);
return NS_OK;
}
nsresult
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet *aUserFontSet, nsIFontMetrics *&aMetrics)
{
// First check our cache
// start from the end, which is where we put the most-recent-used element
nsIFontMetrics* fm;
PRInt32 n = mFontMetrics.Length() - 1;
for (PRInt32 i = n; i >= 0; --i) {
fm = mFontMetrics[i];
nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm);
if (fm->Font().Equals(aFont) && tfm->GetUserFontSet() == aUserFontSet) {
nsCOMPtr<nsIAtom> langGroup;
fm->GetLangGroup(getter_AddRefs(langGroup));
if (aLangGroup == langGroup.get()) {
if (i != n) {
// promote it to the end of the cache
mFontMetrics.RemoveElementAt(i);
mFontMetrics.AppendElement(fm);
}
tfm->GetThebesFontGroup()->UpdateFontList();
NS_ADDREF(aMetrics = fm);
return NS_OK;
}
}
}
// It's not in the cache. Get font metrics and then cache them.
aMetrics = nsnull;
nsresult rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
// the mFontMetrics list has the "head" at the end, because append is
// cheaper than insert
mFontMetrics.AppendElement(fm);
aMetrics = fm;
NS_ADDREF(aMetrics);
return NS_OK;
}
fm->Destroy();
NS_RELEASE(fm);
// One reason why Init() fails is because the system is running out of resources.
// e.g., on Win95/98 only a very limited number of GDI objects are available.
// Compact the cache and try again.
Compact();
rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
mFontMetrics.AppendElement(fm);
aMetrics = fm;
NS_ADDREF(aMetrics);
return NS_OK;
}
fm->Destroy();
NS_RELEASE(fm);
// could not setup a new one, send an old one (XXX search a "best match"?)
n = mFontMetrics.Length() - 1; // could have changed in Compact()
if (n >= 0) {
aMetrics = mFontMetrics[n];
NS_ADDREF(aMetrics);
return NS_OK;
}
NS_POSTCONDITION(NS_SUCCEEDED(rv), "font metrics should not be null - bug 136248");
return rv;
}
/* PostScript module may override this method to create
* nsIFontMetrics objects with their own classes
*/
nsresult
nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
{
static NS_DEFINE_CID(kFontMetricsCID, NS_FONT_METRICS_CID);
return CallCreateInstance(kFontMetricsCID, fm);
}
nsresult nsFontCache::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
{
mFontMetrics.RemoveElement(aFontMetrics);
return NS_OK;
}
nsresult nsFontCache::Compact()
{
// Need to loop backward because the running element can be removed on the way
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
nsIFontMetrics* fm = mFontMetrics[i];
nsIFontMetrics* oldfm = fm;
// Destroy() isn't here because we want our device context to be notified
NS_RELEASE(fm); // this will reset fm to nsnull
// if the font is really gone, it would have called back in
// FontMetricsDeleted() and would have removed itself
if (mFontMetrics.IndexOf(oldfm) >= 0) {
// nope, the font is still there, so let's hold onto it too
NS_ADDREF(oldfm);
}
}
return NS_OK;
}
nsresult nsFontCache::Flush()
{
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
nsIFontMetrics* fm = mFontMetrics[i];
// Destroy() will unhook our device context from the fm so that we won't
// waste time in triggering the notification of FontMetricsDeleted()
// in the subsequent release
fm->Destroy();
NS_RELEASE(fm);
}
mFontMetrics.Clear();
return NS_OK;
}
NS_IMETHODIMP
DeviceContextImpl::PrepareNativeWidget(nsIWidget *aWidget, void **aOut)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
DeviceContextImpl::ClearCachedSystemFonts()
{
return NS_OK;
}

View File

@ -1,201 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#ifndef nsRenderingContextImpl_h___
#define nsRenderingContextImpl_h___
#include "gfxCore.h"
#include "nsIRenderingContext.h"
#include "nsPoint.h"
#include "nsSize.h"
class gfxContext;
class nsRenderingContextImpl : public nsIRenderingContext
{
// CLASS MEMBERS
public:
nsRenderingContextImpl();
// CLASS METHODS
/**
* Return the maximum length of a string that can be handled by the platform
* using the current font metrics.
* The implementation here is just a stub; classes that don't override
* the safe string methods need to implement this.
*/
virtual PRInt32 GetMaxStringLength() = 0;
/**
* Let the device context know whether we want text reordered with
* right-to-left base direction
*/
NS_IMETHOD GetRightToLeftText(PRBool* aIsRTL);
// Safe string method variants: by default, these defer to the more
// elaborate methods below
NS_IMETHOD GetWidth(const nsString& aString, nscoord &aWidth,
PRInt32 *aFontID = nsnull);
NS_IMETHOD GetWidth(const char* aString, nscoord& aWidth);
NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull);
// Safe string methods
NS_IMETHOD GetWidth(const char* aString, PRUint32 aLength,
nscoord& aWidth);
NS_IMETHOD GetWidth(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID = nsnull);
NS_IMETHOD GetTextDimensions(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions);
NS_IMETHOD GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
nsTextDimensions& aDimensions, PRInt32* aFontID = nsnull);
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS)
NS_IMETHOD GetTextDimensions(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
#endif
#ifdef MOZ_MATHML
NS_IMETHOD
GetBoundingMetrics(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
NS_IMETHOD
GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID = nsnull);
#endif
NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing = nsnull);
NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull);
// Unsafe platform-specific implementations
NS_IMETHOD GetWidthInternal(const char* aString, PRUint32 aLength,
nscoord& aWidth)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD GetWidthInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD GetTextDimensionsInternal(const PRUnichar* aString, PRUint32 aLength,
nsTextDimensions& aDimensions, PRInt32* aFontID = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS)
NS_IMETHOD GetTextDimensionsInternal(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD GetTextDimensionsInternal(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
#endif
#ifdef MOZ_MATHML
NS_IMETHOD
GetBoundingMetricsInternal(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD
GetBoundingMetricsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
#endif
NS_IMETHOD DrawStringInternal(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull)
{ return NS_ERROR_NOT_IMPLEMENTED; }
gfxContext *ThebesContext() { return nsnull; }
protected:
virtual ~nsRenderingContextImpl();
};
#endif /* nsRenderingContextImpl */

View File

@ -57,7 +57,6 @@ REQUIRES= \
$(NULL)
CPPSRCS = \
nsRenderingContextImpl.cpp \
gfxImageFrame.cpp \
$(NULL)

View File

@ -1,508 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#include "nsCOMPtr.h"
#include "nsRenderingContextImpl.h"
#include "nsIDeviceContext.h"
#include "nsIImage.h"
#include "nsIRegion.h"
#include "nsIFontMetrics.h"
#include <stdlib.h>
/** ---------------------------------------------------
* See documentation in nsIRenderingContext.h
* @update 3/16/00 dwc
*/
nsRenderingContextImpl :: nsRenderingContextImpl()
{
}
/** ---------------------------------------------------
* See documentation in nsIRenderingContext.h
* @update 3/16/00 dwc
*/
nsRenderingContextImpl :: ~nsRenderingContextImpl()
{
}
NS_IMETHODIMP
nsRenderingContextImpl::GetRightToLeftText(PRBool* aIsRTL)
{
*aIsRTL = PR_FALSE;
return NS_OK;
}
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
// Hard limit substring lengths to 8000 characters ... this lets us statically
// size the cluster buffer array in FindSafeLength
#define MAX_GFX_TEXT_BUF_SIZE 8000
static PRInt32 GetMaxChunkLength(nsRenderingContextImpl* aContext)
{
PRInt32 len = aContext->GetMaxStringLength();
return PR_MIN(len, MAX_GFX_TEXT_BUF_SIZE);
}
static PRInt32 FindSafeLength(nsRenderingContextImpl* aContext,
const PRUnichar *aString, PRUint32 aLength,
PRUint32 aMaxChunkLength)
{
if (aLength <= aMaxChunkLength)
return aLength;
PRInt32 len = aMaxChunkLength;
// Ensure that we don't break inside a surrogate pair
while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
len--;
}
if (len == 0) {
// We don't want our caller to go into an infinite loop, so don't return
// zero. It's hard to imagine how we could actually get here unless there
// are languages that allow clusters of arbitrary size. If there are and
// someone feeds us a 500+ character cluster, too bad.
return aMaxChunkLength;
}
return len;
}
static PRInt32 FindSafeLength(nsRenderingContextImpl* aContext,
const char *aString, PRUint32 aLength,
PRUint32 aMaxChunkLength)
{
// Since it's ASCII, we don't need to worry about clusters or RTL
return PR_MIN(aLength, aMaxChunkLength);
}
NS_IMETHODIMP
nsRenderingContextImpl::GetWidth(const nsString& aString, nscoord &aWidth,
PRInt32 *aFontID)
{
return GetWidth(aString.get(), aString.Length(), aWidth, aFontID);
}
NS_IMETHODIMP
nsRenderingContextImpl::GetWidth(const char* aString, nscoord& aWidth)
{
return GetWidth(aString, strlen(aString), aWidth);
}
NS_IMETHODIMP
nsRenderingContextImpl::DrawString(const nsString& aString, nscoord aX, nscoord aY,
PRInt32 aFontID, const nscoord* aSpacing)
{
return DrawString(aString.get(), aString.Length(), aX, aY, aFontID, aSpacing);
}
NS_IMETHODIMP
nsRenderingContextImpl::GetWidth(const char* aString, PRUint32 aLength,
nscoord& aWidth)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
aWidth = 0;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width;
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aWidth += width;
aLength -= len;
aString += len;
}
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetWidth(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
aWidth = 0;
if (aFontID) {
*aFontID = 0;
}
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width;
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aWidth += width;
aLength -= len;
aString += len;
}
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetTextDimensions(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetTextDimensionsInternal(aString, aLength, aDimensions);
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsTextDimensions dimensions;
nsresult rv = GetTextDimensionsInternal(aString, len, dimensions);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsTextDimensions, we assign
// directly in the first iteration. This ensures that negative ascent/
// descent can be returned.
aDimensions = dimensions;
} else {
aDimensions.Combine(dimensions);
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
nsTextDimensions& aDimensions, PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetTextDimensionsInternal(aString, aLength, aDimensions);
if (aFontID) {
*aFontID = nsnull;
}
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsTextDimensions dimensions;
nsresult rv = GetTextDimensionsInternal(aString, len, dimensions);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsTextDimensions, we assign
// directly in the first iteration. This ensures that negative ascent/
// descent can be returned.
aDimensions = dimensions;
} else {
aDimensions.Combine(dimensions);
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS)
NS_IMETHODIMP
nsRenderingContextImpl::GetTextDimensions(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= PRInt32(maxChunkLength))
return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
if (aFontID) {
*aFontID = 0;
}
// Do a naive implementation based on 3-arg GetTextDimensions
PRInt32 x = 0;
PRInt32 wordCount;
for (wordCount = 0; wordCount < aNumBreaks; ++wordCount) {
PRInt32 lastBreak = wordCount > 0 ? aBreaks[wordCount - 1] : 0;
nsTextDimensions dimensions;
NS_ASSERTION(aBreaks[wordCount] > lastBreak, "Breaks must be monotonically increasing");
NS_ASSERTION(aBreaks[wordCount] <= aLength, "Breaks can't exceed string length");
// Call safe method
nsresult rv =
GetTextDimensions(aString + lastBreak, aBreaks[wordCount] - lastBreak,
dimensions);
if (NS_FAILED(rv))
return rv;
x += dimensions.width;
// The first word always "fits"
if (x > aAvailWidth && wordCount > 0)
break;
// aDimensions ascent/descent should exclude the last word (unless there
// is only one word) so we let it run one word behind
if (wordCount == 0) {
aDimensions = dimensions;
} else {
aDimensions.Combine(aLastWordDimensions);
}
aNumCharsFit = aBreaks[wordCount];
aLastWordDimensions = dimensions;
}
// aDimensions width should include all the text
aDimensions.width = x;
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetTextDimensions(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= PRInt32(maxChunkLength))
return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
if (aFontID) {
*aFontID = 0;
}
// Do a naive implementation based on 3-arg GetTextDimensions
PRInt32 x = 0;
PRInt32 wordCount;
for (wordCount = 0; wordCount < aNumBreaks; ++wordCount) {
PRInt32 lastBreak = wordCount > 0 ? aBreaks[wordCount - 1] : 0;
NS_ASSERTION(aBreaks[wordCount] > lastBreak, "Breaks must be monotonically increasing");
NS_ASSERTION(aBreaks[wordCount] <= aLength, "Breaks can't exceed string length");
nsTextDimensions dimensions;
// Call safe method
nsresult rv =
GetTextDimensions(aString + lastBreak, aBreaks[wordCount] - lastBreak,
dimensions);
if (NS_FAILED(rv))
return rv;
x += dimensions.width;
// The first word always "fits"
if (x > aAvailWidth && wordCount > 0)
break;
// aDimensions ascent/descent should exclude the last word (unless there
// is only one word) so we let it run one word behind
if (wordCount == 0) {
aDimensions = dimensions;
} else {
aDimensions.Combine(aLastWordDimensions);
}
aNumCharsFit = aBreaks[wordCount];
aLastWordDimensions = dimensions;
}
// aDimensions width should include all the text
aDimensions.width = x;
return NS_OK;
}
#endif
#ifdef MOZ_MATHML
NS_IMETHODIMP
nsRenderingContextImpl::GetBoundingMetrics(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetBoundingMetricsInternal(aString, aLength, aBoundingMetrics);
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsBoundingMetrics metrics;
nsresult rv = GetBoundingMetricsInternal(aString, len, metrics);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsBoundingMetrics, we assign
// directly in the first iteration. This ensures that negative ascent/
// descent can be returned and the left bearing is properly initialized.
aBoundingMetrics = metrics;
} else {
aBoundingMetrics += metrics;
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetBoundingMetricsInternal(aString, aLength, aBoundingMetrics, aFontID);
if (aFontID) {
*aFontID = 0;
}
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsBoundingMetrics metrics;
nsresult rv = GetBoundingMetricsInternal(aString, len, metrics);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsBoundingMetrics, we assign
// directly in the first iteration. This ensures that negative ascent/
// descent can be returned and the left bearing is properly initialized.
aBoundingMetrics = metrics;
} else {
aBoundingMetrics += metrics;
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
#endif
NS_IMETHODIMP
nsRenderingContextImpl::DrawString(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsresult rv = DrawStringInternal(aString, len, aX, aY);
if (NS_FAILED(rv))
return rv;
aLength -= len;
if (aLength > 0) {
nscoord width;
rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aX += width;
aString += len;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::DrawString(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,
const nscoord* aSpacing)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength) {
return DrawStringInternal(aString, aLength, aX, aY, aFontID, aSpacing);
}
PRBool isRTL = PR_FALSE;
GetRightToLeftText(&isRTL);
if (isRTL) {
nscoord totalWidth = 0;
if (aSpacing) {
for (PRUint32 i = 0; i < aLength; ++i) {
totalWidth += aSpacing[i];
}
} else {
nsresult rv = GetWidth(aString, aLength, totalWidth);
if (NS_FAILED(rv))
return rv;
}
aX += totalWidth;
}
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width = 0;
if (aSpacing) {
for (PRInt32 i = 0; i < len; ++i) {
width += aSpacing[i];
}
} else {
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
}
if (isRTL) {
aX -= width;
}
nsresult rv = DrawStringInternal(aString, len, aX, aY, aFontID, aSpacing);
if (NS_FAILED(rv))
return rv;
aLength -= len;
if (!isRTL) {
aX += width;
}
aString += len;
if (aSpacing) {
aSpacing += len;
}
}
return NS_OK;
}

View File

@ -57,6 +57,7 @@ REQUIRES = xpcom \
string \
thebes \
widget \
locale \
view \
pref \
unicharutil \
@ -65,6 +66,10 @@ REQUIRES = xpcom \
qcms \
$(NULL)
ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
REQUIRES += uconv
endif
CPPSRCS = \
nsThebesDeviceContext.cpp \
nsThebesImage.cpp \

View File

@ -37,12 +37,20 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsFont.h"
#include "nsGfxCIID.h"
#include "nsIFontMetrics.h"
#include "nsHashtable.h"
#include "nsILanguageAtomService.h"
#include "nsUnicharUtils.h"
#include "nsIServiceManager.h"
#include "nsIPrefService.h"
#include "nsCRT.h"
#include "nsThebesDeviceContext.h"
#include "nsThebesRenderingContext.h"
#include "gfxUserFontSet.h"
#include "nsIWidget.h"
#include "nsIView.h"
@ -114,7 +122,176 @@ static int x11_error_handler (Display *dpy, XErrorEvent *err) {
PRLogModuleInfo* gThebesGFXLog = nsnull;
#endif
NS_IMPL_ISUPPORTS_INHERITED0(nsThebesDeviceContext, DeviceContextImpl)
class nsFontCache
{
public:
nsFontCache();
~nsFontCache();
nsresult Init(nsIDeviceContext* aContext);
nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics);
nsresult FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
nsresult Compact();
nsresult Flush();
nsresult CreateFontMetricsInstance(nsIFontMetrics** fm);
protected:
nsTArray<nsIFontMetrics*> mFontMetrics;
nsIDeviceContext *mContext; // we do not addref this since
// ownership is implied. MMP.
};
nsFontCache::nsFontCache()
{
MOZ_COUNT_CTOR(nsFontCache);
mContext = nsnull;
}
nsFontCache::~nsFontCache()
{
MOZ_COUNT_DTOR(nsFontCache);
Flush();
}
nsresult
nsFontCache::Init(nsIDeviceContext* aContext)
{
NS_PRECONDITION(nsnull != aContext, "null ptr");
// Note: we don't hold a reference to the device context, because it
// holds a reference to us and we don't want circular references
mContext = aContext;
return NS_OK;
}
nsresult
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet* aUserFontSet, nsIFontMetrics*& aMetrics)
{
// First check our cache
// start from the end, which is where we put the most-recent-used element
nsIFontMetrics* fm;
PRInt32 n = mFontMetrics.Length() - 1;
for (PRInt32 i = n; i >= 0; --i) {
fm = mFontMetrics[i];
nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm);
if (fm->Font().Equals(aFont) && tfm->GetUserFontSet() == aUserFontSet) {
nsCOMPtr<nsIAtom> langGroup;
fm->GetLangGroup(getter_AddRefs(langGroup));
if (aLangGroup == langGroup.get()) {
if (i != n) {
// promote it to the end of the cache
mFontMetrics.RemoveElementAt(i);
mFontMetrics.AppendElement(fm);
}
tfm->GetThebesFontGroup()->UpdateFontList();
NS_ADDREF(aMetrics = fm);
return NS_OK;
}
}
}
// It's not in the cache. Get font metrics and then cache them.
aMetrics = nsnull;
nsresult rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
// the mFontMetrics list has the "head" at the end, because append
// is cheaper than insert
mFontMetrics.AppendElement(fm);
aMetrics = fm;
NS_ADDREF(aMetrics);
return NS_OK;
}
fm->Destroy();
NS_RELEASE(fm);
// One reason why Init() fails is because the system is running out of
// resources. e.g., on Win95/98 only a very limited number of GDI
// objects are available. Compact the cache and try again.
Compact();
rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
mFontMetrics.AppendElement(fm);
aMetrics = fm;
NS_ADDREF(aMetrics);
return NS_OK;
}
fm->Destroy();
NS_RELEASE(fm);
// could not setup a new one, send an old one (XXX search a "best
// match"?)
n = mFontMetrics.Length() - 1; // could have changed in Compact()
if (n >= 0) {
aMetrics = mFontMetrics[n];
NS_ADDREF(aMetrics);
return NS_OK;
}
NS_POSTCONDITION(NS_SUCCEEDED(rv), "font metrics should not be null - bug 136248");
return rv;
}
nsresult
nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
{
static NS_DEFINE_CID(kFontMetricsCID, NS_FONT_METRICS_CID);
return CallCreateInstance(kFontMetricsCID, fm);
}
nsresult nsFontCache::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
{
mFontMetrics.RemoveElement(aFontMetrics);
return NS_OK;
}
nsresult nsFontCache::Compact()
{
// Need to loop backward because the running element can be removed on
// the way
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
nsIFontMetrics* fm = mFontMetrics[i];
nsIFontMetrics* oldfm = fm;
// Destroy() isn't here because we want our device context to be
// notified
NS_RELEASE(fm); // this will reset fm to nsnull
// if the font is really gone, it would have called back in
// FontMetricsDeleted() and would have removed itself
if (mFontMetrics.IndexOf(oldfm) >= 0) {
// nope, the font is still there, so let's hold onto it too
NS_ADDREF(oldfm);
}
}
return NS_OK;
}
nsresult nsFontCache::Flush()
{
for (PRInt32 i = mFontMetrics.Length()-1; i >= 0; --i) {
nsIFontMetrics* fm = mFontMetrics[i];
// Destroy() will unhook our device context from the fm so that we
// won't waste time in triggering the notification of
// FontMetricsDeleted() in the subsequent release
fm->Destroy();
NS_RELEASE(fm);
}
mFontMetrics.Clear();
return NS_OK;
}
NS_IMPL_ISUPPORTS3(nsThebesDeviceContext, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
nsThebesDeviceContext::nsThebesDeviceContext()
{
@ -125,21 +302,305 @@ nsThebesDeviceContext::nsThebesDeviceContext()
PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("#### Creating DeviceContext %p\n", this));
mAppUnitsPerDevPixel = nscoord(-1);
mAppUnitsPerInch = nscoord(-1);
mAppUnitsPerDevNotScaledPixel = nscoord(-1);
mPixelScale = 1.0f;
mFontCache = nsnull;
mWidget = nsnull;
mFontAliasTable = nsnull;
#ifdef NS_DEBUG
mInitialized = PR_FALSE;
#endif
mDepth = 0;
mWidth = 0;
mHeight = 0;
mPrintingScale = 1.0f;
mWidgetSurfaceCache.Init();
#if defined(XP_WIN) && !defined(WINCE)
SCRIPT_DIGITSUBSTITUTE sds;
ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds);
#endif
}
static PRBool DeleteValue(nsHashKey* aKey, void* aValue, void* closure)
{
delete ((nsString*)aValue);
return PR_TRUE;
}
nsThebesDeviceContext::~nsThebesDeviceContext()
{
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
if (obs)
obs->RemoveObserver(this, "memory-pressure");
if (nsnull != mFontCache) {
delete mFontCache;
mFontCache = nsnull;
}
if (nsnull != mFontAliasTable) {
mFontAliasTable->Enumerate(DeleteValue);
delete mFontAliasTable;
}
}
NS_IMETHODIMP
nsThebesDeviceContext::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aSomeData)
{
if (mFontCache && !nsCRT::strcmp(aTopic, "memory-pressure")) {
mFontCache->Compact();
}
return NS_OK;
}
NS_IMETHODIMP nsThebesDeviceContext::CreateFontCache()
{
mFontCache = new nsFontCache();
if (!mFontCache) {
return NS_ERROR_OUT_OF_MEMORY;
}
return mFontCache->Init(this);
}
NS_IMETHODIMP nsThebesDeviceContext::FontMetricsDeleted(const nsIFontMetrics* aFontMetrics)
{
if (mFontCache) {
mFontCache->FontMetricsDeleted(aFontMetrics);
}
return NS_OK;
}
void
nsThebesDeviceContext::GetLocaleLangGroup(void)
{
if (!mLocaleLangGroup) {
nsCOMPtr<nsILanguageAtomService> langService;
langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
if (langService) {
mLocaleLangGroup = langService->GetLocaleLanguageGroup();
}
if (!mLocaleLangGroup) {
mLocaleLangGroup = do_GetAtom("x-western");
}
}
}
NS_IMETHODIMP nsThebesDeviceContext::GetMetricsFor(const nsFont& aFont,
nsIAtom* aLangGroup, gfxUserFontSet* aUserFontSet, nsIFontMetrics*& aMetrics)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
if (NS_FAILED(rv)) {
aMetrics = nsnull;
return rv;
}
// XXX temporary fix for performance problem -- erik
GetLocaleLangGroup();
}
// XXX figure out why aLangGroup is NULL sometimes
if (!aLangGroup) {
aLangGroup = mLocaleLangGroup;
}
return mFontCache->GetMetricsFor(aFont, aLangGroup, aUserFontSet, aMetrics);
}
NS_IMETHODIMP nsThebesDeviceContext::GetMetricsFor(const nsFont& aFont,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
if (NS_FAILED(rv)) {
aMetrics = nsnull;
return rv;
}
// XXX temporary fix for performance problem -- erik
GetLocaleLangGroup();
}
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aUserFontSet,
aMetrics);
}
struct FontEnumData {
FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName)
: mDC(aDC), mFaceName(aFaceName)
{}
nsIDeviceContext* mDC;
nsString& mFaceName;
};
static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
{
FontEnumData* data = (FontEnumData*)aData;
// XXX for now, all generic fonts are presumed to exist
// we may want to actually check if there's an installed conversion
if (aGeneric) {
data->mFaceName = aFamily;
return PR_FALSE; // found one, stop.
}
else {
nsAutoString local;
PRBool aliased;
data->mDC->GetLocalFontName(aFamily, local, aliased);
if (aliased || (NS_SUCCEEDED(data->mDC->CheckFontExistence(local)))) {
data->mFaceName = local;
return PR_FALSE; // found one, stop.
}
}
return PR_TRUE; // didn't exist, continue looking
}
NS_IMETHODIMP nsThebesDeviceContext::FirstExistingFont(const nsFont& aFont, nsString& aFaceName)
{
FontEnumData data(this, aFaceName);
if (aFont.EnumerateFamilies(FontEnumCallback, &data)) {
return NS_ERROR_FAILURE; // ran out
}
return NS_OK;
}
class FontAliasKey: public nsHashKey
{
public:
FontAliasKey(const nsString& aString)
{ mString.Assign(aString); }
virtual PRUint32 HashCode(void) const;
virtual PRBool Equals(const nsHashKey *aKey) const;
virtual nsHashKey *Clone(void) const;
nsString mString;
};
PRUint32 FontAliasKey::HashCode(void) const
{
PRUint32 hash = 0;
const PRUnichar* string = mString.get();
PRUnichar ch;
while ((ch = *string++) != 0) {
// FYI: hash = hash*37 + ch
ch = ToUpperCase(ch);
hash = ((hash << 5) + (hash << 2) + hash) + ch;
}
return hash;
}
PRBool FontAliasKey::Equals(const nsHashKey *aKey) const
{
return mString.Equals(((FontAliasKey*)aKey)->mString, nsCaseInsensitiveStringComparator());
}
nsHashKey* FontAliasKey::Clone(void) const
{
return new FontAliasKey(mString);
}
nsresult nsThebesDeviceContext::CreateFontAliasTable()
{
nsresult result = NS_OK;
if (nsnull == mFontAliasTable) {
mFontAliasTable = new nsHashtable();
if (nsnull != mFontAliasTable) {
nsAutoString times; times.AssignLiteral("Times");
nsAutoString timesNewRoman; timesNewRoman.AssignLiteral("Times New Roman");
nsAutoString timesRoman; timesRoman.AssignLiteral("Times Roman");
nsAutoString arial; arial.AssignLiteral("Arial");
nsAutoString helvetica; helvetica.AssignLiteral("Helvetica");
nsAutoString courier; courier.AssignLiteral("Courier");
nsAutoString courierNew; courierNew.AssignLiteral("Courier New");
nsAutoString nullStr;
AliasFont(times, timesNewRoman, timesRoman, PR_FALSE);
AliasFont(timesRoman, timesNewRoman, times, PR_FALSE);
AliasFont(timesNewRoman, timesRoman, times, PR_FALSE);
AliasFont(arial, helvetica, nullStr, PR_FALSE);
AliasFont(helvetica, arial, nullStr, PR_FALSE);
AliasFont(courier, courierNew, nullStr, PR_TRUE);
AliasFont(courierNew, courier, nullStr, PR_FALSE);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
return result;
}
nsresult nsThebesDeviceContext::AliasFont(const nsString& aFont,
const nsString& aAlias,
const nsString& aAltAlias,
PRBool aForceAlias)
{
nsresult result = NS_OK;
if (nsnull != mFontAliasTable) {
if (aForceAlias || NS_FAILED(CheckFontExistence(aFont))) {
if (NS_SUCCEEDED(CheckFontExistence(aAlias))) {
nsString* entry = new nsString(aAlias);
if (nsnull != entry) {
FontAliasKey key(aFont);
mFontAliasTable->Put(&key, entry);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
else if (!aAltAlias.IsEmpty() && NS_SUCCEEDED(CheckFontExistence(aAltAlias))) {
nsString* entry = new nsString(aAltAlias);
if (nsnull != entry) {
FontAliasKey key(aFont);
mFontAliasTable->Put(&key, entry);
}
else {
result = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
else {
result = NS_ERROR_FAILURE;
}
return result;
}
NS_IMETHODIMP nsThebesDeviceContext::GetLocalFontName(const nsString& aFaceName,
nsString& aLocalName,
PRBool& aAliased)
{
nsresult result = NS_OK;
if (nsnull == mFontAliasTable) {
result = CreateFontAliasTable();
}
if (nsnull != mFontAliasTable) {
FontAliasKey key(aFaceName);
const nsString* alias = (const nsString*)mFontAliasTable->Get(&key);
if (nsnull != alias) {
aLocalName = *alias;
aAliased = PR_TRUE;
}
else {
aLocalName = aFaceName;
aAliased = PR_FALSE;
}
}
return result;
}
NS_IMETHODIMP nsThebesDeviceContext::FlushFontCache(void)
{
if (nsnull != mFontCache)
mFontCache->Flush();
return NS_OK;
}
/* static */ void
@ -288,6 +749,16 @@ nsThebesDeviceContext::Init(nsNativeWidget aWidget)
SetDPI();
#ifdef NS_DEBUG
//NS_ASSERTION(!mInitialized, "device context is initialized twice!");
mInitialized = PR_TRUE;
#endif
// register as a memory-pressure observer to free font resources
// in low-memory situations.
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
if (obs)
obs->AddObserver(this, "memory-pressure", PR_TRUE);
#if defined(MOZ_ENABLE_GTK2) && defined(MOZ_X11)
if (getenv ("MOZ_X_SYNC")) {
@ -467,7 +938,6 @@ nsThebesDeviceContext::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
return NS_OK;
}
NS_IMETHODIMP
nsThebesDeviceContext::ConvertPixel(nscolor aColor, PRUint32 & aPixel)
{
@ -554,7 +1024,7 @@ nsThebesDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
NS_IMETHODIMP
nsThebesDeviceContext::PrepareDocument(PRUnichar * aTitle,
nsThebesDeviceContext::PrepareDocument(PRUnichar * aTitle,
PRUnichar* aPrintToFileName)
{
return NS_OK;
@ -562,9 +1032,9 @@ nsThebesDeviceContext::PrepareDocument(PRUnichar * aTitle,
NS_IMETHODIMP
nsThebesDeviceContext::BeginDocument(PRUnichar* aTitle,
nsThebesDeviceContext::BeginDocument(PRUnichar* aTitle,
PRUnichar* aPrintToFileName,
PRInt32 aStartPage,
PRInt32 aStartPage,
PRInt32 aEndPage)
{
static const PRUnichar kEmpty[] = { '\0' };
@ -661,7 +1131,7 @@ nsThebesDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
if (screen) {
PRInt32 x, y, width, height;
screen->GetAvailRect(&x, &y, &width, &height);
// convert to device units
outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
@ -682,20 +1152,18 @@ nsThebesDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
if ( screen ) {
PRInt32 x, y, width, height;
screen->GetRect ( &x, &y, &width, &height );
// convert to device units
outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel());
outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel());
outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel());
outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel());
mWidth = outRect->width;
mHeight = outRect->height;
}
}
//
// FindScreen
//

View File

@ -41,16 +41,20 @@
#define _NS_THEBESDEVICECONTEXT_H_
#include "nsIScreenManager.h"
#include "nsDeviceContext.h"
#include "nsIDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsWeakReference.h"
#include "gfxContext.h"
#include "nsRefPtrHashtable.h"
#include "nsHashKeys.h"
#include "prlog.h"
#include "gfxContext.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gThebesGFXLog;
#endif
@ -61,7 +65,12 @@ extern PRLogModuleInfo* gThebesGFXLog;
#include "gfxOS2Surface.h"
#endif
class nsThebesDeviceContext : public DeviceContextImpl
class nsHashtable;
class nsFontCache;
class nsThebesDeviceContext : public nsIDeviceContext,
public nsIObserver,
public nsSupportsWeakReference
{
public:
nsThebesDeviceContext();
@ -69,16 +78,32 @@ public:
static void Shutdown();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_IMETHOD Init(nsNativeWidget aWidget);
NS_IMETHOD InitForPrinting(nsIDeviceContextSpec *aDevSpec);
NS_IMETHOD CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext);
NS_IMETHOD CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext);
NS_IMETHOD CreateRenderingContext(nsIRenderingContext *&aContext);
NS_IMETHOD CreateRenderingContextInstance(nsIRenderingContext *&aContext);
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics);
NS_IMETHOD GetMetricsFor(const nsFont& aFont,
gfxUserFontSet* aUserFontSet,
nsIFontMetrics*& aMetrics);
NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);
NS_IMETHOD GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
PRBool& aAliased);
NS_IMETHOD CreateFontCache();
NS_IMETHOD FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
NS_IMETHOD FlushFontCache(void);
NS_IMETHOD SupportsNativeWidgets(PRBool& aSupportsWidgets);
NS_IMETHOD PrepareNativeWidget(nsIWidget *aWidget, void **aOut);
@ -93,7 +118,7 @@ public:
NS_IMETHOD ConvertPixel(nscolor aColor, PRUint32& aPixel);
NS_IMETHOD GetDeviceSurfaceDimensions(PRInt32& aWidth, PRInt32& aHeight);
NS_IMETHOD GetDeviceSurfaceDimensions(nscoord& aWidth, nscoord& aHeight);
NS_IMETHOD GetRect(nsRect& aRect);
NS_IMETHOD GetClientRect(nsRect& aRect);
@ -126,6 +151,11 @@ public:
#endif
protected:
virtual nsresult CreateFontAliasTable();
nsresult AliasFont(const nsString& aFont,
const nsString& aAlias, const nsString& aAltAlias,
PRBool aForceAlias);
void GetLocaleLangGroup(void);
nsresult SetDPI();
void ComputeClientRectUsingScreen(nsRect *outRect);
void ComputeFullAreaUsingScreen(nsRect *outRect);
@ -133,7 +163,14 @@ protected:
void CalcPrintingSize();
void UpdateScaledAppUnits();
PRUint32 mDepth;
PRUint32 mDepth;
nsFontCache* mFontCache;
nsCOMPtr<nsIAtom> mLocaleLangGroup; // XXX temp fix for performance bug - erik
nsHashtable* mFontAliasTable;
nsNativeWidget mWidget;
#ifdef NS_DEBUG
PRBool mInitialized;
#endif
private:
nsCOMPtr<nsIScreenManager> mScreenManager;
@ -141,8 +178,6 @@ private:
nscoord mWidth;
nscoord mHeight;
nsRefPtrHashtable<nsISupportsHashKey, gfxASurface> mWidgetSurfaceCache;
nsRefPtr<gfxASurface> mPrintingSurface;
float mPrintingScale;
nsCOMPtr<nsIDeviceContextSpec> mDeviceContextSpec;

View File

@ -40,10 +40,8 @@
#include "nsThebesRenderingContext.h"
#include "nsThebesDeviceContext.h"
#include "nsRect.h"
#include "nsString.h"
#include "nsTransform2D.h"
#include "nsIRegion.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsGfxCIID.h"
@ -52,10 +50,10 @@
#include "gfxIImageFrame.h"
#include "nsIImage.h"
#include "nsIThebesFontMetrics.h"
#include "nsThebesRegion.h"
#include "nsThebesImage.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -81,6 +79,47 @@ static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
NS_IMPL_ISUPPORTS1(nsThebesRenderingContext, nsIRenderingContext)
// Hard limit substring lengths to 8000 characters ... this lets us statically
// size the cluster buffer array in FindSafeLength
#define MAX_GFX_TEXT_BUF_SIZE 8000
static PRInt32 GetMaxChunkLength(nsThebesRenderingContext* aContext)
{
PRInt32 len = aContext->GetMaxStringLength();
return PR_MIN(len, MAX_GFX_TEXT_BUF_SIZE);
}
static PRInt32 FindSafeLength(nsThebesRenderingContext* aContext,
const PRUnichar *aString, PRUint32 aLength,
PRUint32 aMaxChunkLength)
{
if (aLength <= aMaxChunkLength)
return aLength;
PRInt32 len = aMaxChunkLength;
// Ensure that we don't break inside a surrogate pair
while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
len--;
}
if (len == 0) {
// We don't want our caller to go into an infinite loop, so don't
// return zero. It's hard to imagine how we could actually get here
// unless there are languages that allow clusters of arbitrary size.
// If there are and someone feeds us a 500+ character cluster, too
// bad.
return aMaxChunkLength;
}
return len;
}
static PRInt32 FindSafeLength(nsThebesRenderingContext* aContext,
const char *aString, PRUint32 aLength,
PRUint32 aMaxChunkLength)
{
// Since it's ASCII, we don't need to worry about clusters or RTL
return PR_MIN(aLength, aMaxChunkLength);
}
nsThebesRenderingContext::nsThebesRenderingContext()
: mLineStyle(nsLineStyle_kNone)
, mColor(NS_RGB(0,0,0))
@ -159,7 +198,7 @@ nsThebesRenderingContext::GetDeviceContext(nsIDeviceContext *& aDeviceContext)
return NS_OK;
}
NS_IMETHODIMP
NS_IMETHODIMP
nsThebesRenderingContext::PushTranslation(PushedTranslation* aState)
{
PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PushTranslation\n", this));
@ -298,6 +337,7 @@ nsThebesRenderingContext::SetClipRegion(const nsIRegion& pxRegion,
return NS_OK;
}
//
// other junk
//
@ -336,7 +376,7 @@ nsThebesRenderingContext::SetColor(nscolor aColor)
* CSS colors are defined to be in by the spec.
*/
mThebes->SetColor(gfxRGBA(aColor));
mColor = aColor;
return NS_OK;
}
@ -780,7 +820,7 @@ nsThebesRenderingContext::GetRightToLeftText(PRBool* aIsRTL)
void
nsThebesRenderingContext::SetTextRunRTL(PRBool aIsRTL)
{
mFontMetrics->SetTextRunRTL(aIsRTL);
mFontMetrics->SetTextRunRTL(aIsRTL);
}
NS_IMETHODIMP
@ -816,9 +856,9 @@ nsThebesRenderingContext::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
PRInt32
nsThebesRenderingContext::GetMaxStringLength()
{
if (!mFontMetrics)
return 1;
return mFontMetrics->GetMaxStringLength();
if (!mFontMetrics)
return 1;
return mFontMetrics->GetMaxStringLength();
}
NS_IMETHODIMP
@ -837,6 +877,407 @@ nsThebesRenderingContext::GetWidth(PRUnichar aC, nscoord &aWidth, PRInt32 *aFont
}
NS_IMETHODIMP
nsThebesRenderingContext::GetWidth(const nsString& aString, nscoord &aWidth,
PRInt32 *aFontID)
{
return GetWidth(aString.get(), aString.Length(), aWidth, aFontID);
}
NS_IMETHODIMP
nsThebesRenderingContext::GetWidth(const char* aString, nscoord& aWidth)
{
return GetWidth(aString, strlen(aString), aWidth);
}
NS_IMETHODIMP
nsThebesRenderingContext::DrawString(const nsString& aString, nscoord aX, nscoord aY,
PRInt32 aFontID, const nscoord* aSpacing)
{
return DrawString(aString.get(), aString.Length(), aX, aY, aFontID, aSpacing);
}
NS_IMETHODIMP
nsThebesRenderingContext::GetWidth(const char* aString,
PRUint32 aLength,
nscoord& aWidth)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
aWidth = 0;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width;
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aWidth += width;
aLength -= len;
aString += len;
}
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetWidth(const PRUnichar *aString,
PRUint32 aLength,
nscoord &aWidth,
PRInt32 *aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
aWidth = 0;
if (aFontID) {
*aFontID = 0;
}
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width;
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aWidth += width;
aLength -= len;
aString += len;
}
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetTextDimensions(const char* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetTextDimensionsInternal(aString, aLength, aDimensions);
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsTextDimensions dimensions;
nsresult rv = GetTextDimensionsInternal(aString, len, dimensions);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsTextDimensions, we
// assign directly in the first iteration. This ensures that
// negative ascent/ descent can be returned.
aDimensions = dimensions;
} else {
aDimensions.Combine(dimensions);
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetTextDimensions(const PRUnichar* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetTextDimensionsInternal(aString, aLength, aDimensions);
if (aFontID) {
*aFontID = nsnull;
}
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsTextDimensions dimensions;
nsresult rv = GetTextDimensionsInternal(aString, len, dimensions);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsTextDimensions, we
// assign directly in the first iteration. This ensures that
// negative ascent/ descent can be returned.
aDimensions = dimensions;
} else {
aDimensions.Combine(dimensions);
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS)
NS_IMETHODIMP
nsThebesRenderingContext::GetTextDimensions(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= PRInt32(maxChunkLength))
return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
if (aFontID) {
*aFontID = 0;
}
// Do a naive implementation based on 3-arg GetTextDimensions
PRInt32 x = 0;
PRInt32 wordCount;
for (wordCount = 0; wordCount < aNumBreaks; ++wordCount) {
PRInt32 lastBreak = wordCount > 0 ? aBreaks[wordCount - 1] : 0;
nsTextDimensions dimensions;
NS_ASSERTION(aBreaks[wordCount] > lastBreak, "Breaks must be monotonically increasing");
NS_ASSERTION(aBreaks[wordCount] <= aLength, "Breaks can't exceed string length");
// Call safe method
nsresult rv =
GetTextDimensions(aString + lastBreak, aBreaks[wordCount] - lastBreak,
dimensions);
if (NS_FAILED(rv))
return rv;
x += dimensions.width;
// The first word always "fits"
if (x > aAvailWidth && wordCount > 0)
break;
// aDimensions ascent/descent should exclude the last word (unless there
// is only one word) so we let it run one word behind
if (wordCount == 0) {
aDimensions = dimensions;
} else {
aDimensions.Combine(aLastWordDimensions);
}
aNumCharsFit = aBreaks[wordCount];
aLastWordDimensions = dimensions;
}
// aDimensions width should include all the text
aDimensions.width = x;
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetTextDimensions(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= PRInt32(maxChunkLength))
return GetTextDimensionsInternal(aString, aLength, aAvailWidth, aBreaks, aNumBreaks,
aDimensions, aNumCharsFit, aLastWordDimensions, aFontID);
if (aFontID) {
*aFontID = 0;
}
// Do a naive implementation based on 3-arg GetTextDimensions
PRInt32 x = 0;
PRInt32 wordCount;
for (wordCount = 0; wordCount < aNumBreaks; ++wordCount) {
PRInt32 lastBreak = wordCount > 0 ? aBreaks[wordCount - 1] : 0;
NS_ASSERTION(aBreaks[wordCount] > lastBreak, "Breaks must be monotonically increasing");
NS_ASSERTION(aBreaks[wordCount] <= aLength, "Breaks can't exceed string length");
nsTextDimensions dimensions;
// Call safe method
nsresult rv =
GetTextDimensions(aString + lastBreak, aBreaks[wordCount] - lastBreak,
dimensions);
if (NS_FAILED(rv))
return rv;
x += dimensions.width;
// The first word always "fits"
if (x > aAvailWidth && wordCount > 0)
break;
// aDimensions ascent/descent should exclude the last word (unless there
// is only one word) so we let it run one word behind
if (wordCount == 0) {
aDimensions = dimensions;
} else {
aDimensions.Combine(aLastWordDimensions);
}
aNumCharsFit = aBreaks[wordCount];
aLastWordDimensions = dimensions;
}
// aDimensions width should include all the text
aDimensions.width = x;
return NS_OK;
}
#endif
#ifdef MOZ_MATHML
NS_IMETHODIMP
nsThebesRenderingContext::GetBoundingMetrics(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetBoundingMetricsInternal(aString, aLength, aBoundingMetrics);
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsBoundingMetrics metrics;
nsresult rv = GetBoundingMetricsInternal(aString, len, metrics);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsBoundingMetrics, we
// assign directly in the first iteration. This ensures that
// negative ascent/ descent can be returned and the left bearing
// is properly initialized.
aBoundingMetrics = metrics;
} else {
aBoundingMetrics += metrics;
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength)
return GetBoundingMetricsInternal(aString, aLength, aBoundingMetrics, aFontID);
if (aFontID) {
*aFontID = 0;
}
PRBool firstIteration = PR_TRUE;
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsBoundingMetrics metrics;
nsresult rv = GetBoundingMetricsInternal(aString, len, metrics);
if (NS_FAILED(rv))
return rv;
if (firstIteration) {
// Instead of combining with a Clear()ed nsBoundingMetrics, we
// assign directly in the first iteration. This ensures that
// negative ascent/ descent can be returned and the left bearing
// is properly initialized.
aBoundingMetrics = metrics;
} else {
aBoundingMetrics += metrics;
}
aLength -= len;
aString += len;
firstIteration = PR_FALSE;
}
return NS_OK;
}
#endif
NS_IMETHODIMP
nsThebesRenderingContext::DrawString(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nsresult rv = DrawStringInternal(aString, len, aX, aY);
if (NS_FAILED(rv))
return rv;
aLength -= len;
if (aLength > 0) {
nscoord width;
rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
aX += width;
aString += len;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsThebesRenderingContext::DrawString(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,
const nscoord* aSpacing)
{
PRUint32 maxChunkLength = GetMaxChunkLength(this);
if (aLength <= maxChunkLength) {
return DrawStringInternal(aString, aLength, aX, aY, aFontID, aSpacing);
}
PRBool isRTL = PR_FALSE;
GetRightToLeftText(&isRTL);
if (isRTL) {
nscoord totalWidth = 0;
if (aSpacing) {
for (PRUint32 i = 0; i < aLength; ++i) {
totalWidth += aSpacing[i];
}
} else {
nsresult rv = GetWidth(aString, aLength, totalWidth);
if (NS_FAILED(rv))
return rv;
}
aX += totalWidth;
}
while (aLength > 0) {
PRInt32 len = FindSafeLength(this, aString, aLength, maxChunkLength);
nscoord width = 0;
if (aSpacing) {
for (PRInt32 i = 0; i < len; ++i) {
width += aSpacing[i];
}
} else {
nsresult rv = GetWidthInternal(aString, len, width);
if (NS_FAILED(rv))
return rv;
}
if (isRTL) {
aX -= width;
}
nsresult rv = DrawStringInternal(aString, len, aX, aY, aFontID, aSpacing);
if (NS_FAILED(rv))
return rv;
aLength -= len;
if (!isRTL) {
aX += width;
}
aString += len;
if (aSpacing) {
aSpacing += len;
}
}
return NS_OK;
}
nsresult
nsThebesRenderingContext::GetWidthInternal(const char* aString, PRUint32 aLength, nscoord& aWidth)
{
#ifdef DISABLE_TEXT
@ -852,7 +1293,7 @@ nsThebesRenderingContext::GetWidthInternal(const char* aString, PRUint32 aLength
return mFontMetrics->GetWidth(aString, aLength, aWidth, this);
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetWidthInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID)
{
@ -869,28 +1310,28 @@ nsThebesRenderingContext::GetWidthInternal(const PRUnichar *aString, PRUint32 aL
return mFontMetrics->GetWidth(aString, aLength, aWidth, aFontID, this);
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions)
{
mFontMetrics->GetMaxAscent(aDimensions.ascent);
mFontMetrics->GetMaxDescent(aDimensions.descent);
return GetWidth(aString, aLength, aDimensions.width);
mFontMetrics->GetMaxAscent(aDimensions.ascent);
mFontMetrics->GetMaxDescent(aDimensions.descent);
return GetWidth(aString, aLength, aDimensions.width);
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions,
PRInt32* aFontID)
{
mFontMetrics->GetMaxAscent(aDimensions.ascent);
mFontMetrics->GetMaxDescent(aDimensions.descent);
return GetWidth(aString, aLength, aDimensions.width, aFontID);
mFontMetrics->GetMaxAscent(aDimensions.ascent);
mFontMetrics->GetMaxDescent(aDimensions.descent);
return GetWidth(aString, aLength, aDimensions.width, aFontID);
}
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) || defined(XP_MACOSX) || defined (MOZ_DFB)
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
@ -904,7 +1345,7 @@ nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
@ -920,7 +1361,7 @@ nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
#endif
#ifdef MOZ_MATHML
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetBoundingMetricsInternal(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics)
@ -928,7 +1369,7 @@ nsThebesRenderingContext::GetBoundingMetricsInternal(const char* aString,
return mFontMetrics->GetBoundingMetrics(aString, aLength, this, aBoundingMetrics);
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::GetBoundingMetricsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
@ -938,7 +1379,7 @@ nsThebesRenderingContext::GetBoundingMetricsInternal(const PRUnichar* aString,
}
#endif // MOZ_MATHML
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::DrawStringInternal(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing)
@ -951,7 +1392,7 @@ nsThebesRenderingContext::DrawStringInternal(const char *aString, PRUint32 aLeng
this);
}
NS_IMETHODIMP
nsresult
nsThebesRenderingContext::DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,

View File

@ -42,7 +42,6 @@
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIRenderingContext.h"
#include "nsRenderingContextImpl.h"
#include "nsIDeviceContext.h"
#include "nsIFontMetrics.h"
#include "nsIWidget.h"
@ -57,7 +56,7 @@
class nsIImage;
class nsThebesRenderingContext : public nsRenderingContextImpl
class nsThebesRenderingContext : public nsIRenderingContext
{
public:
nsThebesRenderingContext();
@ -65,6 +64,74 @@ public:
NS_DECL_ISUPPORTS
/**
* Return the maximum length of a string that can be handled by the platform
* using the current font metrics.
*/
virtual PRInt32 GetMaxStringLength();
// Safe string method variants: by default, these defer to the more
// elaborate methods below
NS_IMETHOD GetWidth(const nsString& aString, nscoord &aWidth,
PRInt32 *aFontID = nsnull);
NS_IMETHOD GetWidth(const char* aString, nscoord& aWidth);
NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull);
// Safe string methods
NS_IMETHOD GetWidth(const char* aString, PRUint32 aLength,
nscoord& aWidth);
NS_IMETHOD GetWidth(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID = nsnull);
NS_IMETHOD GetWidth(char aC, nscoord &aWidth);
NS_IMETHOD GetWidth(PRUnichar aC, nscoord &aWidth,
PRInt32 *aFontID);
NS_IMETHOD GetTextDimensions(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions);
NS_IMETHOD GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
nsTextDimensions& aDimensions, PRInt32* aFontID = nsnull);
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS)
NS_IMETHOD GetTextDimensions(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
#endif
#ifdef MOZ_MATHML
NS_IMETHOD GetBoundingMetrics(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
NS_IMETHOD GetBoundingMetrics(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID = nsnull);
#endif
NS_IMETHOD DrawString(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing = nsnull);
NS_IMETHOD DrawString(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull);
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxASurface* aThebesSurface);
NS_IMETHOD Init(nsIDeviceContext* aContext, gfxContext* aThebesContext);
@ -99,81 +166,6 @@ public:
NS_IMETHOD FillEllipse(const nsRect& aRect);
NS_IMETHOD FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight);
NS_IMETHOD GetWidth(const nsString& aString, nscoord &aWidth,
PRInt32 *aFontID = nsnull)
{ return nsRenderingContextImpl::GetWidth(aString, aWidth, aFontID); }
NS_IMETHOD GetWidth(const char* aString, nscoord& aWidth)
{ return nsRenderingContextImpl::GetWidth(aString, aWidth); }
NS_IMETHOD GetWidth(const char* aString, PRUint32 aLength,
nscoord& aWidth)
{ return nsRenderingContextImpl::GetWidth(aString, aLength, aWidth); }
NS_IMETHOD GetWidth(const PRUnichar *aString, PRUint32 aLength,
nscoord &aWidth, PRInt32 *aFontID = nsnull)
{ return nsRenderingContextImpl::GetWidth(aString, aLength, aWidth, aFontID); }
NS_IMETHOD DrawString(const nsString& aString, nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull)
{ return nsRenderingContextImpl::DrawString(aString, aX, aY, aFontID, aSpacing); }
NS_IMETHOD GetWidth(char aC, nscoord &aWidth);
NS_IMETHOD GetWidth(PRUnichar aC, nscoord &aWidth,
PRInt32 *aFontID);
NS_IMETHOD GetWidthInternal(const char *aString, PRUint32 aLength, nscoord &aWidth);
NS_IMETHOD GetWidthInternal(const PRUnichar *aString, PRUint32 aLength, nscoord &aWidth,
PRInt32 *aFontID);
NS_IMETHOD DrawStringInternal(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing);
NS_IMETHOD DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,
const nscoord* aSpacing);
NS_IMETHOD GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
nsTextDimensions& aDimensions);
NS_IMETHOD GetTextDimensionsInternal(const PRUnichar *aString, PRUint32 aLength,
nsTextDimensions& aDimensions,PRInt32 *aFontID);
NS_IMETHOD GetTextDimensionsInternal(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID);
NS_IMETHOD GetTextDimensionsInternal(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID);
#ifdef MOZ_MATHML
/**
* Returns metrics (in app units) of an 8-bit character string
*/
NS_IMETHOD GetBoundingMetricsInternal(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
/**
* Returns metrics (in app units) of a Unicode character string
*/
NS_IMETHOD GetBoundingMetricsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID = nsnull);
#endif /* MOZ_MATHML */
virtual PRInt32 GetMaxStringLength();
NS_IMETHOD PushFilter(const nsRect& aRect, PRBool aAreaIsOpaque, float aOpacity);
NS_IMETHOD PopFilter();
@ -183,6 +175,10 @@ public:
NS_IMETHOD PopTranslation(PushedTranslation* aState);
NS_IMETHOD SetTranslation(nscoord aX, nscoord aY);
/**
* Let the device context know whether we want text reordered with
* right-to-left base direction
*/
NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
NS_IMETHOD GetRightToLeftText(PRBool* aIsRTL);
virtual void SetTextRunRTL(PRBool aIsRTL);
@ -212,8 +208,64 @@ public:
void TransformCoord (nscoord *aX, nscoord *aY);
protected:
nsresult GetWidthInternal(const char *aString, PRUint32 aLength, nscoord &aWidth);
nsresult GetWidthInternal(const PRUnichar *aString, PRUint32 aLength, nscoord &aWidth,
PRInt32 *aFontID = nsnull);
nsresult DrawStringInternal(const char *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
const nscoord* aSpacing = nsnull);
nsresult DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID = -1,
const nscoord* aSpacing = nsnull);
nsresult GetTextDimensionsInternal(const char* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions);
nsresult GetTextDimensionsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsTextDimensions& aDimensions,
PRInt32* aFontID = nsnull);
nsresult GetTextDimensionsInternal(const char* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
nsresult GetTextDimensionsInternal(const PRUnichar* aString,
PRInt32 aLength,
PRInt32 aAvailWidth,
PRInt32* aBreaks,
PRInt32 aNumBreaks,
nsTextDimensions& aDimensions,
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
PRInt32* aFontID = nsnull);
#ifdef MOZ_MATHML
/**
* Returns metrics (in app units) of an 8-bit character string
*/
nsresult GetBoundingMetricsInternal(const char* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics);
/**
* Returns metrics (in app units) of a Unicode character string
*/
nsresult GetBoundingMetricsInternal(const PRUnichar* aString,
PRUint32 aLength,
nsBoundingMetrics& aBoundingMetrics,
PRInt32* aFontID = nsnull);
#endif /* MOZ_MATHML */
nsCOMPtr<nsIDeviceContext> mDeviceContext;
// cached pixels2twips, twips2pixels values
// cached app units per device pixel value
double mP2A;
nsCOMPtr<nsIWidget> mWidget;

View File

@ -649,23 +649,26 @@ $(addsuffix .$(OBJ_SUFFIX),jsdtracef jsinterp jsobj): $(CURDIR)/javascript-trace
endif
ifdef GNU_CC
ifndef CROSS_COMPILE
# If we don't have run-mozilla.sh *and* we're linking against NSPR, we don't
# know how to run the JS binary. Oh well
imacro_asm.js: imacro_asm.js.in jsopcode.tbl
$(CC) -c -x c -E -P -I$(srcdir) $< > $@
GARBAGE += imacros.c.out imacro_asm.js
GARBAGE += imacros.c.tmp imacro_asm.js
ifndef CROSS_COMPILE
# Obsolete comment: if you replace update-imacros with libs, this would apply
# but then parallel gmake would sometimes try to run $(DIST)/bin/js before it
# had been built and installed. Want a fix for this, de-automating for now.
ifneq (,$(wildcard $(RUN_TEST_PROGRAM))$(if $(NSPR_LIBS),,1))
libs:: imacro_asm.js $(srcdir)/imacros.jsasm
$(wildcard $(RUN_TEST_PROGRAM)) $(DIST)/bin/js$(BIN_SUFFIX) $< $(srcdir)/imacros.jsasm > imacros.c.tmp
@cmp -s imacros.c.tmp $(srcdir)/imacros.c.out || \
(echo "imacros.c.out is out of date. Run 'make update-imacros' to copy it to your source tree."; diff -U 4 $(srcdir)/imacros.c.out imacros.c.out; exit 1)
@echo "imacros.c.out is up to date"
# Build imacros.c.out after descending into DIRS and building the js shell.
# This may result in an updated imacros.c.out file that requires a re-build
# to stabilize.
update-imacros:: imacros.c.out
@cmp -s imacros.c.out $(srcdir)/$< || cp imacros.c.out $(srcdir)
update-imacros: imacros.c.tmp
cp $< $(srcdir)/imacros.c.out
%.c.out: %.jsasm imacro_asm.js
$(DIST)/bin/js imacro_asm.js $< > $@
.PHONY: update-imacros
endif
endif
endif

View File

@ -2505,6 +2505,17 @@ nsLayoutUtils::GetStringWidth(const nsIFrame* aFrame,
/* static */ PRBool
nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
{
LinePosition position;
if (!GetFirstLinePosition(aFrame, &position))
return PR_FALSE;
*aResult = position.mBaseline;
return PR_TRUE;
}
/* static */ PRBool
nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
LinePosition* aResult)
{
const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
if (!block) {
@ -2512,7 +2523,11 @@ nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
// so, use the baseline of its first row.
nsIAtom* fType = aFrame->GetType();
if (fType == nsGkAtoms::tableOuterFrame) {
*aResult = aFrame->GetBaseline();
aResult->mTop = 0;
aResult->mBaseline = aFrame->GetBaseline();
// This is what we want for the list bullet caller; not sure if
// other future callers will want the same.
aResult->mBottom = aFrame->GetSize().height;
return PR_TRUE;
}
@ -2522,12 +2537,12 @@ nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
if (!sFrame) {
NS_NOTREACHED("not scroll frame");
}
nscoord kidBaseline;
if (GetFirstLineBaseline(sFrame->GetScrolledFrame(), &kidBaseline)) {
LinePosition kidPosition;
if (GetFirstLinePosition(sFrame->GetScrolledFrame(), &kidPosition)) {
// Consider only the border and padding that contributes to the
// kid's position, not the scrolling, so we get the initial
// position.
*aResult = kidBaseline + aFrame->GetUsedBorderAndPadding().top;
*aResult = kidPosition + aFrame->GetUsedBorderAndPadding().top;
return PR_TRUE;
}
return PR_FALSE;
@ -2542,16 +2557,19 @@ nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
line != line_end; ++line) {
if (line->IsBlock()) {
nsIFrame *kid = line->mFirstChild;
nscoord kidBaseline;
if (GetFirstLineBaseline(kid, &kidBaseline)) {
*aResult = kidBaseline + kid->GetPosition().y;
LinePosition kidPosition;
if (GetFirstLinePosition(kid, &kidPosition)) {
*aResult = kidPosition + kid->GetPosition().y;
return PR_TRUE;
}
} else {
// XXX Is this the right test? We have some bogus empty lines
// floating around, but IsEmpty is perhaps too weak.
if (line->GetHeight() != 0 || !line->IsEmpty()) {
*aResult = line->mBounds.y + line->GetAscent();
nscoord top = line->mBounds.y;
aResult->mTop = top;
aResult->mBaseline = top + line->GetAscent();
aResult->mBottom = top + line->GetHeight();
return PR_TRUE;
}
}

View File

@ -775,6 +775,28 @@ public:
*/
static PRBool GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult);
/**
* Just like GetFirstLineBaseline, except also returns the top and
* bottom of the line with the baseline.
*
* Returns true if a line was found (and fills in aResult).
* Otherwise returns false.
*/
struct LinePosition {
nscoord mTop, mBaseline, mBottom;
LinePosition operator+(nscoord aOffset) const {
LinePosition result;
result.mTop = mTop + aOffset;
result.mBaseline = mBaseline + aOffset;
result.mBottom = mBottom + aOffset;
return result;
}
};
static PRBool GetFirstLinePosition(const nsIFrame* aFrame,
LinePosition* aResult);
/**
* Derive a baseline of |aFrame| (measured from its top border edge)
* from its last in-flow line box (not descending into anything with

View File

@ -5103,8 +5103,6 @@ PresShell::RenderDocument(const nsRect& aRect, PRUint32 aFlags,
nsIFrame* rootFrame = FrameManager()->GetRootFrame();
if (rootFrame) {
nsAutoDisableGetUsedXAssertions disableAssert;
nsDisplayListBuilder builder(rootFrame, PR_FALSE,
(aFlags & RENDER_CARET) != 0);
nsDisplayList list;

View File

@ -43,7 +43,6 @@
#include "nsDataDocumentContentPolicy.h"
#include "nsNoDataProtocolContentPolicy.h"
#include "nsDOMCID.h"
#include "nsCSSOMFactory.h"
#include "nsInspectorCSSUtils.h"
#include "nsHTMLContentSerializer.h"
#include "nsHTMLParts.h"
@ -522,7 +521,6 @@ MAKE_CTOR(CreateXTFService, nsIXTFService, NS_NewXTF
MAKE_CTOR(CreateXMLContentBuilder, nsIXMLContentBuilder, NS_NewXMLContentBuilder)
#endif
MAKE_CTOR(CreateContentDLF, nsIDocumentLoaderFactory, NS_NewContentDocumentLoaderFactory)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCSSOMFactory)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsInspectorCSSUtils)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsContentAreaDragDrop)
@ -995,11 +993,6 @@ static const nsModuleComponentInfo gComponents[] = {
"@mozilla.org/content/subtree-content-iterator;1",
CreateSubtreeIterator },
{ "CSS Object Model Factory",
NS_CSSOMFACTORY_CID,
nsnull,
nsCSSOMFactoryConstructor },
{ "Inspector CSS Utils",
NS_INSPECTORCSSUTILS_CID,
nsnull,

View File

@ -59,7 +59,6 @@
#include "nsEventListenerManager.h"
#include "nsFrame.h"
#include "nsGenericElement.h" // for nsDOMEventRTTearoff
#include "nsStyledElement.h"
#include "nsGlobalWindow.h"
#include "nsGkAtoms.h"
#include "nsImageFrame.h"
@ -321,7 +320,6 @@ nsLayoutStatics::Shutdown()
nsCSSScanner::ReleaseGlobals();
NS_IF_RELEASE(nsRuleNode::gLangService);
nsStyledElement::Shutdown();
nsTextFragment::Shutdown();

View File

@ -1075,14 +1075,14 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
mLines.begin().next()->IsBlock()))) {
// Reflow the bullet
nsHTMLReflowMetrics metrics;
// FIXME: aReflowState.mComputedBorderPadding.top isn't even the
// right place -- we really want the top of the line whose baseline
// we're using (or, actually, the entire line, once we fix bug
// 25888)
ReflowBullet(state, metrics, aReflowState.mComputedBorderPadding.top);
// XXX Use the entire line when we fix bug 25888.
nsLayoutUtils::LinePosition position;
PRBool havePosition = nsLayoutUtils::GetFirstLinePosition(this, &position);
nscoord lineTop = havePosition ? position.mTop
: aReflowState.mComputedBorderPadding.top;
ReflowBullet(state, metrics, lineTop);
nscoord baseline;
if (nsLayoutUtils::GetFirstLineBaseline(this, &baseline)) {
if (havePosition) {
// We have some lines to align the bullet with.
// Doing the alignment using the baseline will also cater for
@ -1090,7 +1090,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// Tall bullets won't look particularly nice here...
nsRect bbox = mBullet->GetRect();
bbox.y = baseline - metrics.ascent;
bbox.y = position.mBaseline - metrics.ascent;
mBullet->SetRect(bbox);
}
// Otherwise just leave the bullet where it is, up against our top padding.
@ -1657,19 +1657,19 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
} else {
// Note that this check will become incorrect once bug 25888 is fixed
// because we are only checking the top of the line
aState.GetAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
PRBool wasImpactedByFloat = aLine->IsImpactedByFloat();
PRBool isImpactedByFloat = aState.IsImpactedByFloat();
nsFlowAreaRect floatAvailableSpace =
aState.GetFloatAvailableSpace(aLine->mBounds.y + aDeltaY, PR_FALSE);
#ifdef REALLY_NOISY_REFLOW
printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n",
this, wasImpactedByFloat, isImpactedByFloat);
this, wasImpactedByFloat, floatAvailableSpace.mHasFloats);
#endif
// Mark the line dirty if it was or is affected by a float
// We actually only really need to reflow if the amount of impact
// changes, but that's not straightforward to check
if (wasImpactedByFloat || isImpactedByFloat) {
if (wasImpactedByFloat || floatAvailableSpace.mHasFloats) {
aLine->MarkDirty();
}
}
@ -2951,15 +2951,15 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// Here aState.mY is the top border-edge of the block.
// Compute the available space for the block
aState.GetAvailableSpace();
nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
#ifdef REALLY_NOISY_REFLOW
printf("setting line %p isImpacted to %s\n", aLine.get(), aState.IsImpactedByFloat()?"true":"false");
printf("setting line %p isImpacted to %s\n",
aLine.get(), floatAvailableSpace.mHasFloats?"true":"false");
#endif
PRBool isImpacted = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE;
aLine->SetLineIsImpactedByFloat(isImpacted);
aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
nsRect availSpace;
aState.ComputeBlockAvailSpace(frame, display, replacedBlock != nsnull,
availSpace);
aState.ComputeBlockAvailSpace(frame, display, floatAvailableSpace,
replacedBlock != nsnull, availSpace);
// Now put the Y coordinate back to the top of the top-margin +
// clearance, and flow the block.
@ -3039,7 +3039,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// then pushing it to the next page would give it more room. Note that
// isImpacted doesn't include impact from the block's own floats.
PRBool forceFit = aState.IsAdjacentWithTop() && clearance <= 0 &&
!isImpacted;
!floatAvailableSpace.mHasFloats;
nsCollapsingMargin collapsedBottomMargin;
nsRect combinedArea(0,0,0,0);
*aKeepReflowGoing = brc.PlaceBlock(blockHtmlRS, forceFit, aLine.get(),
@ -3347,24 +3347,23 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
if (ShouldApplyTopMargin(aState, aLine)) {
aState.mY += aState.mPrevBottomMargin.get();
}
aState.GetAvailableSpace();
PRBool impactedByFloats = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE;
aLine->SetLineIsImpactedByFloat(impactedByFloats);
nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
#ifdef REALLY_NOISY_REFLOW
printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
this, impactedByFloats);
this, floatAvailableSpace.mHasFloats);
#endif
const nsMargin& borderPadding = aState.BorderPadding();
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
nscoord availWidth = aState.mAvailSpaceRect.width;
nscoord x = floatAvailableSpace.mRect.x + borderPadding.left;
nscoord availWidth = floatAvailableSpace.mRect.width;
nscoord availHeight;
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
availHeight = NS_UNCONSTRAINEDSIZE;
}
else {
/* XXX get the height right! */
availHeight = aState.mAvailSpaceRect.height;
availHeight = floatAvailableSpace.mRect.height;
}
// Make sure to enable resize optimization before we call BeginLineReflow
@ -3373,7 +3372,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
aLineLayout.BeginLineReflow(x, aState.mY,
availWidth, availHeight,
impactedByFloats,
floatAvailableSpace.mHasFloats,
PR_FALSE /*XXX isTopOfPage*/);
aState.SetFlag(BRS_LINE_LAYOUT_EMPTY, PR_FALSE);
@ -3396,7 +3395,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// continuations
PRBool isContinuingPlaceholders = PR_FALSE;
if (impactedByFloats) {
if (floatAvailableSpace.mHasFloats) {
// There is a soft break opportunity at the start of the line, because
// we can always move this line down below float(s).
if (aLineLayout.NotifyOptionalBreakPosition(frame->GetContent(), 0, PR_TRUE, eNormalBreak)) {
@ -3501,14 +3500,14 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
//
// What we do is to advance past the first float we find and
// then reflow the line all over again.
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != floatAvailableSpace.mRect.height,
"unconstrained height on totally empty line");
// See the analogous code for blocks in nsBlockReflowState::ClearFloats.
if (aState.mAvailSpaceRect.height > 0) {
NS_ASSERTION(aState.IsImpactedByFloat(),
if (floatAvailableSpace.mRect.height > 0) {
NS_ASSERTION(floatAvailableSpace.mHasFloats,
"redo line on totally empty line with non-empty band...");
aState.mY += aState.mAvailSpaceRect.height;
aState.mY += floatAvailableSpace.mRect.height;
} else {
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight,
"We shouldn't be running out of height here");
@ -5646,8 +5645,9 @@ nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
// Float support
nsRect
nsBlockFrame::ComputeFloatAvailableSpace(nsBlockReflowState& aState,
nsIFrame* aFloatFrame)
nsBlockFrame::AdjustFloatAvailableSpace(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFloatFrame)
{
// Compute the available width. By default, assume the width of the
// containing block.
@ -5663,7 +5663,7 @@ nsBlockFrame::ComputeFloatAvailableSpace(nsBlockReflowState& aState,
// give tables only the available space
// if they can shrink we may not be constrained to place
// them in the next line
availWidth = aState.mAvailSpaceRect.width;
availWidth = aFloatAvailableSpace.width;
// round down to twips per pixel so that we fit
// needed when prev. float has procentage width
// (maybe is a table flaw that makes table chose to round up
@ -5696,12 +5696,14 @@ nsBlockFrame::ComputeFloatAvailableSpace(nsBlockReflowState& aState,
nscoord
nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsPlaceholderFrame* aPlaceholder)
{
// Reflow the float.
nsIFrame* floatFrame = aPlaceholder->GetOutOfFlowFrame();
nsRect availSpace = ComputeFloatAvailableSpace(aState, floatFrame);
nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
floatFrame);
nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState,
floatFrame,
@ -5712,6 +5714,7 @@ nsBlockFrame::ComputeFloatWidth(nsBlockReflowState& aState,
nsresult
nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsPlaceholderFrame* aPlaceholder,
nsMargin& aFloatMargin,
nsReflowStatus& aReflowStatus)
@ -5723,12 +5726,13 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
#ifdef NOISY_FLOAT
printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
aPlaceholder->GetOutOfFlowFrame(), this,
aState.mAvailSpaceRect.x, aState.mAvailSpaceRect.y,
aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
aFloatAvailableSpace.x, aFloatAvailableSpace.y,
aFloatAvailableSpace.width, aFloatAvailableSpace.height
);
#endif
nsRect availSpace = ComputeFloatAvailableSpace(aState, floatFrame);
nsRect availSpace = AdjustFloatAvailableSpace(aState, aFloatAvailableSpace,
floatFrame);
nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState,
floatFrame,
@ -6650,22 +6654,43 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
mBullet->WillReflow(aState.mPresContext);
mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status);
// Place the bullet now, separate it from mOutsideBulletX by its margin.
// If the mAvailSpaceRect position is outside the mOutsideBulletX
// position it means the line didn't care about the float edge and we
// use that position instead (there cannot be any floats at the start
// of the line this case since that would violate CSS 2.1 float rules).
// XXX we need to take floats inside the principal block that clears
// outside floats into account also (bug 428810).
nscoord x = rs.mStyleVisibility->mDirection == NS_STYLE_DIRECTION_LTR ?
PR_MIN(aState.mOutsideBulletX, aState.mAvailSpaceRect.x)
- reflowState.mComputedMargin.right - aMetrics.width :
PR_MAX(aState.mOutsideBulletX, aState.mAvailSpaceRect.XMost())
+ reflowState.mComputedMargin.left;
// Get the float available space using our saved state from before we
// started reflowing the block, so that we ignore any floats inside
// the block.
// FIXME: aLineTop isn't actually set correctly by some callers, since
// they reposition the line.
nsRect floatAvailSpace =
aState.GetFloatAvailableSpaceWithState(aLineTop, PR_FALSE,
&aState.mFloatManagerStateBefore)
.mRect;
// FIXME (bug 25888): need to check the entire region that the first
// line overlaps, not just the top pixel.
// FIXME: come up with rules for when mAvailSpaceRect is valid so we
// don't need to do this.
aState.GetAvailableSpace();
// Place the bullet now. We want to place the bullet relative to the
// border-box of the associated block (using the right/left margin of
// the bullet frame as separation). However, if a line box would be
// displaced by floats that are *outside* the associated block, we
// want to displace it by the same amount. That is, we act as though
// the edge of the floats is the content-edge of the block, and place
// the bullet at a position offset from there by the block's padding,
// the block's border, and the bullet frame's margin.
nscoord x;
if (rs.mStyleVisibility->mDirection == NS_STYLE_DIRECTION_LTR) {
// Note: floatAvailSpace.x is relative to the content box and never
// less than zero. Converting to frame coordinates and subtracting
// the padding and border cancel each other out, and the PR_MAX()
// with 0 (or with the left border+padding) is even implied in the
// right place.
x = floatAvailSpace.x - reflowState.mComputedMargin.right - aMetrics.width;
} else {
// The XMost() of the available space and the computed width both
// give us offsets from the left content edge. Then we add the left
// border/padding to get into frame coordinates, and the right
// border/padding and the bullet's margin to offset the position.
x = PR_MIN(rs.ComputedWidth(), floatAvailSpace.XMost())
+ rs.mComputedBorderPadding.LeftRight()
+ reflowState.mComputedMargin.left;
}
// Approximate the bullets position; vertical alignment will provide
// the final vertical location.
@ -6824,6 +6849,7 @@ nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame)
/* static */
nsBlockFrame::ReplacedElementWidthToClear
nsBlockFrame::WidthToClearPastFloats(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFrame)
{
nscoord leftOffset, rightOffset;
@ -6877,7 +6903,8 @@ nsBlockFrame::WidthToClearPastFloats(nsBlockReflowState& aState,
}
}
aState.ComputeReplacedBlockOffsetsForFloats(aFrame, leftOffset, rightOffset,
aState.ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
leftOffset, rightOffset,
&result);
// result.marginLeft has already been subtracted from leftOffset (etc.)
@ -6901,7 +6928,8 @@ nsBlockFrame::WidthToClearPastFloats(nsBlockReflowState& aState,
offsetState.mComputedBorderPadding.LeftRight() -
(result.marginLeft + result.marginRight);
} else {
aState.ComputeReplacedBlockOffsetsForFloats(aFrame, leftOffset, rightOffset);
aState.ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
leftOffset, rightOffset);
nscoord availWidth = aState.mContentArea.width - leftOffset - rightOffset;
// We actually don't want the min width here; see bug 427782; we only

View File

@ -304,7 +304,9 @@ public:
{ return marginLeft + borderBoxWidth + marginRight; }
};
static ReplacedElementWidthToClear
WidthToClearPastFloats(nsBlockReflowState& aState, nsIFrame* aFrame);
WidthToClearPastFloats(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFrame);
/**
* Walks up the frame tree, starting with aCandidate, and returns the first
@ -529,14 +531,17 @@ protected:
LineReflowStatus* aLineReflowStatus);
// Compute the available width for a float.
nsRect ComputeFloatAvailableSpace(nsBlockReflowState& aState,
nsIFrame* aFloatFrame);
nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsIFrame* aFloatFrame);
// Computes the border-box width of the float
nscoord ComputeFloatWidth(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsPlaceholderFrame* aPlaceholder);
// An incomplete aReflowStatus indicates the float should be split
// but only if the available height is constrained.
nsresult ReflowFloat(nsBlockReflowState& aState,
const nsRect& aFloatAvailableSpace,
nsPlaceholderFrame* aPlaceholder,
nsMargin& aFloatMargin,
nsReflowStatus& aReflowStatus);

View File

@ -102,6 +102,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
// coordinate system origin for later.
mFloatManager->Translate(borderPadding.left, borderPadding.top);
mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY);
mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
}
mReflowStatus = NS_FRAME_COMPLETE;
@ -139,16 +140,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mCurrentLine = aFrame->end_lines();
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(aReflowState.frame);
// Calculate mOutsideBulletX
GetAvailableSpace();
// FIXME (bug 25888): need to check the entire region that the first
// line overlaps, not just the top pixel.
mOutsideBulletX =
mReflowState.mStyleVisibility->mDirection == NS_STYLE_DIRECTION_LTR ?
mAvailSpaceRect.x :
PR_MIN(mReflowState.ComputedWidth(), mAvailSpaceRect.XMost()) +
mReflowState.mComputedBorderPadding.LeftRight();
}
void
@ -198,6 +189,7 @@ nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
void
nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
const nsRect& aFloatAvailableSpace,
nscoord& aLeftResult,
nscoord& aRightResult,
nsBlockFrame::
@ -208,13 +200,13 @@ nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
// only give it free space. An example is a table frame - the
// tables do not flow around floats.
// However, we can let its margins intersect floats.
NS_ASSERTION(mAvailSpaceRect.x >= 0, "bad avail space rect x");
NS_ASSERTION(mAvailSpaceRect.width == 0 ||
mAvailSpaceRect.XMost() <= mContentArea.width,
NS_ASSERTION(aFloatAvailableSpace.x >= 0, "bad avail space rect x");
NS_ASSERTION(aFloatAvailableSpace.width == 0 ||
aFloatAvailableSpace.XMost() <= mContentArea.width,
"bad avail space rect width");
nscoord leftOffset, rightOffset;
if (mAvailSpaceRect.width == mContentArea.width) {
if (aFloatAvailableSpace.width == mContentArea.width) {
// We don't need to compute margins when there are no floats around.
leftOffset = 0;
rightOffset = 0;
@ -231,12 +223,13 @@ nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
aReplacedWidth->marginRight == os.mComputedMargin.right),
"unexpected aReplacedWidth");
nscoord leftFloatXOffset = mAvailSpaceRect.x;
nscoord leftFloatXOffset = aFloatAvailableSpace.x;
leftOffset = PR_MAX(leftFloatXOffset, os.mComputedMargin.left) -
(aReplacedWidth ? aReplacedWidth->marginLeft
: os.mComputedMargin.left);
leftOffset = PR_MAX(leftOffset, 0); // in case of negative margin
nscoord rightFloatXOffset = mContentArea.width - mAvailSpaceRect.XMost();
nscoord rightFloatXOffset =
mContentArea.width - aFloatAvailableSpace.XMost();
rightOffset = PR_MAX(rightFloatXOffset, os.mComputedMargin.right) -
(aReplacedWidth ? aReplacedWidth->marginRight
: os.mComputedMargin.right);
@ -252,11 +245,13 @@ nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
void
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
const nsStyleDisplay* aDisplay,
const nsFlowAreaRect& aFloatAvailableSpace,
PRBool aBlockAvoidsFloats,
nsRect& aResult)
{
#ifdef REALLY_NOISY_REFLOW
printf("CBAS frame=%p has floats %d\n", aFrame, mBandHasFloats);
printf("CBAS frame=%p has floats %d\n",
aFrame, aFloatAvailableSpace.mHasFloats);
#endif
aResult.y = mY;
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
@ -284,7 +279,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
!aBlockAvoidsFloats,
"unexpected replaced width");
if (!aBlockAvoidsFloats) {
if (mBandHasFloats) {
if (aFloatAvailableSpace.mHasFloats) {
// Use the float-edge property to determine how the child block
// will interact with the float.
const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
@ -300,8 +295,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
{
// The child block's margins should be placed adjacent to,
// but not overlap the float.
aResult.x = mAvailSpaceRect.x + borderPadding.left;
aResult.width = mAvailSpaceRect.width;
aResult.x = aFloatAvailableSpace.mRect.x + borderPadding.left;
aResult.width = aFloatAvailableSpace.mRect.width;
}
break;
}
@ -319,11 +314,14 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
nsBlockFrame::ReplacedElementWidthToClear *replacedWidth = nsnull;
if (aFrame->GetType() == nsGkAtoms::tableOuterFrame) {
replacedWidth = &replacedWidthStruct;
replacedWidthStruct = nsBlockFrame::WidthToClearPastFloats(*this, aFrame);
replacedWidthStruct =
nsBlockFrame::WidthToClearPastFloats(*this, aFloatAvailableSpace.mRect,
aFrame);
}
nscoord leftOffset, rightOffset;
ComputeReplacedBlockOffsetsForFloats(aFrame, leftOffset, rightOffset,
ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
leftOffset, rightOffset,
replacedWidth);
aResult.x = borderPadding.left + leftOffset;
aResult.width = mContentArea.width - leftOffset - rightOffset;
@ -334,8 +332,10 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
#endif
}
void
nsBlockReflowState::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint)
nsFlowAreaRect
nsBlockReflowState::GetFloatAvailableSpaceWithState(
nscoord aY, PRBool aRelaxHeightConstraint,
nsFloatManager::SavedState *aState) const
{
#ifdef DEBUG
// Verify that the caller setup the coordinate system properly
@ -345,27 +345,24 @@ nsBlockReflowState::GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint)
"bad coord system");
#endif
PRBool hasFloats;
mAvailSpaceRect =
nsFlowAreaRect result =
mFloatManager->GetBand(aY - BorderPadding().top,
aRelaxHeightConstraint ? nscoord_MAX
: mContentArea.height,
mContentArea.width,
&hasFloats);
mBandHasFloats = hasFloats;
mContentArea.width, aState);
// Keep the width >= 0 for compatibility with nsSpaceManager.
if (mAvailSpaceRect.width < 0)
mAvailSpaceRect.width = 0;
if (result.mRect.width < 0)
result.mRect.width = 0;
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
mAvailSpaceRect.x, mAvailSpaceRect.y,
mAvailSpaceRect.width, mAvailSpaceRect.height,
mBandHasFloats);
result.mRect.x, result.mRect.y, result.mRect.width,
result.mRect.height, result.mHasFloats);
}
#endif
return result;
}
/*
@ -524,17 +521,6 @@ nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
}
}
PRBool
nsBlockReflowState::IsImpactedByFloat() const
{
#ifdef REALLY_NOISY_REFLOW
printf("nsBlockReflowState::IsImpactedByFloat %p returned %d\n",
this, mBandHasFloats);
#endif
return mBandHasFloats;
}
PRBool
nsBlockReflowState::InitFloat(nsLineLayout& aLineLayout,
nsPlaceholderFrame* aPlaceholder,
@ -575,6 +561,17 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
nsFloatCache* fc = mFloatCacheFreeList.Alloc();
fc->mPlaceholder = aPlaceholder;
// Because we are in the middle of reflowing a placeholder frame
// within a line (and possibly nested in an inline frame or two
// that's a child of our block) we need to restore the space
// manager's translation to the space that the block resides in
// before placing the float.
nscoord ox, oy;
mFloatManager->GetTranslation(ox, oy);
nscoord dx = ox - mFloatManagerX;
nscoord dy = oy - mFloatManagerY;
mFloatManager->Translate(-dx, -dy);
PRBool placed;
// Now place the float immediately if possible. Otherwise stash it
@ -582,20 +579,11 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
// If one or more floats has already been pushed to the next line,
// don't let this one go on the current line, since that would violate
// float ordering.
nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
if (mBelowCurrentLineFloats.IsEmpty() &&
(aLineLayout.LineIsEmpty() ||
mBlock->ComputeFloatWidth(*this, aPlaceholder) <= aAvailableWidth)) {
// Because we are in the middle of reflowing a placeholder frame
// within a line (and possibly nested in an inline frame or two
// that's a child of our block) we need to restore the space
// manager's translation to the space that the block resides in
// before placing the float.
nscoord ox, oy;
mFloatManager->GetTranslation(ox, oy);
nscoord dx = ox - mFloatManagerX;
nscoord dy = oy - mFloatManagerY;
mFloatManager->Translate(-dx, -dy);
mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aPlaceholder) <=
aAvailableWidth)) {
// And then place it
PRBool isLeftFloat;
// force it to fit if we're at the top of the block and we can't
@ -606,9 +594,11 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
"If we asked for force-fit, it should have been placed");
if (forceFit || (placed && !NS_FRAME_IS_TRUNCATED(aReflowStatus))) {
// Pass on updated available space to the current inline reflow engine
GetAvailableSpace(mY, forceFit);
nsRect availSpace(nsPoint(mAvailSpaceRect.x + BorderPadding().left, mY),
mAvailSpaceRect.Size());
nsFlowAreaRect floatAvailSpace =
GetFloatAvailableSpace(mY, forceFit);
nsRect availSpace(nsPoint(floatAvailSpace.mRect.x + BorderPadding().left,
mY),
floatAvailSpace.mRect.Size());
aLineLayout.UpdateBand(availSpace, isLeftFloat,
aPlaceholder->GetOutOfFlowFrame());
@ -632,9 +622,6 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
}
delete fc;
}
// Restore coordinate system
mFloatManager->Translate(dx, dy);
}
else {
// Always claim to be placed; we don't know whether we fit yet, so we
@ -656,19 +643,24 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
}
}
}
// Restore coordinate system
mFloatManager->Translate(dx, dy);
return placed;
}
PRBool
nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
PRUint8 aFloats, PRBool aForceFit)
nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
const nsFlowAreaRect& aFloatAvailableSpace,
PRBool aForceFit)
{
// If the current Y coordinate is not impacted by any floats
// then by definition the float fits.
PRBool result = PR_TRUE;
if (mBandHasFloats) {
if (aFloatAvailableSpace.mHasFloats) {
// XXX We should allow overflow by up to half a pixel here (bug 21193).
if (mAvailSpaceRect.width < aFloatSize.width) {
if (aFloatAvailableSpace.mRect.width < aFloatSize.width) {
// The available width is too narrow (and its been impacted by a
// prior float)
result = PR_FALSE;
@ -681,7 +673,8 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
// At this point we know that there is enough horizontal space for
// the float (somewhere). Lets see if there is enough vertical
// space.
if (NSCoordGreaterThan(aFloatSize.height, mAvailSpaceRect.height)) {
if (NSCoordGreaterThan(aFloatSize.height,
aFloatAvailableSpace.mRect.height)) {
// The available height is too short. However, its possible that
// there is enough open space below which is not impacted by a
// float.
@ -692,16 +685,16 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
// here.
nscoord xa;
if (NS_STYLE_FLOAT_LEFT == aFloats) {
xa = mAvailSpaceRect.x;
xa = aFloatAvailableSpace.mRect.x;
}
else {
xa = mAvailSpaceRect.XMost() - aFloatSize.width;
xa = aFloatAvailableSpace.mRect.XMost() - aFloatSize.width;
// In case the float is too big, don't go past the left edge
// XXXldb This seems wrong, but we might want to fix bug 6976
// first.
if (xa < mAvailSpaceRect.x) {
xa = mAvailSpaceRect.x;
if (xa < aFloatAvailableSpace.mRect.x) {
xa = aFloatAvailableSpace.mRect.x;
}
}
nscoord xb = xa + aFloatSize.width;
@ -721,19 +714,21 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
nscoord yb = ya + aFloatSize.height;
nscoord saveY = mY;
nsFlowAreaRect floatAvailableSpace(aFloatAvailableSpace);
for (;;) {
// Get the available space at the new Y coordinate
if (mAvailSpaceRect.height <= 0) {
if (floatAvailableSpace.mRect.height <= 0) {
// there is no more available space. We lose.
result = PR_FALSE;
break;
}
mY += mAvailSpaceRect.height;
GetAvailableSpace(mY, aForceFit);
mY += floatAvailableSpace.mRect.height;
floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
if (mBandHasFloats) {
if ((xa < mAvailSpaceRect.x) || (xb > mAvailSpaceRect.XMost())) {
if (floatAvailableSpace.mHasFloats) {
if (xa < floatAvailableSpace.mRect.x ||
xb > floatAvailableSpace.mRect.XMost()) {
// The float can't go here.
result = PR_FALSE;
break;
@ -741,17 +736,15 @@ nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize,
}
// See if there is now enough height for the float.
if (yb <= mY + mAvailSpaceRect.height) {
if (yb <= mY + floatAvailableSpace.mRect.height) {
// Winner. The bottom Y coordinate of the float is in
// this band.
break;
}
}
// Restore Y coordinate and available space information
// regardless of the outcome.
// Restore Y coordinate
mY = saveY;
GetAvailableSpace(mY, aForceFit);
}
return result;
@ -792,14 +785,15 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
mY = ClearFloats(mY, floatDisplay->mBreakType);
}
// Get the band of available space
GetAvailableSpace(mY, aForceFit);
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
NS_ASSERTION(floatFrame->GetParent() == mBlock,
"Float frame has wrong parent");
// Reflow the float
nsMargin floatMargin;
mBlock->ReflowFloat(*this, placeholder, floatMargin, aReflowStatus);
mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
floatMargin, aReflowStatus);
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
@ -825,8 +819,9 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
// Can the float fit here?
PRBool keepFloatOnSameLine = PR_FALSE;
while (!CanPlaceFloat(floatSize, floatDisplay->mFloats, aForceFit)) {
if (mAvailSpaceRect.height <= 0) {
while (!CanPlaceFloat(floatSize, floatDisplay->mFloats, floatAvailableSpace,
aForceFit)) {
if (floatAvailableSpace.mRect.height <= 0) {
// No space, nowhere to put anything.
mY = saveY;
return PR_FALSE;
@ -836,8 +831,8 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
mY += mAvailSpaceRect.height;
GetAvailableSpace(mY, aForceFit);
mY += floatAvailableSpace.mRect.height;
floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
} else {
// This quirk matches the one in nsBlockFrame::ReflowFloat
// IE handles float tables in a very special way
@ -875,13 +870,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
}
// the table does not fit anymore in this line so advance to next band
mY += mAvailSpaceRect.height;
GetAvailableSpace(mY, aForceFit);
mY += floatAvailableSpace.mRect.height;
floatAvailableSpace = GetFloatAvailableSpace(mY, aForceFit);
// reflow the float again now since we have more space
// XXXldb We really don't need to Reflow in a loop, we just need
// to ComputeSize in a loop (once ComputeSize depends on
// availableWidth, which should make this work again).
mBlock->ReflowFloat(*this, placeholder, floatMargin, aReflowStatus);
mBlock->ReflowFloat(*this, floatAvailableSpace.mRect, placeholder,
floatMargin, aReflowStatus);
// Get the floats bounding box and margin information
floatSize = floatFrame->GetSize() +
nsSize(floatMargin.LeftRight(), floatMargin.TopBottom());
@ -900,18 +896,18 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache,
nscoord floatX, floatY;
if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
isLeftFloat = PR_TRUE;
floatX = mAvailSpaceRect.x;
floatX = floatAvailableSpace.mRect.x;
}
else {
isLeftFloat = PR_FALSE;
if (!keepFloatOnSameLine) {
floatX = mAvailSpaceRect.XMost() - floatSize.width;
floatX = floatAvailableSpace.mRect.XMost() - floatSize.width;
}
else {
// this is the IE quirk (see few lines above)
// the table is kept in the same line: don't let it overlap the
// previous float
floatX = mAvailSpaceRect.x;
floatX = floatAvailableSpace.mRect.x;
}
}
*aIsLeftFloat = isLeftFloat;
@ -1105,22 +1101,25 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
if (aReplacedBlock) {
for (;;) {
GetAvailableSpace(newY, PR_FALSE);
nsFlowAreaRect floatAvailableSpace =
GetFloatAvailableSpace(newY, PR_FALSE);
nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
nsBlockFrame::WidthToClearPastFloats(*this, aReplacedBlock);
if (!mBandHasFloats ||
PR_MAX(mAvailSpaceRect.x, replacedWidth.marginLeft) +
nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace.mRect,
aReplacedBlock);
if (!floatAvailableSpace.mHasFloats ||
PR_MAX(floatAvailableSpace.mRect.x, replacedWidth.marginLeft) +
replacedWidth.borderBoxWidth +
PR_MAX(mContentArea.width -
PR_MIN(mContentArea.width, mAvailSpaceRect.XMost()),
PR_MIN(mContentArea.width,
floatAvailableSpace.mRect.XMost()),
replacedWidth.marginRight) <=
mContentArea.width) {
break;
}
// See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
if (mAvailSpaceRect.height > 0) {
if (floatAvailableSpace.mRect.height > 0) {
// See if there's room in the next band.
newY += mAvailSpaceRect.height;
newY += floatAvailableSpace.mRect.height;
} else {
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
// Stop trying to clear here; we'll just get pushed to the
@ -1131,11 +1130,6 @@ nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
newY += 1;
}
}
// Restore mBandHasFloats and mAvailSpaceRect to the way they were.
// This may well not be needed, and we should probably come up with
// well-defined rules about when these members are valid so that
// it's clearly not needed.
GetAvailableSpace();
}
#ifdef DEBUG

View File

@ -83,12 +83,23 @@ public:
void SetupOverflowPlaceholdersProperty();
/**
* Get the available reflow space for the current y coordinate. The
* available space is relative to our coordinate system (0,0) is our
* upper left corner.
* Get the available reflow space (the area not occupied by floats)
* for the current y coordinate. The available space is relative to
* our coordinate system, which is the content box, with (0, 0) in the
* upper left.
*
* Returns whether there are floats present at the given vertical
* coordinate and within the width of the content rect.
*/
void GetAvailableSpace() { GetAvailableSpace(mY, PR_FALSE); }
void GetAvailableSpace(nscoord aY, PRBool aRelaxHeightConstraint);
nsFlowAreaRect GetFloatAvailableSpace() const
{ return GetFloatAvailableSpace(mY, PR_FALSE); }
nsFlowAreaRect GetFloatAvailableSpace(nscoord aY,
PRBool aRelaxHeightConstraint) const
{ return GetFloatAvailableSpaceWithState(aY, aRelaxHeightConstraint,
nsnull); }
nsFlowAreaRect
GetFloatAvailableSpaceWithState(nscoord aY, PRBool aRelaxHeightConstraint,
nsFloatManager::SavedState *aState) const;
/*
* The following functions all return PR_TRUE if they were able to
@ -104,7 +115,9 @@ public:
PRBool aInitialReflow,
nscoord aAvailableWidth,
nsReflowStatus& aReflowStatus);
PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats, PRBool aForceFit);
PRBool CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats,
const nsFlowAreaRect& aFloatAvailableSpace,
PRBool aForceFit);
PRBool FlowAndPlaceFloat(nsFloatCache* aFloatCache,
PRBool* aIsLeftFloat,
nsReflowStatus& aReflowStatus,
@ -149,6 +162,7 @@ public:
// (which need not be the current mY). Callers need only pass
// aReplacedWidth for outer table frames.
void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
const nsRect& aFloatAvailableSpace,
nscoord& aLeftResult,
nscoord& aRightResult,
nsBlockFrame::ReplacedElementWidthToClear
@ -157,6 +171,7 @@ public:
// Caller must have called GetAvailableSpace for the current mY
void ComputeBlockAvailSpace(nsIFrame* aFrame,
const nsStyleDisplay* aDisplay,
const nsFlowAreaRect& aFloatAvailableSpace,
PRBool aBlockAvoidsFloats,
nsRect& aResult);
@ -174,8 +189,6 @@ public:
}
}
PRBool IsImpactedByFloat() const;
nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock);
void FreeLineBox(nsLineBox* aLine);
@ -204,12 +217,11 @@ public:
// XXX get rid of this
nsReflowStatus mReflowStatus;
// The x-position we should place an outside bullet relative to.
// This is the border-box edge of the principal box. However, if a line box
// would be displaced by floats, we want to displace it by the same amount.
// That is, we act as though the edge of the floats is the content-edge of
// the block, displaced by the block's padding and border.
nscoord mOutsideBulletX;
// The float manager state as it was before the contents of this
// block. This is needed for positioning bullets, since we only want
// to move the bullet to flow around floats that were before this
// block, not floats inside of it.
nsFloatManager::SavedState mFloatManagerStateBefore;
nscoord mBottomEdge;
@ -250,10 +262,6 @@ public:
// The current Y coordinate in the block
nscoord mY;
// The available space within the current band.
// (relative to the *content*-rect of the block)
nsRect mAvailSpaceRect;
// The combined area of all floats placed so far
nsRect mFloatCombinedArea;
@ -296,11 +304,6 @@ public:
PRUint8 mFloatBreakType;
// The number of floats on the sides of mAvailSpaceRect, including
// floats that do not reduce mAvailSpaceRect because they are in the
// margins.
PRPackedBool mBandHasFloats;
void SetFlag(PRUint32 aFlag, PRBool aValue)
{
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");

View File

@ -135,11 +135,11 @@ void nsFloatManager::Shutdown()
sCachedFloatManagerCount = -1;
}
nsRect
nsFlowAreaRect
nsFloatManager::GetBand(nscoord aYOffset,
nscoord aMaxHeight,
nscoord aContentAreaWidth,
PRBool* aHasFloats) const
SavedState* aState) const
{
NS_ASSERTION(aMaxHeight >= 0, "unexpected max height");
NS_ASSERTION(aContentAreaWidth >= 0, "unexpected content area width");
@ -150,14 +150,23 @@ nsFloatManager::GetBand(nscoord aYOffset,
top = nscoord_MIN;
}
// Determine the last float that we should consider.
PRUint32 floatCount;
if (aState) {
// Use the provided state.
floatCount = aState->mFloatInfoCount;
NS_ABORT_IF_FALSE(floatCount <= mFloats.Length(), "bad state");
} else {
// Use our current state.
floatCount = mFloats.Length();
}
// If there are no floats at all, or we're below the last one, return
// quickly.
PRUint32 floatCount = mFloats.Length();
if (floatCount == 0 ||
(mFloats[floatCount-1].mLeftYMost <= top &&
mFloats[floatCount-1].mRightYMost <= top)) {
*aHasFloats = PR_FALSE;
return nsRect(0, aYOffset, aContentAreaWidth, aMaxHeight);
return nsFlowAreaRect(0, aYOffset, aContentAreaWidth, aMaxHeight, PR_FALSE);
}
nscoord bottom;
@ -180,7 +189,7 @@ nsFloatManager::GetBand(nscoord aYOffset,
// Walk backwards through the floats until we either hit the front of
// the list or we're above |top|.
PRBool haveFloats = PR_FALSE;
for (PRUint32 i = mFloats.Length(); i > 0; --i) {
for (PRUint32 i = floatCount; i > 0; --i) {
const FloatInfo &fi = mFloats[i-1];
if (fi.mLeftYMost <= top && fi.mRightYMost <= top) {
// There aren't any more floats that could intersect this band.
@ -230,9 +239,8 @@ nsFloatManager::GetBand(nscoord aYOffset,
}
}
*aHasFloats = haveFloats;
nscoord height = (bottom == nscoord_MAX) ? nscoord_MAX : (bottom - top);
return nsRect(left - mX, top - mY, right - left, height);
return nsFlowAreaRect(left - mX, top - mY, right - left, height, haveFloats);
}
nsresult

View File

@ -52,6 +52,22 @@ class nsIFrame;
struct nsHTMLReflowState;
class nsPresContext;
/**
* The available space for content not occupied by floats is divided
* into a (vertical) sequence of rectangles. However, we need to know
* not only the rectangle, but also whether it was reduced (from the
* content rectangle) by floats that actually intruded into the content
* rectangle.
*/
struct nsFlowAreaRect {
nsRect mRect;
PRPackedBool mHasFloats;
nsFlowAreaRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
PRBool aHasFloats)
: mRect(aX, aY, aWidth, aHeight), mHasFloats(aHasFloats) {}
};
#define NS_FLOAT_MANAGER_CACHE_SIZE 4
class nsFloatManager {
@ -64,6 +80,18 @@ public:
static void Shutdown();
// Structure that stores the current state of a frame manager for
// Save/Restore purposes.
struct SavedState;
friend struct SavedState;
struct SavedState {
private:
PRUint32 mFloatInfoCount;
nscoord mX, mY;
friend class nsFloatManager;
};
/**
* Translate the current origin by the specified (dx, dy). This
* creates a new local coordinate space relative to the current
@ -92,18 +120,21 @@ public:
* @param aMaxHeight [in] maximum height of available space desired
* @param aContentAreaWidth [in] the width of the content area (whose left
* edge must be zero in the current translation)
* @param aHasFloats [out] whether there are floats at the sides of
* the return value including those that do not
* reduce the line box width at all (because they
* are entirely in the margins)
* @return the resulting rectangle for line boxes. It will not go
* left of 0, nor right of aContentAreaWidth, but will be
* narrower when floats are present.
* @param aState [in] If null, use the current state, otherwise, do
* computation based only on floats present in the given
* saved state.
* @return An nsFlowAreaRect whose:
* mRect is the resulting rectangle for line boxes. It will not go
* left of 0, nor right of aContentAreaWidth, but will be
* narrower when floats are present.
* mBandHasFloats is whether there are floats at the sides of the
* return value including those that do not reduce the line box
* width at all (because they are entirely in the margins)
*
* aY and aAvailSpace are positioned relative to the current translation
*/
nsRect GetBand(nscoord aY, nscoord aMaxHeight, nscoord aContentAreaWidth,
PRBool* aHasFloats) const;
nsFlowAreaRect GetBand(nscoord aY, nscoord aMaxHeight,
nscoord aContentAreaWidth, SavedState* aState) const;
/**
* Add a float that comes after all floats previously added. Its top
@ -128,18 +159,6 @@ private:
struct FloatInfo;
public:
// Structure that stores the current state of a frame manager for
// Save/Restore purposes.
struct SavedState;
friend struct SavedState;
struct SavedState {
private:
PRUint32 mFloatInfoCount;
nscoord mX, mY;
friend class nsFloatManager;
};
PRBool HasAnyFloats() const { return !mFloats.IsEmpty(); }
/**
@ -172,7 +191,9 @@ public:
* These states must be managed using stack discipline. PopState can only
* be used after PushState has been used to save the state, and it can only
* be used once --- although it can be omitted; saved states can be ignored.
* States must be popped in the reverse order they were pushed.
* States must be popped in the reverse order they were pushed. A
* call to PopState invalidates any saved states Pushed after the
* state passed to PopState was pushed.
*/
void PopState(SavedState* aState);

View File

@ -49,6 +49,7 @@
#include "nsTransform2D.h"
#include "gfxContext.h"
class nsDisplayItemCanvas : public nsDisplayItem {
public:
@ -224,6 +225,7 @@ void
nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect, nsPoint aPt)
{
nsPresContext *presContext = PresContext();
nsRect inner = GetInnerArea() + aPt;
nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
@ -234,34 +236,24 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext,
if (inner.width == 0 || inner.height == 0)
return;
nsIntSize canvasSize = GetCanvasSize();
nsSize sizeAppUnits(PresContext()->DevPixelsToAppUnits(canvasSize.width),
PresContext()->DevPixelsToAppUnits(canvasSize.height));
nsIntSize sizeCSSPixels = GetCanvasSize();
nsSize sizeAppUnits(nsPresContext::CSSPixelsToAppUnits(sizeCSSPixels.width),
nsPresContext::CSSPixelsToAppUnits(sizeCSSPixels.height));
// XXXvlad clip to aDirtyRect!
gfxContext *ctx = aRenderingContext.ThebesContext();
if (inner.Size() != sizeAppUnits)
{
float sx = inner.width / (float) sizeAppUnits.width;
float sy = inner.height / (float) sizeAppUnits.height;
gfxFloat sx = inner.width / (gfxFloat) sizeAppUnits.width;
gfxFloat sy = inner.height / (gfxFloat) sizeAppUnits.height;
aRenderingContext.PushState();
aRenderingContext.Translate(inner.x, inner.y);
aRenderingContext.Scale(sx, sy);
ctx->Save();
canvas->RenderContexts(aRenderingContext.ThebesContext());
ctx->Translate(gfxPoint(presContext->AppUnitsToGfxUnits(inner.x),
presContext->AppUnitsToGfxUnits(inner.y)));
ctx->Scale(sx, sy);
aRenderingContext.PopState();
} else {
//nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py);
canvas->RenderContexts(ctx);
aRenderingContext.PushState();
aRenderingContext.Translate(inner.x, inner.y);
canvas->RenderContexts(aRenderingContext.ThebesContext());
aRenderingContext.PopState();
}
ctx->Restore();
}
NS_IMETHODIMP

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-left: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-left: 40px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-right: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-right: 40px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div></div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div></div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div></div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div></div>
</div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-left: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-left: 40px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-right: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 20px"></div>
<div style="margin-right: 40px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div style="float: left; height: 20px; width: 15px"></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div style="float: left; height: 20px; width: 15px"></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div style="float: right; height: 20px; width: 15px"></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div style="float: right; height: 20px; width: 15px"></div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div style="float: left; height: 20px; width: 15px"></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div style="float: left; height: 20px; width: 15px"></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div style="float: right; height: 20px; width: 15px"></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div style="float: right; height: 20px; width: 15px"></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div style="float: left; height: 20px; width: 15px"></div>
<div style="clear:left"></div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div style="float: left; height: 20px; width: 15px"></div>
<div style="clear:left"></div>
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div style="float: right; height: 20px; width: 15px"></div>
<div style="clear:right"></div>
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div style="float: right; height: 20px; width: 15px"></div>
<div style="clear:right"></div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: left; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 1px 32px 32px; border: medium solid transparent; border-width: 2px 2px 16px 16px; padding: 4px 4px 8px 8px">
<div style="float: left; height: 20px; width: 15px"></div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: left; height: 20px; width: 100px"></div>
</div>
<div style="margin-left: 40px; width: 70px; display: list-item;">
<div style="float: left; height: 20px; width: 15px"></div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 6px">
<div style="float: right; height: 20px; width: 116px"></div>
</div>
<div style="width: 70px; display: list-item; margin: 1px 32px 32px 1px; border: medium solid transparent; border-width: 2px 16px 16px 2px; padding: 4px 8px 8px 4px">
<div style="float: right; height: 20px; width: 15px"></div>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 10px">
<div style="float: right; height: 20px; width: 100px"></div>
</div>
<div style="margin-right: 40px; width: 70px; display: list-item;">
<div style="float: right; height: 20px; width: 15px"></div>
</div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 40px"></div>
<div style="margin-left: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 40px"></div>
<div style="margin-left: 40px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html dir="rtl">
<title>Testcase, bug 428810</title>
<style type="text/css">
html, body { margin: 0; padding: 0; }
</style>
<div style="height: 40px"></div>
<div style="margin-right: 32px; display: list-item;">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div>

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