mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to tracemonkey.
This commit is contained in:
commit
c05dbc60ec
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
"""
|
||||
|
368
build/package/wince/make_wince_cab.py
Normal file
368
build/package/wince/make_wince_cab.py
Normal 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()
|
@ -72,6 +72,7 @@ LIBXUL_SDK = @LIBXUL_SDK@
|
||||
L10NBASEDIR = @L10NBASEDIR@
|
||||
|
||||
LIBXUL_DIST = @LIBXUL_DIST@
|
||||
SYSTEM_LIBXUL = @SYSTEM_LIBXUL@
|
||||
|
||||
XULRUNNER_STUB_NAME = @XULRUNNER_STUB_NAME@
|
||||
|
||||
|
@ -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 ===================================================================
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -89,8 +89,6 @@ public:
|
||||
nsAttrValue& aResult,
|
||||
PRBool aForceInDataDoc);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
|
||||
virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -63,7 +63,6 @@ EXPORTS = \
|
||||
nsIImage.h \
|
||||
nsGfxCIID.h \
|
||||
nsIRegion.h \
|
||||
nsDeviceContext.h \
|
||||
nsITheme.h \
|
||||
nsThemeConstants.h \
|
||||
$(NULL)
|
||||
|
@ -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___ */
|
@ -67,7 +67,6 @@ endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsColor.cpp \
|
||||
nsDeviceContext.cpp \
|
||||
nsFont.cpp \
|
||||
nsRect.cpp \
|
||||
nsRegion.cpp \
|
||||
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -57,7 +57,6 @@ REQUIRES= \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsRenderingContextImpl.cpp \
|
||||
gfxImageFrame.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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 \
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
10
layout/reftests/bugs/428810-1-ltr-insets-ref.html
Normal file
10
layout/reftests/bugs/428810-1-ltr-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
10
layout/reftests/bugs/428810-1-ltr-ref.html
Normal file
10
layout/reftests/bugs/428810-1-ltr-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
11
layout/reftests/bugs/428810-1-rtl-insets-ref.html
Normal file
11
layout/reftests/bugs/428810-1-rtl-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
11
layout/reftests/bugs/428810-1-rtl-ref.html
Normal file
11
layout/reftests/bugs/428810-1-rtl-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
12
layout/reftests/bugs/428810-1a-ltr-insets.html
Normal file
12
layout/reftests/bugs/428810-1a-ltr-insets.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1a-ltr.html
Normal file
12
layout/reftests/bugs/428810-1a-ltr.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1a-rtl-insets.html
Normal file
13
layout/reftests/bugs/428810-1a-rtl-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1a-rtl.html
Normal file
13
layout/reftests/bugs/428810-1a-rtl.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1b-ltr-insets.html
Normal file
12
layout/reftests/bugs/428810-1b-ltr-insets.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1b-ltr.html
Normal file
12
layout/reftests/bugs/428810-1b-ltr.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1b-rtl-insets.html
Normal file
13
layout/reftests/bugs/428810-1b-rtl-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1b-rtl.html
Normal file
13
layout/reftests/bugs/428810-1b-rtl.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1c-ltr-insets.html
Normal file
12
layout/reftests/bugs/428810-1c-ltr-insets.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1c-ltr.html
Normal file
12
layout/reftests/bugs/428810-1c-ltr.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1c-rtl-insets.html
Normal file
13
layout/reftests/bugs/428810-1c-rtl-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1c-rtl.html
Normal file
13
layout/reftests/bugs/428810-1c-rtl.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1d-ltr-insets.html
Normal file
12
layout/reftests/bugs/428810-1d-ltr-insets.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-1d-ltr.html
Normal file
12
layout/reftests/bugs/428810-1d-ltr.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1d-rtl-insets.html
Normal file
13
layout/reftests/bugs/428810-1d-rtl-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-1d-rtl.html
Normal file
13
layout/reftests/bugs/428810-1d-rtl.html
Normal 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>
|
||||
|
10
layout/reftests/bugs/428810-2-ltr-insets-ref.html
Normal file
10
layout/reftests/bugs/428810-2-ltr-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
10
layout/reftests/bugs/428810-2-ltr-ref.html
Normal file
10
layout/reftests/bugs/428810-2-ltr-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
11
layout/reftests/bugs/428810-2-rtl-insets-ref.html
Normal file
11
layout/reftests/bugs/428810-2-rtl-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
11
layout/reftests/bugs/428810-2-rtl-ref.html
Normal file
11
layout/reftests/bugs/428810-2-rtl-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
13
layout/reftests/bugs/428810-2a-ltr-insets.html
Normal file
13
layout/reftests/bugs/428810-2a-ltr-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-2a-ltr.html
Normal file
13
layout/reftests/bugs/428810-2a-ltr.html
Normal 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>
|
||||
|
14
layout/reftests/bugs/428810-2a-rtl-insets.html
Normal file
14
layout/reftests/bugs/428810-2a-rtl-insets.html
Normal 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>
|
||||
|
14
layout/reftests/bugs/428810-2a-rtl.html
Normal file
14
layout/reftests/bugs/428810-2a-rtl.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-2b-ltr-insets.html
Normal file
13
layout/reftests/bugs/428810-2b-ltr-insets.html
Normal 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> </div>
|
||||
</div>
|
||||
|
13
layout/reftests/bugs/428810-2b-ltr.html
Normal file
13
layout/reftests/bugs/428810-2b-ltr.html
Normal 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> </div>
|
||||
</div>
|
||||
|
14
layout/reftests/bugs/428810-2b-rtl-insets.html
Normal file
14
layout/reftests/bugs/428810-2b-rtl-insets.html
Normal 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> </div>
|
||||
</div>
|
||||
|
14
layout/reftests/bugs/428810-2b-rtl.html
Normal file
14
layout/reftests/bugs/428810-2b-rtl.html
Normal 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> </div>
|
||||
</div>
|
||||
|
13
layout/reftests/bugs/428810-2e-ltr-insets.html
Normal file
13
layout/reftests/bugs/428810-2e-ltr-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-2e-ltr.html
Normal file
13
layout/reftests/bugs/428810-2e-ltr.html
Normal 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>
|
||||
|
14
layout/reftests/bugs/428810-2e-rtl-insets.html
Normal file
14
layout/reftests/bugs/428810-2e-rtl-insets.html
Normal 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>
|
||||
|
14
layout/reftests/bugs/428810-2e-rtl.html
Normal file
14
layout/reftests/bugs/428810-2e-rtl.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-2f-ltr-insets.html
Normal file
12
layout/reftests/bugs/428810-2f-ltr-insets.html
Normal 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>
|
||||
|
12
layout/reftests/bugs/428810-2f-ltr.html
Normal file
12
layout/reftests/bugs/428810-2f-ltr.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-2f-rtl-insets.html
Normal file
13
layout/reftests/bugs/428810-2f-rtl-insets.html
Normal 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>
|
||||
|
13
layout/reftests/bugs/428810-2f-rtl.html
Normal file
13
layout/reftests/bugs/428810-2f-rtl.html
Normal 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>
|
||||
|
10
layout/reftests/bugs/428810-3-ltr-insets-ref.html
Normal file
10
layout/reftests/bugs/428810-3-ltr-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
10
layout/reftests/bugs/428810-3-ltr-ref.html
Normal file
10
layout/reftests/bugs/428810-3-ltr-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
11
layout/reftests/bugs/428810-3-rtl-insets-ref.html
Normal file
11
layout/reftests/bugs/428810-3-rtl-insets-ref.html
Normal 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;">
|
||||
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user