Merge autoland to mozilla-central. a=merge

This commit is contained in:
Mihai Alexandru Michis 2019-08-02 12:47:54 +03:00
Родитель e9b6a4610d 905c456380
Коммит b3fd653bc6
107 изменённых файлов: 1807 добавлений и 1417 удалений

Просмотреть файл

@ -33,12 +33,13 @@
#include "nsRange.h"
#include "nsTextFragment.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/dom/Element.h"
#include "mozilla/EventStates.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PresShell.h"
#include "mozilla/TextEditor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/Selection.h"
#include "gfxSkipChars.h"
#include <algorithm>
@ -255,13 +256,10 @@ uint32_t HyperTextAccessible::DOMPointToOffset(nsINode* aNode,
// first search)
Accessible* descendant = nullptr;
if (findNode) {
nsCOMPtr<nsIContent> findContent(do_QueryInterface(findNode));
if (findContent && findContent->IsHTMLElement(nsGkAtoms::br) &&
findContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::mozeditorbogusnode,
nsGkAtoms::_true, eIgnoreCase)) {
// This <br> is the hacky "bogus node" used when there is no text in a
// control
dom::HTMLBRElement* brElement = dom::HTMLBRElement::FromNode(findNode);
if (brElement && brElement->IsPaddingForEmptyEditor()) {
// This <br> is the hacky "padding <br> element" used when there is no
// text in the editor.
return 0;
}

Просмотреть файл

@ -34,6 +34,12 @@ OuterDocAccessible::OuterDocAccessible(nsIContent* aContent,
: AccessibleWrap(aContent, aDoc) {
mType = eOuterDocType;
#ifdef XP_WIN
if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
remoteDoc->SendParentCOMProxy(this);
}
#endif
if (IPCAccessibilityActive()) {
auto bridge = dom::BrowserBridgeChild::GetFrom(aContent);
if (bridge) {

Просмотреть файл

@ -767,7 +767,12 @@ void DocAccessibleParent::SendParentCOMProxy(Accessible* aOuterDoc) {
RefPtr<IAccessible> nativeAcc;
aOuterDoc->GetNativeInterface(getter_AddRefs(nativeAcc));
MOZ_ASSERT(nativeAcc);
if (NS_WARN_IF(!nativeAcc)) {
// Couldn't get a COM proxy for the outer doc. That probably means it died,
// but the parent process hasn't received a message to remove it from the
// ProxyAccessible tree yet.
return;
}
RefPtr<IDispatch> wrapped(
mscom::PassthruProxy::Wrap<IDispatch>(WrapNotNull(nativeAcc)));

Просмотреть файл

@ -218,6 +218,9 @@ class DocAccessibleParent : public ProxyAccessible,
void MaybeInitWindowEmulation();
/**
* Note that an OuterDocAccessible can be created before the
* DocAccessibleParent or vice versa. Therefore, this must be conditionally
* called when either of these is created.
* @param aOuterDoc The OuterDocAccessible to be returned as the parent of
* this document. Only GetNativeInterface() is called on this, so it
* may be a ProxyAccessibleWrap or similar.

Просмотреть файл

@ -46,7 +46,7 @@ void DocAccessibleChild::Shutdown() {
ipc::IPCResult DocAccessibleChild::RecvParentCOMProxy(
const IDispatchHolder& aParentCOMProxy) {
MOZ_ASSERT(!mParentProxy && !aParentCOMProxy.IsNull());
MOZ_ASSERT(!aParentCOMProxy.IsNull());
mParentProxy.reset(const_cast<IDispatchHolder&>(aParentCOMProxy).Release());
SetConstructedInParentProcess();

Просмотреть файл

@ -1547,10 +1547,9 @@ pref("browser.ping-centre.production.endpoint", "https://tiles.services.mozilla.
// Enable GMP support in the addon manager.
pref("media.gmp-provider.enabled", true);
#ifdef EARLY_BETA_OR_EARLIER
// Enable blocking access to storage from tracking resources only in nightly
// and early beta. By default the value is 0: BEHAVIOR_ACCEPT
// Enable blocking access to storage from tracking resources by default.
pref("network.cookie.cookieBehavior", 4 /* BEHAVIOR_REJECT_TRACKER */);
#ifdef EARLY_BETA_OR_EARLIER
// Enable fingerprinting blocking by default only in nightly and early beta.
pref("privacy.trackingprotection.fingerprinting.enabled", true);
#endif
@ -1740,12 +1739,8 @@ pref("signon.generation.enabled", true);
pref("signon.schemeUpgrades", true);
pref("signon.privateBrowsingCapture.enabled", true);
pref("signon.showAutoCompleteFooter", true);
#ifdef NIGHTLY_BUILD
pref("signon.management.page.enabled", true);
pref("signon.management.overrideURI", "about:logins?filter=%DOMAIN%");
#else
pref("signon.management.page.enabled", false);
#endif
pref("signon.management.page.breach-alerts.enabled", false);
#ifdef NIGHTLY_BUILD
// Bug 1563330 tracks shipping this by default.

Просмотреть файл

@ -0,0 +1,233 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# PGO
# ==============================================================
@depends(c_compiler, check_build_environment, target)
@imports('multiprocessing')
@imports(_from='__builtin__', _import='min')
def pgo_flags(compiler, build_env, target):
topobjdir = build_env.topobjdir
if topobjdir.endswith('/js/src'):
topobjdir = topobjdir[:-7]
if compiler.type == 'gcc':
return namespace(
gen_cflags=['-fprofile-generate'],
gen_ldflags=['-fprofile-generate'],
use_cflags=['-fprofile-use', '-fprofile-correction',
'-Wcoverage-mismatch'],
use_ldflags=['-fprofile-use'],
)
if compiler.type in ('clang-cl', 'clang'):
profdata = os.path.join(topobjdir, 'merged.profdata')
prefix = ''
if compiler.type == 'clang-cl':
prefix = '/clang:'
if target.cpu == 'x86_64':
gen_ldflags = ['clang_rt.profile-x86_64.lib']
elif target.cpu == 'x86':
gen_ldflags = ['clang_rt.profile-i386.lib']
else:
gen_ldflags = None
else:
gen_ldflags = ['-fprofile-generate']
return namespace(
gen_cflags=[prefix + '-fprofile-generate'],
gen_ldflags=gen_ldflags,
use_cflags=[prefix + '-fprofile-use=%s' % profdata,
# Some error messages about mismatched profile data
# come in via -Wbackend-plugin, so disable those too.
'-Wno-error=backend-plugin'],
use_ldflags=[],
)
set_config('PROFILE_GEN_CFLAGS', pgo_flags.gen_cflags)
set_config('PROFILE_GEN_LDFLAGS', pgo_flags.gen_ldflags)
set_config('PROFILE_USE_CFLAGS', pgo_flags.use_cflags)
set_config('PROFILE_USE_LDFLAGS', pgo_flags.use_ldflags)
llvm_profdata = check_prog('LLVM_PROFDATA', ['llvm-profdata'],
allow_missing=True,
paths=toolchain_search_path)
js_option('--enable-profile-generate',
nargs='?',
choices=('cross',),
help='Build a PGO instrumented binary')
imply_option('MOZ_PGO',
depends_if('--enable-profile-generate')(lambda _: True))
set_config('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
set_define('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
js_option('--enable-profile-use',
nargs='?',
choices=('cross',),
help='Use a generated profile during the build')
js_option('--with-pgo-profile-path',
help='Path to the directory with unmerged profile data to use during the build',
nargs=1)
js_option('--enable-cross-pgo',
help='Enable PGO on Rust code')
imply_option('MOZ_PGO',
depends_if('--enable-profile-use')(lambda _: True))
set_config('MOZ_PROFILE_USE',
depends_if('--enable-profile-use')(lambda _: True))
@depends('--with-pgo-profile-path', '--enable-profile-use', llvm_profdata)
@imports('os')
def pgo_profile_path(path, pgo_use, profdata):
if not path:
return
if path and not pgo_use:
die('Pass --enable-profile-use to use --with-pgo-profile-path.')
if path and not profdata:
die('LLVM_PROFDATA must be set to process the pgo profile.')
if not os.path.isdir(path[0]):
die('Argument to --with-pgo-profile-path must be a directory.')
if not os.path.isabs(path[0]):
die('Argument to --with-pgo-profile-path must be an absolute path.')
return path[0]
set_config('PGO_PROFILE_PATH', pgo_profile_path)
option('--with-pgo-jarlog',
help='Use the provided jarlog file when packaging during a profile-use '
'build',
nargs=1)
set_config('PGO_JARLOG_PATH', depends_if('--with-pgo-jarlog')(lambda p: p))
@depends('MOZ_PGO', '--enable-profile-use', '--enable-profile-generate',
c_compiler, rustc_info)
def moz_pgo_rust(pgo, profile_use, profile_generate, c_compiler, rustc):
if not pgo:
return
# Enabling PGO through MOZ_PGO only and not --enable* flags.
if not profile_use and not profile_generate:
return
if profile_use and profile_generate:
die('Cannot build with --enable-profile-use and --enable-profile-generate.')
want_cross = (len(profile_use) and profile_use[0] == 'cross') \
or (len(profile_generate) and profile_generate[0] == 'cross')
if not want_cross:
return
if c_compiler.type == 'gcc':
die('Cannot use cross-language PGO with GCC.')
# PGO is not stable prior to 1.37
if rustc.version < Version('1.37'):
die('Cannot use cross-language PGO with Rust version %s.' % rustc.version)
return True
set_config('MOZ_PGO_RUST', moz_pgo_rust)
# LTO
# ==============================================================
js_option('--enable-lto',
env='MOZ_LTO',
nargs='?',
choices=('full', 'thin', 'cross'),
help='Enable LTO')
js_option(env='MOZ_LD64_KNOWN_GOOD',
nargs=1,
help='Indicate that ld64 is free of symbol aliasing bugs.')
imply_option('MOZ_LD64_KNOWN_GOOD', depends_if('MOZ_AUTOMATION')(lambda _: True))
@depends('--enable-lto', 'MOZ_PGO', '--enable-profile-generate', c_compiler,
'MOZ_LD64_KNOWN_GOOD', target)
@imports('multiprocessing')
def lto(value, pgo, profile_generate, c_compiler, ld64_known_good, target):
cflags = []
ldflags = []
enabled = None
rust_lto = False
# MSVC's implementation of PGO implies LTO. Make clang-cl match this.
if c_compiler.type == 'clang-cl' and pgo and not profile_generate and value.origin == 'default':
value = ['cross']
if value:
enabled = True
# `cross` implies `thin`, but with Rust code participating in LTO
# as well. Make that a little more explicit.
if len(value) and value[0].lower() == 'cross':
if c_compiler.type == 'gcc':
die('Cross-language LTO is not supported with GCC.')
rust_lto = True
value = ['thin']
if target.kernel == 'Darwin' and target.os == 'OSX' \
and value[0].lower() == 'cross' and not ld64_known_good:
die('The Mac linker is known to have a bug that affects cross-language '
'LTO. If you know that your linker is free from this bug, please '
'set the environment variable `MOZ_LD64_KNOWN_GOOD=1` and re-run '
'configure.')
if c_compiler.type == 'clang':
if len(value) and value[0].lower() == 'full':
cflags.append("-flto")
ldflags.append("-flto")
else:
cflags.append("-flto=thin")
ldflags.append("-flto=thin")
elif c_compiler.type == 'clang-cl':
if len(value) and value[0].lower() == 'full':
cflags.append("-flto")
else:
cflags.append("-flto=thin")
# With clang-cl, -flto can only be used with -c or -fuse-ld=lld.
# AC_TRY_LINKs during configure don't have -c, so pass -fuse-ld=lld.
cflags.append("-fuse-ld=lld");
else:
num_cores = multiprocessing.cpu_count()
cflags.append("-flto")
cflags.append("-flifetime-dse=1")
ldflags.append("-flto=%s" % num_cores)
ldflags.append("-flifetime-dse=1")
return namespace(
enabled=enabled,
cflags=cflags,
ldflags=ldflags,
rust_lto=rust_lto,
)
add_old_configure_assignment('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO', lto.enabled)
set_define('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO_CFLAGS', lto.cflags)
set_config('MOZ_LTO_LDFLAGS', lto.ldflags)
set_config('MOZ_LTO_RUST', lto.rust_lto)
add_old_configure_assignment('MOZ_LTO_CFLAGS', lto.cflags)
add_old_configure_assignment('MOZ_LTO_LDFLAGS', lto.ldflags)

Просмотреть файл

@ -96,6 +96,7 @@ def rustc_info(rustc):
version=Version(info.get('release', '0')),
commit=info.get('commit-hash', 'unknown'),
host=info['host'],
llvm_version=Version(info.get('LLVM version', '0')),
)
set_config('RUSTC_VERSION', depends(rustc_info)(lambda info: str(info.version)))

Просмотреть файл

@ -1411,54 +1411,6 @@ set_config('_DEPEND_CFLAGS', depend_cflags(c_compiler))
set_config('_HOST_DEPEND_CFLAGS', depend_cflags(host_c_compiler))
@depends(c_compiler, check_build_environment, target)
@imports('multiprocessing')
@imports(_from='__builtin__', _import='min')
def pgo_flags(compiler, build_env, target):
topobjdir = build_env.topobjdir
if topobjdir.endswith('/js/src'):
topobjdir = topobjdir[:-7]
if compiler.type == 'gcc':
return namespace(
gen_cflags=['-fprofile-generate'],
gen_ldflags=['-fprofile-generate'],
use_cflags=['-fprofile-use', '-fprofile-correction',
'-Wcoverage-mismatch'],
use_ldflags=['-fprofile-use'],
)
if compiler.type in ('clang-cl', 'clang'):
profdata = os.path.join(topobjdir, 'merged.profdata')
prefix = ''
if compiler.type == 'clang-cl':
prefix = '/clang:'
if target.cpu == 'x86_64':
gen_ldflags = ['clang_rt.profile-x86_64.lib']
elif target.cpu == 'x86':
gen_ldflags = ['clang_rt.profile-i386.lib']
else:
gen_ldflags = None
else:
gen_ldflags = ['-fprofile-generate']
return namespace(
gen_cflags=[prefix + '-fprofile-generate'],
gen_ldflags=gen_ldflags,
use_cflags=[prefix + '-fprofile-use=%s' % profdata,
# Some error messages about mismatched profile data
# come in via -Wbackend-plugin, so disable those too.
'-Wno-error=backend-plugin'],
use_ldflags=[],
)
set_config('PROFILE_GEN_CFLAGS', pgo_flags.gen_cflags)
set_config('PROFILE_GEN_LDFLAGS', pgo_flags.gen_ldflags)
set_config('PROFILE_USE_CFLAGS', pgo_flags.use_cflags)
set_config('PROFILE_USE_LDFLAGS', pgo_flags.use_ldflags)
@depends(c_compiler)
def preprocess_option(compiler):
# The uses of PREPROCESS_OPTION depend on the spacing for -o/-Fi.
@ -1482,149 +1434,6 @@ def is_windows(target, host):
include('windows.configure', when=is_windows)
# PGO
# ==============================================================
llvm_profdata = check_prog('LLVM_PROFDATA', ['llvm-profdata'],
allow_missing=True,
paths=toolchain_search_path)
js_option('--enable-profile-generate',
help='Build a PGO instrumented binary')
imply_option('MOZ_PGO',
depends_if('--enable-profile-generate')(lambda _: True))
set_config('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
set_define('MOZ_PROFILE_GENERATE',
depends_if('--enable-profile-generate')(lambda _: True))
js_option('--enable-profile-use',
help='Use a generated profile during the build')
js_option('--with-pgo-profile-path',
help='Path to the directory with unmerged profile data to use during the build',
nargs=1)
imply_option('MOZ_PGO',
depends_if('--enable-profile-use')(lambda _: True))
set_config('MOZ_PROFILE_USE',
depends_if('--enable-profile-use')(lambda _: True))
@depends('--with-pgo-profile-path', '--enable-profile-use', llvm_profdata)
@imports('os')
def pgo_profile_path(path, pgo_use, profdata):
if not path:
return
if path and not pgo_use:
die('Pass --enable-profile-use to use --with-pgo-profile-path.')
if path and not profdata:
die('LLVM_PROFDATA must be set to process the pgo profile.')
if not os.path.isdir(path[0]):
die('Argument to --with-pgo-profile-path must be a directory.')
if not os.path.isabs(path[0]):
die('Argument to --with-pgo-profile-path must be an absolute path.')
return path[0]
set_config('PGO_PROFILE_PATH', pgo_profile_path)
option('--with-pgo-jarlog',
help='Use the provided jarlog file when packaging during a profile-use '
'build',
nargs=1)
set_config('PGO_JARLOG_PATH', depends_if('--with-pgo-jarlog')(lambda p: p))
# LTO
# ==============================================================
js_option('--enable-lto',
env='MOZ_LTO',
nargs='?',
choices=('full', 'thin', 'cross'),
help='Enable LTO')
js_option(env='MOZ_LD64_KNOWN_GOOD',
nargs=1,
help='Indicate that ld64 is free of symbol aliasing bugs.')
imply_option('MOZ_LD64_KNOWN_GOOD', depends_if('MOZ_AUTOMATION')(lambda _: True))
@depends('--enable-lto', 'MOZ_PGO', '--enable-profile-generate', c_compiler,
'MOZ_LD64_KNOWN_GOOD', target)
@imports('multiprocessing')
def lto(value, pgo, profile_generate, c_compiler, ld64_known_good, target):
cflags = []
ldflags = []
enabled = None
rust_lto = False
# MSVC's implementation of PGO implies LTO. Make clang-cl match this.
if c_compiler.type == 'clang-cl' and pgo and not profile_generate and value.origin == 'default':
value = ['cross']
if value:
enabled = True
# `cross` implies `thin`, but with Rust code participating in LTO
# as well. Make that a little more explicit.
if len(value) and value[0].lower() == 'cross':
if c_compiler.type == 'gcc':
die('Cross-language LTO is not supported with GCC.')
rust_lto = True
value = ['thin']
if target.kernel == 'Darwin' and target.os == 'OSX' \
and value[0].lower() == 'cross' and not ld64_known_good:
die('The Mac linker is known to have a bug that affects cross-language '
'LTO. If you know that your linker is free from this bug, please '
'set the environment variable `MOZ_LD64_KNOWN_GOOD=1` and re-run '
'configure.')
if c_compiler.type == 'clang':
if len(value) and value[0].lower() == 'full':
cflags.append("-flto")
ldflags.append("-flto")
else:
cflags.append("-flto=thin")
ldflags.append("-flto=thin")
elif c_compiler.type == 'clang-cl':
if len(value) and value[0].lower() == 'full':
cflags.append("-flto")
else:
cflags.append("-flto=thin")
# With clang-cl, -flto can only be used with -c or -fuse-ld=lld.
# AC_TRY_LINKs during configure don't have -c, so pass -fuse-ld=lld.
cflags.append("-fuse-ld=lld");
else:
num_cores = multiprocessing.cpu_count()
cflags.append("-flto")
cflags.append("-flifetime-dse=1")
ldflags.append("-flto=%s" % num_cores)
ldflags.append("-flifetime-dse=1")
return namespace(
enabled=enabled,
cflags=cflags,
ldflags=ldflags,
rust_lto=rust_lto,
)
add_old_configure_assignment('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO', lto.enabled)
set_define('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO_CFLAGS', lto.cflags)
set_config('MOZ_LTO_LDFLAGS', lto.ldflags)
set_config('MOZ_LTO_RUST', lto.rust_lto)
add_old_configure_assignment('MOZ_LTO_CFLAGS', lto.cflags)
add_old_configure_assignment('MOZ_LTO_LDFLAGS', lto.ldflags)
# ASAN
# ==============================================================

Просмотреть файл

@ -132,7 +132,11 @@ export MOZ_TOPOBJDIR=$(topobjdir)
target_rust_ltoable := force-cargo-library-build
target_rust_nonltoable := force-cargo-test-run force-cargo-library-check $(foreach b,build check,force-cargo-program-$(b))
$(target_rust_ltoable): RUSTFLAGS:=$(rustflags_override) $(RUSTFLAGS) $(if $(MOZ_LTO_RUST),-Clinker-plugin-lto)
ifdef MOZ_PGO_RUST
rust_pgo_flags := $(if $(MOZ_PROFILE_GENERATE),-C profile-generate=$(topobjdir)) $(if $(MOZ_PROFILE_USE),-C profile-use=$(topobjdir)/merged.profdata)
endif
$(target_rust_ltoable): RUSTFLAGS:=$(rustflags_override) $(RUSTFLAGS) $(if $(MOZ_LTO_RUST),-Clinker-plugin-lto) $(rust_pgo_flags)
$(target_rust_nonltoable): RUSTFLAGS:=$(rustflags_override) $(RUSTFLAGS)
TARGET_RECIPES := $(target_rust_ltoable) $(target_rust_nonltoable)

Просмотреть файл

@ -25,7 +25,6 @@ copyToClipboard.accesskey=C
# LOCALIZATION NOTE (copySource.label): This is the text that appears in the
# context menu to copy the selected source of file open.
copySource=Copy
copySource.label=Copy source text
copySource.accesskey=y
@ -50,7 +49,6 @@ setDirectoryRoot.accesskey=r
# LOCALIZATION NOTE (removeDirectoryRoot.label): This is the text that appears in the
# context menu to remove a directory as root directory
removeDirectoryRoot.label=Remove directory root
removeDirectoryRoot.accesskey=d
# LOCALIZATION NOTE (copyFunction.label): This is the text that appears in the
# context menu to copy the function the user selected
@ -106,26 +104,10 @@ skipPausingTooltip.label=Deactivate breakpoints
# breakpoints and pausing triggers
undoSkipPausingTooltip.label=Activate breakpoints
# LOCALIZATION NOTE (pauseButtonItem): The label that is displayed for the dropdown pause
# list item when the debugger is in a running state.
pauseButtonItem=Pause on Next Statement
# LOCALIZATION NOTE (ignoreExceptionsItem): The pause on exceptions button description
# when the debugger will not pause on exceptions.
ignoreExceptionsItem=Ignore exceptions
# LOCALIZATION NOTE (pauseOnUncaughtExceptionsItem): The pause on exceptions dropdown
# item shown when a user is adding a new breakpoint.
pauseOnUncaughtExceptionsItem=Pause on uncaught exceptions
# LOCALIZATION NOTE (pauseOnExceptionsItem2): The pause on exceptions checkbox description
# when the debugger will pause on all exceptions.
pauseOnExceptionsItem2=Pause on exceptions
# LOCALIZATION NOTE (ignoreCaughtExceptionsItem): The pause on exceptions checkbox description
# when the debugger will not pause on any caught exception
ignoreCaughtExceptionsItem=Ignore caught exceptions
# LOCALIZATION NOTE (pauseOnCaughtExceptionsItem): The pause on exceptions checkbox description
# when the debugger should pause on caught exceptions
pauseOnCaughtExceptionsItem=Pause on caught exceptions
@ -141,76 +123,14 @@ threadsHeader=Threads
# program as opposed to worker threads.
mainThread=Main Thread
# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list
# when there are no workers.
noWorkersText=This page has no workers.
# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list
# when there are no sources.
noSourcesText=This page has no sources.
# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab
# when there are no events.
noEventListenersText=No event listeners to display.
# LOCALIZATION NOTE (eventListenersHeader1): The text to display in the events
# header.
eventListenersHeader1=Event Listener Breakpoints
# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab
# when there are no stack frames.
noStackFramesText=No stack frames to display
# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when
# the user hovers over the checkbox used to toggle an event breakpoint.
eventCheckboxTooltip=Toggle breaking on this event
# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab
# for every event item, between the event type and event selector.
eventOnSelector=on
# LOCALIZATION NOTE (eventInSource): The text to display in the events tab
# for every event item, between the event selector and listener's owner source.
eventInSource=in
# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when
# an event is listened on more than one target node.
eventNodes=%S nodes
# LOCALIZATION NOTE (eventNative): The text to display in the events tab when
# a listener is added from plugins, thus getting translated to native code.
eventNative=[native code]
# LOCALIZATION NOTE (*Events): The text to display in the events tab for
# each group of sub-level event entries.
animationEvents=Animation
audioEvents=Audio
batteryEvents=Battery
clipboardEvents=Clipboard
compositionEvents=Composition
deviceEvents=Device
displayEvents=Display
dragAndDropEvents=Drag and Drop
gamepadEvents=Gamepad
indexedDBEvents=IndexedDB
interactionEvents=Interaction
keyboardEvents=Keyboard
mediaEvents=HTML5 Media
mouseEvents=Mouse
mutationEvents=Mutation
navigationEvents=Navigation
pointerLockEvents=Pointer Lock
sensorEvents=Sensor
storageEvents=Storage
timeEvents=Time
touchEvents=Touch
otherEvents=Other
# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when
# the user hovers over the checkbox used to toggle blackboxing its associated
# source.
blackboxCheckboxTooltip2=Toggle blackboxing
# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for
# searching all the source files the debugger has seen.
# Do not localize "CmdOrCtrl+P", or change the format of the string. These are
@ -283,14 +203,6 @@ projectTextSearch.placeholder=Find in files…
# message when the query did not match any text of all files in a project.
projectTextSearch.noResults=No results found
# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger
# does not have any sources.
sources.noSourcesAvailable=This page has no sources
# LOCALIZATION NOTE (sources.noSourcesAvailableRoot): Text shown when the debugger
# does not have any sources under a specific directory root.
sources.noSourcesAvailableRoot=This directory root has no sources
# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search
# for searching within a the currently opened files in the editor
# Do not localize "CmdOrCtrl+F", or change the format of the string. These are
@ -322,50 +234,6 @@ sourceSearch.search.againPrev.key3=Cmd+Shift+G
# Shows a summary of the number of matches for autocomplete
sourceSearch.resultsSummary2=#1 result;#1 results
# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the
# global search results when there are no matching strings after filtering.
noMatchingStringsText=No matches found
# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the
# filter text box when it is empty and the scripts container is selected.
emptySearchText=Search scripts (%S)
# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that
# appears in the filter text box for the variables view container.
emptyVariablesFilterText=Filter variables
# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that
# appears in the filter text box for the editor's variables view bubble.
emptyPropertiesFilterText=Filter properties
# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the
# filter panel popup for the filter scripts operation.
searchPanelFilter=Filter scripts (%S)
# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the
# filter panel popup for the global search operation.
searchPanelGlobal=Search in all files (%S)
# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the
# filter panel popup for the function search operation.
searchPanelFunction=Search for function definition (%S)
# LOCALIZATION NOTE (searchPanelFunction2): This is the text that appears in the
# filter panel popup for the function search operation.
searchPanelFunction2=Find function definition (%S)
# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the
# filter panel popup for the token search operation.
searchPanelToken=Find in this file (%S)
# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the
# filter panel popup for the line search operation.
searchPanelGoToLine=Go to line (%S)
# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the
# filter panel popup for the variables search operation.
searchPanelVariable=Filter variables (%S)
# LOCALIZATION NOTE (breakpointHeadingMenuItem.*): The text for all the elements
# that are displayed in the breakpoint headings menu item popup.
breakpointHeadingsMenuItem.enableInSource.label=Enable breakpoints
@ -377,7 +245,6 @@ breakpointHeadingsMenuItem.removeInSource.accesskey=R
# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that
# are displayed in the breakpoints menu item popup.
breakpointMenuItem.setConditional=Configure conditional breakpoint
breakpointMenuItem.enableSelf2.label=Enable
breakpointMenuItem.enableSelf2.accesskey=E
breakpointMenuItem.disableSelf2.label=Disable
@ -403,27 +270,14 @@ breakpointMenuItem.addCondition2.accesskey=A
breakpointMenuItem.editCondition2.label=Edit condition
breakpointMenuItem.editCondition2.accesskey=n
breakpointMenuItem.enableSelf=Enable breakpoint
breakpointMenuItem.enableSelf.accesskey=E
breakpointMenuItem.disableSelf=Disable breakpoint
breakpointMenuItem.disableSelf.accesskey=D
breakpointMenuItem.deleteSelf=Remove breakpoint
breakpointMenuItem.deleteSelf.accesskey=R
breakpointMenuItem.enableOthers=Enable others
breakpointMenuItem.enableOthers.accesskey=o
breakpointMenuItem.disableOthers=Disable others
breakpointMenuItem.disableOthers.accesskey=s
breakpointMenuItem.deleteOthers=Remove others
breakpointMenuItem.deleteOthers.accesskey=h
breakpointMenuItem.enableAll=Enable all breakpoints
breakpointMenuItem.enableAll.accesskey=b
breakpointMenuItem.disableAll=Disable all breakpoints
breakpointMenuItem.disableAll.accesskey=k
breakpointMenuItem.deleteAll=Remove all breakpoints
breakpointMenuItem.deleteAll.accesskey=a
breakpointMenuItem.removeCondition.label=Remove breakpoint condition
breakpointMenuItem.removeCondition.accesskey=c
breakpointMenuItem.editCondition.label=Edit breakpoint condition
breakpointMenuItem.editCondition.accesskey=n
breakpointMenuItem.disableAllAtLine.label=Disable breakpoints on line
breakpointMenuItem.disableAllAtLine.accesskey=K
breakpointMenuItem.enableAllAtLine.label=Enable breakpoints on line
@ -434,10 +288,6 @@ breakpointMenuItem.removeAllAtLine.accesskey=X
# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.
breakpoints.header=Breakpoints
# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are
# no breakpoints present
breakpoints.none=No breakpoints
# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip
# when hovering over the 'disable breakpoints' switch button in right sidebar
breakpoints.enable=Enable breakpoints
@ -479,18 +329,11 @@ callStack.group.expandTooltip=Show %S frames
# example: `Collapse React frames`.
callStack.group.collapseTooltip=Collapse %S frames
# LOCALIZATION NOTE (components.header): Header for the
# Framework Components pane in the right sidebar.
components.header=Components
# LOCALIZATION NOTE (editor.searchResults1): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# Editor Search bar message to summarize the selected search result. e.g. 5 of 10 results.
editor.searchResults1=%d of #1 result;%d of #1 results
# LOCALIZATION NOTE (editor.singleResult): Copy shown when there is one result.
editor.singleResult=1 result
# LOCALIZATION NOTE (editor.noResultsFound): Editor Search bar message
# for when no results found.
editor.noResultsFound=No results found
@ -503,10 +346,6 @@ editor.searchResults.nextResult=Next result
# tooltip for traversing to the Previous Result
editor.searchResults.prevResult=Previous result
# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for
# toggling search type buttons(function search, variable search)
editor.searchTypeToggleTitle=Search for:
# LOCALIZATION NOTE (editor.continueToHere.label): Editor gutter context
# menu item for jumping to a new paused location
editor.continueToHere.label=Continue to here
@ -538,14 +377,6 @@ editor.addConditionBreakpoint.accesskey=c
# for setting a breakpoint condition on a line.
editor.editConditionBreakpoint=Edit condition
# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context menu item
# for creating a breakpoint with a condition
editor.addConditionalBreakpoint=Add conditional breakpoint
# LOCALIZATION NOTE (editor.addLogBreakpoint): Editor gutter context menu item
# for creating a breakpoint with a log
editor.addLogBreakpoint=Add log point
# LOCALIZATION NOTE (editor.addLogPoint): Editor gutter context
# menu item for adding a log point on a line.
editor.addLogPoint=Add log
@ -569,10 +400,6 @@ editor.conditionalPanel.placeholder2=Breakpoint condition, e.g. items.length > 0
# input element inside ConditionalPanel component when a log point is set
editor.conditionalPanel.logPoint.placeholder2=Log message, e.g. displayName
# LOCALIZATION NOTE (editor.conditionalPanel.close): Tooltip text for
# close button inside ConditionalPanel component
editor.conditionalPanel.close=Cancel edit breakpoint and close
# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item
# for navigating to a source mapped location
editor.jumpToMappedLocation1=Jump to %S location
@ -608,7 +435,6 @@ expressions.placeholder=Add watch expression
expressions.errorMsg=Invalid expression…
expressions.label=Add watch expression
expressions.accesskey=e
expressions.key=CmdOrCtrl+Shift+E
expressions.remove.tooltip=Remove watch expression
# LOCALIZATION NOTE (xhrBreakpoints.header): The pause on any XHR breakpoints headings
@ -662,7 +488,6 @@ sourceFooter.blackbox.accesskey=B
# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated
# with the blackbox button
sourceFooter.unblackbox=Unblackbox source
sourceFooter.unblackbox.accesskey=b
# LOCALIZATION NOTE (sourceFooter.mappedSource): Text associated
# with a mapped source. %S is replaced by the source map origin.
@ -676,10 +501,6 @@ sourceFooter.mappedSourceTooltip=(Source mapped from %S)
# with a mapped source. Displays next to URLs in tree and tabs.
sourceFooter.mappedSuffix=(mapped)
# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated
# with a code coverage button
sourceFooter.codeCoverage=Code coverage
# LOCALIZATION NOTE (sourceFooter.currentCursorPosition): Text associated
# with the current cursor line and column
sourceFooter.currentCursorPosition=(%1$S, %2$S)
@ -724,9 +545,6 @@ sources.header=Sources
# LOCALIZATION NOTE (outline.header): Outline left sidebar header
outline.header=Outline
# LOCALIZATION NOTE (scopes.mapScopes): Label for toggling scope mappings
scopes.mapScopes=Map Scopes
# LOCALIZATION NOTE (outline.placeholder): Placeholder text for the filter input
# element
outline.placeholder=Filter functions
@ -773,10 +591,6 @@ welcome.findInFiles=%S to find in files
# a mac we use the unicode character.
welcome.findInFiles2=%S Find in files
# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome
# panel. %S is replaced by the keyboard shortcut to search for functions.
welcome.searchFunction=%S to search for functions in file
# LOCALIZATION NOTE (welcome.allShortcuts): The label to open the modal of
# shortcuts, displayed in the welcome panel.
welcome.allShortcuts=Show all shortcuts
@ -789,18 +603,6 @@ sourceSearch.search=Search sources…
# prompt for searching for files.
sourceSearch.search2=Go to file…
# LOCALIZATION NOTE (sourceSearch.noResults2): The center pane Source Search
# message when the query did not match any of the sources.
sourceSearch.noResults2=No results found
# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip
# when the debugger will not pause on exceptions.
ignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions
# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button
# tooltip when the debugger will pause on uncaught exceptions.
pauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions
# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip
# when the debugger will pause on all exceptions.
pauseOnExceptions=Pause on all exceptions. Click to ignore exceptions
@ -818,101 +620,6 @@ wasmIsNotAvailable=Please refresh to debug this module
# viewer when there is an error loading a file
errorLoadingText3=Error loading this URI: %S
# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the
# watch expressions list to add a new item.
addWatchExpressionText=Add watch expression
# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the
# variables view popup.
addWatchExpressionButton=Watch
# LOCALIZATION NOTE (extensionsText): The text that is displayed to represent
# "moz-extension" directories in the source tree
extensionsText=Extensions
# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the
# variables pane when there are no variables to display.
emptyVariablesText=No variables to display
# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables
# pane as a header for each variable scope (e.g. "Global scope, "With scope",
# etc.).
scopeLabel=%S scope
# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch
# expressions scope. This text is displayed in the variables pane as a header for
# the watch expressions scope.
watchExpressionsScopeLabel=Watch expressions
# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text
# is added to scopeLabel and displayed in the variables pane as a header for
# the global scope.
globalScopeLabel=Global
# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is
# shown before the stack trace in an error.
variablesViewErrorStacktrace=Stack trace:
# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed
# when you have an object preview that does not show all of the elements. At the end of the list
# you see "N more..." in the web console output.
# This is a semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 number of remaining items in the object
# example: 3 more…
variablesViewMoreObjects=#1 more…;#1 more…
# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
# in the variables list on an item with an editable name.
variablesEditableNameTooltip=Double click to edit
# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed
# in the variables list on an item with an editable value.
variablesEditableValueTooltip=Click to change value
# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed
# in the variables list on an item which can be removed.
variablesCloseButtonTooltip=Click to remove
# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed
# in the variables list on a getter or setter which can be edited.
variablesEditButtonTooltip=Click to set value
# LOCALIZATION NOTE (variablesDomNodeValueTooltip): The text that is displayed
# in a tooltip on the "open in inspector" button in the the variables list for a
# DOMNode item.
variablesDomNodeValueTooltip=Click to select the node in the inspector
# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed
# in the variables list on certain variables or properties as tooltips.
# Explanations of what these represent can be found at the following links:
# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible
# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen
# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed
# It's probably best to keep these in English.
configurableTooltip=configurable
enumerableTooltip=enumerable
writableTooltip=writable
frozenTooltip=frozen
sealedTooltip=sealed
extensibleTooltip=extensible
overriddenTooltip=overridden
WebIDLTooltip=WebIDL
# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed
# in the variables list as a separator between the name and value.
variablesSeparatorLabel=:
# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed
# in the watch expressions list as a separator between the code and evaluation.
watchExpressionsSeparatorLabel2=\u0020→
# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed
# in the functions search panel as a separator between function's inferred name
# and its real name (if available).
functionSearchSeparatorLabel=
# LOCALIZATION NOTE(gotoLineModal.placeholder): The placeholder
# text displayed when the user searches for specific lines in a file
gotoLineModal.placeholder=Go to line…
@ -959,19 +666,6 @@ symbolSearch.searchModifier.caseSensitive=Case sensitive
# when searching text in a file
symbolSearch.searchModifier.wholeWord=Whole word
# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears
# as a description in the notification panel popup, when multiple debuggers are
# open in separate tabs and the user tries to resume them in the wrong order.
# The substitution parameter is the URL of the last paused window that must be
# resumed first.
resumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S
variablesViewOptimizedOut=(optimized away)
variablesViewUninitialized=(uninitialized)
variablesViewMissingArgs=(unavailable)
anonymousSourcesLabel=Anonymous sources
experimental=This is an experimental feature
# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed

Просмотреть файл

@ -54,7 +54,6 @@
#include "nsSandboxFlags.h"
#include "Link.h"
#include "HTMLLinkElement.h"
using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::dom;
@ -136,53 +135,6 @@ nsContentSink::~nsContentSink() {
}
}
bool nsContentSink::sNotifyOnTimer;
int32_t nsContentSink::sBackoffCount;
int32_t nsContentSink::sNotificationInterval;
int32_t nsContentSink::sInteractiveDeflectCount;
int32_t nsContentSink::sPerfDeflectCount;
int32_t nsContentSink::sPendingEventMode;
int32_t nsContentSink::sEventProbeRate;
int32_t nsContentSink::sInteractiveParseTime;
int32_t nsContentSink::sPerfParseTime;
int32_t nsContentSink::sInteractiveTime;
int32_t nsContentSink::sInitialPerfTime;
int32_t nsContentSink::sEnablePerfMode;
void nsContentSink::InitializeStatics() {
Preferences::AddBoolVarCache(&sNotifyOnTimer, "content.notify.ontimer", true);
// -1 means never.
Preferences::AddIntVarCache(&sBackoffCount, "content.notify.backoffcount",
-1);
// The gNotificationInterval has a dramatic effect on how long it
// takes to initially display content for slow connections.
// The current value provides good
// incremental display of content without causing an increase
// in page load time. If this value is set below 1/10 of second
// it starts to impact page load performance.
// see bugzilla bug 72138 for more info.
Preferences::AddIntVarCache(&sNotificationInterval, "content.notify.interval",
120000);
Preferences::AddIntVarCache(&sInteractiveDeflectCount,
"content.sink.interactive_deflect_count", 0);
Preferences::AddIntVarCache(&sPerfDeflectCount,
"content.sink.perf_deflect_count", 200);
Preferences::AddIntVarCache(&sPendingEventMode,
"content.sink.pending_event_mode", 1);
Preferences::AddIntVarCache(&sEventProbeRate, "content.sink.event_probe_rate",
1);
Preferences::AddIntVarCache(&sInteractiveParseTime,
"content.sink.interactive_parse_time", 3000);
Preferences::AddIntVarCache(&sPerfParseTime, "content.sink.perf_parse_time",
360000);
Preferences::AddIntVarCache(&sInteractiveTime,
"content.sink.interactive_time", 750000);
Preferences::AddIntVarCache(&sInitialPerfTime,
"content.sink.initial_perf_time", 2000000);
Preferences::AddIntVarCache(&sEnablePerfMode, "content.sink.enable_perf_mode",
0);
}
nsresult nsContentSink::Init(Document* aDoc, nsIURI* aURI,
nsISupports* aContainer, nsIChannel* aChannel) {
MOZ_ASSERT(aDoc, "null ptr");
@ -213,10 +165,10 @@ nsresult nsContentSink::Init(Document* aDoc, nsIURI* aURI,
mNodeInfoManager = aDoc->NodeInfoManager();
mBackoffCount = sBackoffCount;
mBackoffCount = StaticPrefs::content_notify_backoffcount();
if (sEnablePerfMode != 0) {
mDynamicLowerValue = sEnablePerfMode == 1;
if (StaticPrefs::content_sink_enable_perf_mode() != 0) {
mDynamicLowerValue = StaticPrefs::content_sink_enable_perf_mode() == 1;
FavorPerformanceHint(!mDynamicLowerValue, 0);
}
@ -1271,8 +1223,8 @@ nsContentSink::Notify(nsITimer* timer) {
}
bool nsContentSink::IsTimeToNotify() {
if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
mInMonolithicContainer) {
if (!StaticPrefs::content_notify_ontimer() || !mLayoutStarted ||
!mBackoffCount || mInMonolithicContainer) {
return false;
}
@ -1302,7 +1254,7 @@ nsresult nsContentSink::WillInterruptImpl() {
#ifndef SINK_NO_INCREMENTAL
if (WaitForPendingSheets()) {
mDeferredFlushTags = true;
} else if (sNotifyOnTimer && mLayoutStarted) {
} else if (StaticPrefs::content_notify_ontimer() && mLayoutStarted) {
if (mBackoffCount && !mInMonolithicContainer) {
int64_t now = PR_Now();
int64_t interval = GetNotificationInterval();
@ -1379,8 +1331,9 @@ nsresult nsContentSink::DidProcessATokenImpl() {
++mDeflectedCount;
// Check if there's a pending event
if (sPendingEventMode != 0 && !mHasPendingEvent &&
(mDeflectedCount % sEventProbeRate) == 0) {
if (StaticPrefs::content_sink_pending_event_mode() != 0 &&
!mHasPendingEvent &&
(mDeflectedCount % StaticPrefs::content_sink_event_probe_rate()) == 0) {
nsViewManager* vm = presShell->GetViewManager();
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
nsCOMPtr<nsIWidget> widget;
@ -1388,14 +1341,16 @@ nsresult nsContentSink::DidProcessATokenImpl() {
mHasPendingEvent = widget && widget->HasPendingInputEvent();
}
if (mHasPendingEvent && sPendingEventMode == 2) {
if (mHasPendingEvent && StaticPrefs::content_sink_pending_event_mode() == 2) {
return NS_ERROR_HTMLPARSER_INTERRUPTED;
}
// Have we processed enough tokens to check time?
if (!mHasPendingEvent &&
mDeflectedCount < uint32_t(mDynamicLowerValue ? sInteractiveDeflectCount
: sPerfDeflectCount)) {
mDeflectedCount <
uint32_t(mDynamicLowerValue
? StaticPrefs::content_sink_interactive_deflect_count()
: StaticPrefs::content_sink_perf_deflect_count())) {
return NS_OK;
}
@ -1522,7 +1477,7 @@ nsresult nsContentSink::WillParseImpl(void) {
uint32_t currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
if (sEnablePerfMode == 0) {
if (StaticPrefs::content_sink_enable_perf_mode() == 0) {
nsViewManager* vm = presShell->GetViewManager();
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
uint32_t lastEventTime;
@ -1530,8 +1485,10 @@ nsresult nsContentSink::WillParseImpl(void) {
bool newDynLower =
mDocument->IsInBackgroundWindow() ||
((currentTime - mBeginLoadTime) > uint32_t(sInitialPerfTime) &&
(currentTime - lastEventTime) < uint32_t(sInteractiveTime));
((currentTime - mBeginLoadTime) >
StaticPrefs::content_sink_initial_perf_time() &&
(currentTime - lastEventTime) <
StaticPrefs::content_sink_interactive_time());
if (mDynamicLowerValue != newDynLower) {
FavorPerformanceHint(!newDynLower, 0);
@ -1543,8 +1500,9 @@ nsresult nsContentSink::WillParseImpl(void) {
mHasPendingEvent = false;
mCurrentParseEndTime =
currentTime +
(mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
currentTime + (mDynamicLowerValue
? StaticPrefs::content_sink_interactive_parse_time()
: StaticPrefs::content_sink_perf_parse_time());
return NS_OK;
}

Просмотреть файл

@ -27,6 +27,7 @@
#include "mozilla/Logging.h"
#include "nsCycleCollectionParticipant.h"
#include "nsThreadUtils.h"
#include "mozilla/StaticPrefs_content.h"
class nsIURI;
class nsIChannel;
@ -117,8 +118,6 @@ class nsContentSink : public nsICSSLoaderObserver,
bool LinkContextIsOurDocument(const nsAString& aAnchor);
bool Decode5987Format(nsAString& aEncoded);
static void InitializeStatics();
protected:
nsContentSink();
virtual ~nsContentSink();
@ -256,7 +255,7 @@ class nsContentSink : public nsICSSLoaderObserver,
return 1000;
}
return sNotificationInterval;
return mozilla::StaticPrefs::content_notify_interval();
}
virtual nsresult FlushTags() = 0;
@ -267,7 +266,9 @@ class nsContentSink : public nsICSSLoaderObserver,
void DoProcessLinkHeader();
void StopDeflecting() { mDeflectedCount = sPerfDeflectCount; }
void StopDeflecting() {
mDeflectedCount = mozilla::StaticPrefs::content_sink_perf_deflect_count();
}
protected:
RefPtr<Document> mDocument;
@ -335,31 +336,6 @@ class nsContentSink : public nsICSSLoaderObserver,
nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
mProcessLinkHeaderEvent;
// Do we notify based on time?
static bool sNotifyOnTimer;
// Back off timer notification after count.
static int32_t sBackoffCount;
// Notification interval in microseconds
static int32_t sNotificationInterval;
// How many times to deflect in interactive/perf modes
static int32_t sInteractiveDeflectCount;
static int32_t sPerfDeflectCount;
// 0 = don't check for pending events
// 1 = don't deflect if there are pending events
// 2 = bail if there are pending events
static int32_t sPendingEventMode;
// How often to probe for pending events. 1=every token
static int32_t sEventProbeRate;
// How long to stay off the event loop in interactive/perf modes
static int32_t sInteractiveParseTime;
static int32_t sPerfParseTime;
// How long to be in interactive mode after an event
static int32_t sInteractiveTime;
// How long to stay in perf mode after initial loading
static int32_t sInitialPerfTime;
// Should we switch between perf-mode and interactive-mode
static int32_t sEnablePerfMode;
};
#endif // _nsContentSink_h_

Просмотреть файл

@ -41,6 +41,7 @@
#include "mozilla/dom/Comment.h"
#include "mozilla/dom/DocumentType.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/ProcessingInstruction.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/Text.h"
@ -1727,9 +1728,8 @@ nsCOMPtr<nsINode> nsHTMLCopyEncoder::GetChildAt(nsINode* aParent,
}
bool nsHTMLCopyEncoder::IsMozBR(Element* aElement) {
return aElement->IsHTMLElement(nsGkAtoms::br) &&
aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"), eIgnoreCase);
HTMLBRElement* brElement = HTMLBRElement::FromNodeOrNull(aElement);
return brElement && brElement->IsPaddingForEmptyLastLine();
}
nsresult nsHTMLCopyEncoder::GetNodeLocation(nsINode* inChild,

Просмотреть файл

@ -3736,7 +3736,18 @@ double nsGlobalWindowOuter::GetDevicePixelRatioOuter(CallerType aCallerType) {
}
if (nsContentUtils::ResistFingerprinting(aCallerType)) {
return 1.0;
// Spoofing the DevicePixelRatio causes blurriness in some situations
// on HiDPI displays. pdf.js is a non-system caller; but it can't
// expose the fingerprintable information, so we can safely disable
// spoofing in this situation. It doesn't address the issue for
// web-rendered content (including pdf.js instances on the web.)
// In the future we hope to have a better solution to fix all HiDPI
// blurriness...
nsAutoCString origin;
nsresult rv = this->GetPrincipal()->GetOrigin(origin);
if (NS_FAILED(rv) || origin != NS_LITERAL_CSTRING("resource://pdf.js")) {
return 1.0;
}
}
float overrideDPPX = presContext->GetOverrideDPPX();

Просмотреть файл

@ -63,7 +63,6 @@ bool nsHTMLContentSerializer::SerializeHTMLAttributes(
nsresult rv;
nsAutoString valueStr;
NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
for (int32_t index = 0; index < count; index++) {
const nsAttrName* name = aElement->GetAttrNameAt(index);
@ -78,16 +77,6 @@ bool nsHTMLContentSerializer::SerializeHTMLAttributes(
}
aElement->GetAttr(namespaceID, attrName, valueStr);
//
// Filter out special case of <br type="_moz"> or <br _moz*>,
// used by the editor. Bug 16988. Yuck.
//
if (aTagName == nsGkAtoms::br && aNamespace == kNameSpaceID_XHTML &&
attrName == nsGkAtoms::type && namespaceID == kNameSpaceID_None &&
StringBeginsWith(valueStr, _mozStr)) {
continue;
}
if (mIsCopying && mIsFirstChildOfOL && aTagName == nsGkAtoms::li &&
aNamespace == kNameSpaceID_XHTML && attrName == nsGkAtoms::value &&
namespaceID == kNameSpaceID_None) {

Просмотреть файл

@ -22,6 +22,7 @@
#include "mozilla/EditorUtils.h"
#include "mozilla/dom/CharacterData.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/Text.h"
#include "mozilla/Preferences.h"
#include "mozilla/BinarySearch.h"
@ -1039,9 +1040,12 @@ nsresult nsPlainTextSerializer::DoAddLeaf(nsAtom* aTag) {
if (aTag == nsGkAtoms::br) {
// Another egregious editor workaround, see bug 38194:
// ignore the bogus br tags that the editor sticks here and there.
nsAutoString tagAttr;
if (NS_FAILED(GetAttributeValue(nsGkAtoms::type, tagAttr)) ||
!tagAttr.EqualsLiteral("_moz")) {
// FYI: `brElement` may be `nullptr` if the element is <br> element
// of non-HTML element.
// XXX Do we need to call `EnsureVerticalSpace()` when the <br> element
// is not an HTML element?
HTMLBRElement* brElement = HTMLBRElement::FromNodeOrNull(mElement);
if (!brElement || !brElement->IsPaddingForEmptyLastLine()) {
EnsureVerticalSpace(mEmptyLines + 1);
}
} else if (aTag == nsGkAtoms::hr &&

Просмотреть файл

@ -208,8 +208,6 @@ bool nsXHTMLContentSerializer::SerializeAttributes(
PushNameSpaceDecl(aTagPrefix, aTagNamespaceURI, aOriginalElement);
}
NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
count = aElement->GetAttrCount();
// Now serialize each of the attributes
@ -252,15 +250,6 @@ bool nsXHTMLContentSerializer::SerializeAttributes(
bool isJS = false;
if (kNameSpaceID_XHTML == contentNamespaceID) {
//
// Filter out special case of <br type="_moz"> or <br _moz*>,
// used by the editor. Bug 16988. Yuck.
//
if (namespaceID == kNameSpaceID_None && aTagName == nsGkAtoms::br &&
attrName == nsGkAtoms::type && StringBeginsWith(valueStr, _mozStr)) {
continue;
}
if (mIsCopying && mIsFirstChildOfOL && (aTagName == nsGkAtoms::li) &&
(attrName == nsGkAtoms::value)) {
// This is handled separately in SerializeLIValueAttribute()

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/HTMLUnknownElement.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/Text.h"
@ -483,20 +484,17 @@ nsresult ContentEventHandler::QueryContentRect(
return NS_OK;
}
// Editor places a bogus BR node under its root content if the editor doesn't
// have any text. This happens even for single line editors.
// Editor places a padding <br> element under its root content if the editor
// doesn't have any text. This happens even for single line editors.
// When we get text content and when we change the selection,
// we don't want to include the bogus BRs at the end.
// we don't want to include the padding <br> elements at the end.
static bool IsContentBR(nsIContent* aContent) {
return aContent->IsHTMLElement(nsGkAtoms::br) &&
!aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::moz, eIgnoreCase) &&
!aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::mozeditorbogusnode,
nsGkAtoms::_true, eIgnoreCase);
HTMLBRElement* brElement = HTMLBRElement::FromNode(aContent);
return brElement && !brElement->IsPaddingForEmptyLastLine() &&
!brElement->IsPaddingForEmptyEditor();
}
static bool IsMozBR(nsIContent* aContent) {
static bool IsPaddingBR(nsIContent* aContent) {
return aContent->IsHTMLElement(nsGkAtoms::br) && !IsContentBR(aContent);
}
@ -1484,7 +1482,7 @@ ContentEventHandler::GetFirstFrameInRangeForTextRect(
// If the element node causes a line break before it, it's the first
// node causing text.
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
IsMozBR(node->AsContent())) {
IsPaddingBR(node->AsContent())) {
nodePosition.Set(node, 0);
}
}
@ -1571,7 +1569,7 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange) {
}
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
IsMozBR(node->AsContent())) {
IsPaddingBR(node->AsContent())) {
nodePosition.Set(node, 0);
break;
}
@ -1623,7 +1621,7 @@ ContentEventHandler::GetLineBreakerRectBefore(nsIFrame* aFrame) {
// open tag causes a line break or moz-<br> for computing empty last line's
// rect.
MOZ_ASSERT(ShouldBreakLineBefore(aFrame->GetContent(), mRootContent) ||
IsMozBR(aFrame->GetContent()));
IsPaddingBR(aFrame->GetContent()));
nsIFrame* frameForFontMetrics = aFrame;
@ -1883,7 +1881,7 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
// it represents empty line at the last of current block. Therefore,
// we need to compute its rect too.
else if (ShouldBreakLineBefore(firstContent, mRootContent) ||
IsMozBR(firstContent)) {
IsPaddingBR(firstContent)) {
nsRect brRect;
// If the frame is not a <br> frame, we need to compute the caret rect
// with last character's rect before firstContent if there is.

Просмотреть файл

@ -246,9 +246,12 @@ EVENT(toggle, eToggle, EventNameType_HTML, eBasicEventClass)
EVENT(volumechange, eVolumeChange, EventNameType_HTML, eBasicEventClass)
EVENT(waiting, eWaiting, EventNameType_HTML, eBasicEventClass)
EVENT(wheel, eWheel, EventNameType_All, eWheelEventClass)
EVENT(copy, eCopy, EventNameType_HTMLXUL, eClipboardEventClass)
EVENT(cut, eCut, EventNameType_HTMLXUL, eClipboardEventClass)
EVENT(paste, ePaste, EventNameType_HTMLXUL, eClipboardEventClass)
EVENT(copy, eCopy, EventNameType_HTMLXUL | EventNameType_SVGGraphic,
eClipboardEventClass)
EVENT(cut, eCut, EventNameType_HTMLXUL | EventNameType_SVGGraphic,
eClipboardEventClass)
EVENT(paste, ePaste, EventNameType_HTMLXUL | EventNameType_SVGGraphic,
eClipboardEventClass)
// Gecko-specific extensions that apply to elements
EVENT(beforescriptexecute, eBeforeScriptExecute, EventNameType_HTMLXUL,
eBasicEventClass)

Просмотреть файл

@ -186,7 +186,6 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
IMEContentObserver::IMEContentObserver()
: mESM(nullptr),
mIMENotificationRequests(nullptr),
mPreAttrChangeLength(0),
mSuppressNotifications(0),
mPreCharacterDataChangeLength(-1),
mSendingNotification(NOTIFY_IME_OF_NOTHING),
@ -1085,51 +1084,6 @@ void IMEContentObserver::ContentRemoved(nsIContent* aChild,
MaybeNotifyIMEOfTextChange(data);
}
void IMEContentObserver::AttributeWillChange(dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType) {
if (!NeedsTextChangeNotification()) {
return;
}
mPreAttrChangeLength =
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
}
void IMEContentObserver::AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) {
if (!NeedsTextChangeNotification()) {
return;
}
mEndOfAddedTextCache.Clear();
mStartOfRemovingTextRangeCache.Clear();
uint32_t postAttrChangeLength =
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
if (postAttrChangeLength == mPreAttrChangeLength) {
return;
}
// First, compute text range which were added during a document change.
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
// Then, compute the new text changed caused by this attribute change.
uint32_t start;
nsresult rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(mRootContent, 0), NodePositionBefore(aElement, 0),
mRootContent, &start, LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
TextChangeData data(
start, start + mPreAttrChangeLength, start + postAttrChangeLength,
IsEditorHandlingEventForComposition(), IsEditorComposing());
MaybeNotifyIMEOfTextChange(data);
}
void IMEContentObserver::ClearAddedNodesDuringDocumentChange() {
mFirstAddedContainer = mLastAddedContainer = nullptr;
mFirstAddedContent = mLastAddedContent = nullptr;

Просмотреть файл

@ -57,8 +57,6 @@ class IMEContentObserver final : public nsStubMutationObserver,
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIREFLOWOBSERVER
// nsIScrollObserver
@ -484,7 +482,6 @@ class IMEContentObserver final : public nsStubMutationObserver,
EventStateManager* mESM;
const IMENotificationRequests* mIMENotificationRequests;
uint32_t mPreAttrChangeLength;
uint32_t mSuppressNotifications;
int64_t mPreCharacterDataChangeLength;

Просмотреть файл

@ -14,10 +14,29 @@
namespace mozilla {
namespace dom {
#define BR_ELEMENT_FLAG_BIT(n_) \
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
// BR element specific bits
enum {
// NS_PADDING_FOR_EMPTY_EDITOR is set if the <br> element is created by
// editor for placing caret at proper position in empty editor.
NS_PADDING_FOR_EMPTY_EDITOR = BR_ELEMENT_FLAG_BIT(0),
// NS_PADDING_FOR_EMPTY_LAST_LINE is set if the <br> element is created by
// editor for placing caret at proper position for making empty last line
// in a block or <textarea> element visible.
NS_PADDING_FOR_EMPTY_LAST_LINE = BR_ELEMENT_FLAG_BIT(1),
};
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
class HTMLBRElement final : public nsGenericHTMLElement {
public:
explicit HTMLBRElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLBRElement, br)
virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
@ -38,6 +57,13 @@ class HTMLBRElement final : public nsGenericHTMLElement {
virtual JSObject* WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
bool IsPaddingForEmptyEditor() const {
return HasFlag(NS_PADDING_FOR_EMPTY_EDITOR);
}
bool IsPaddingForEmptyLastLine() const {
return HasFlag(NS_PADDING_FOR_EMPTY_LAST_LINE);
}
private:
virtual ~HTMLBRElement();

Просмотреть файл

@ -22,3 +22,16 @@ partial interface HTMLBRElement {
attribute DOMString clear;
};
// Mozilla extensions
partial interface HTMLBRElement {
// Set to true if the <br> element is created by editor for placing caret
// at proper position in empty editor.
[ChromeOnly]
readonly attribute boolean isPaddingForEmptyEditor;
// Set to true if the <br> element is created by editor for placing caret
// at proper position making last empty line in a block element in HTML
// editor or <textarea> element visible.
[ChromeOnly]
readonly attribute boolean isPaddingForEmptyLastLine;
};

Просмотреть файл

@ -348,9 +348,10 @@ enum class EditAction {
// eHidePassword indicates that editor hides password with mask characters.
eHidePassword,
// eCreateBogusNode indicates that editor wants to create a bogus node after
// the editor is modified, asynchronously.
eCreateBogusNode,
// eCreatePaddingBRElementForEmptyEditor indicates that editor wants to
// create a padding <br> element for empty editor after it modifies its
// content.
eCreatePaddingBRElementForEmptyEditor,
};
// This is int32_t instead of int16_t because nsIInlineSpellChecker.idl's
@ -469,8 +470,9 @@ enum class EditSubAction : int32_t {
eDecreaseZIndex,
eIncreaseZIndex,
// eCreateBogusNode indicates to create a bogus <br> node.
eCreateBogusNode,
// eCreatePaddingBRElementForEmptyEditor indicates to create a padding <br>
// element for empty editor.
eCreatePaddingBRElementForEmptyEditor,
};
inline EditorInputType ToInputType(EditAction aEditAction) {

Просмотреть файл

@ -1450,6 +1450,83 @@ nsresult EditorBase::InsertNodeWithTransaction(
return rv;
}
EditorDOMPoint EditorBase::PrepareToInsertBRElement(
const EditorDOMPoint& aPointToInsert) {
MOZ_ASSERT(IsEditActionDataAvailable());
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return EditorDOMPoint();
}
if (!aPointToInsert.IsInTextNode()) {
return aPointToInsert;
}
if (aPointToInsert.IsStartOfContainer()) {
// Insert before the text node.
EditorDOMPoint pointInContainer(aPointToInsert.GetContainer());
NS_WARNING_ASSERTION(pointInContainer.IsSet(),
"Failed to climb up the DOM tree from text node");
return pointInContainer;
}
if (aPointToInsert.IsEndOfContainer()) {
// Insert after the text node.
EditorDOMPoint pointInContainer(aPointToInsert.GetContainer());
if (NS_WARN_IF(!pointInContainer.IsSet())) {
return pointInContainer;
}
DebugOnly<bool> advanced = pointInContainer.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset to after the text node");
return pointInContainer;
}
MOZ_DIAGNOSTIC_ASSERT(aPointToInsert.IsSetAndValid());
// Unfortunately, we need to split the text node at the offset.
ErrorResult error;
nsCOMPtr<nsIContent> newLeftNode =
SplitNodeWithTransaction(aPointToInsert, error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
return EditorDOMPoint();
}
Unused << newLeftNode;
// Insert new <br> before the right node.
EditorDOMPoint pointInContainer(aPointToInsert.GetContainer());
NS_WARNING_ASSERTION(pointInContainer.IsSet(),
"Failed to split the text node");
return pointInContainer;
}
CreateElementResult
EditorBase::InsertPaddingBRElementForEmptyLastLineWithTransaction(
const EditorDOMPoint& aPointToInsert) {
MOZ_ASSERT(IsEditActionDataAvailable());
EditorDOMPoint pointToInsert = PrepareToInsertBRElement(aPointToInsert);
if (NS_WARN_IF(!pointToInsert.IsSet())) {
return CreateElementResult(NS_ERROR_FAILURE);
}
RefPtr<Element> newBRElement = CreateHTMLContent(nsGkAtoms::br);
if (NS_WARN_IF(!newBRElement)) {
return CreateElementResult(NS_ERROR_FAILURE);
}
newBRElement->SetFlags(NS_PADDING_FOR_EMPTY_LAST_LINE);
nsresult rv = InsertNodeWithTransaction(*newBRElement, pointToInsert);
if (NS_WARN_IF(Destroyed())) {
return CreateElementResult(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return CreateElementResult(rv);
}
return CreateElementResult(newBRElement.forget());
}
NS_IMETHODIMP
EditorBase::SplitNode(nsINode* aNode, int32_t aOffset, nsINode** aNewLeftNode) {
if (NS_WARN_IF(!aNode)) {
@ -2520,9 +2597,10 @@ EditorRawDOMPoint EditorBase::FindBetterInsertionPoint(
return EditorRawDOMPoint(aPoint.GetContainer()->GetFirstChild(), 0);
}
// In some other cases, aNode is the anonymous DIV, and offset points to the
// terminating mozBR. In that case, we'll adjust aInOutNode and
// aInOutOffset to the preceding text node, if any.
// In some other cases, aNode is the anonymous DIV, and offset points to
// the terminating padding <br> element for empty last line. In that case,
// we'll adjust aInOutNode and aInOutOffset to the preceding text node,
// if any.
if (!aPoint.IsStartOfContainer()) {
if (AsHTMLEditor()) {
// Fall back to a slow path that uses GetChildAt_Deprecated() for
@ -2551,10 +2629,10 @@ EditorRawDOMPoint EditorBase::FindBetterInsertionPoint(
}
}
// Sometimes, aNode is the mozBR element itself. In that case, we'll adjust
// the insertion point to the previous text node, if one exists, or to the
// parent anonymous DIV.
if (TextEditUtils::IsMozBR(aPoint.GetContainer()) &&
// Sometimes, aNode is the padding <br> element itself. In that case, we'll
// adjust the insertion point to the previous text node, if one exists, or
// to the parent anonymous DIV.
if (EditorBase::IsPaddingBRElementForEmptyLastLine(*aPoint.GetContainer()) &&
aPoint.IsStartOfContainer()) {
nsIContent* previousSibling = aPoint.GetContainer()->GetPreviousSibling();
if (previousSibling && previousSibling->IsText()) {
@ -2603,9 +2681,9 @@ nsresult EditorBase::InsertTextWithTransaction(
return NS_ERROR_INVALID_ARG;
}
// In some cases, the node may be the anonymous div elemnt or a mozBR
// element. Let's try to look for better insertion point in the nearest
// text node if there is.
// In some cases, the node may be the anonymous div element or a padding
// <br> element for empty last line. Let's try to look for better insertion
// point in the nearest text node if there is.
EditorDOMPoint pointToInsert = FindBetterInsertionPoint(aPointToInsert);
// If a neighboring text node already exists, use that

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/TransactionManager.h" // for TransactionManager
#include "mozilla/WeakPtr.h" // for WeakPtr
#include "mozilla/dom/DataTransfer.h" // for dom::DataTransfer
#include "mozilla/dom/HTMLBRElement.h" // for dom::HTMLBRElement
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/Text.h"
#include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr
@ -90,6 +91,10 @@ class TextServicesDocument;
class TypeInState;
class WSRunObject;
template <typename NodeType>
class CreateNodeResultBase;
typedef CreateNodeResultBase<dom::Element> CreateElementResult;
namespace dom {
class DataTransfer;
class DragEvent;
@ -101,9 +106,6 @@ namespace widget {
struct IMEState;
} // namespace widget
#define kMOZEditorBogusNodeAttrAtom nsGkAtoms::mozeditorbogusnode
#define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE")
/**
* SplitAtEdges is for EditorBase::SplitNodeDeepWithTransaction(),
* HTMLEditor::InsertNodeAtPoint()
@ -707,7 +709,7 @@ class EditorBase : public nsIEditor,
case EditSubAction::eUndo:
case EditSubAction::eRedo:
case EditSubAction::eComputeTextToOutput:
case EditSubAction::eCreateBogusNode:
case EditSubAction::eCreatePaddingBRElementForEmptyEditor:
case EditSubAction::eNone:
MOZ_ASSERT(aDirection == eNone);
mDirectionOfTopLevelEditSubAction = eNone;
@ -966,6 +968,18 @@ class EditorBase : public nsIEditor,
MOZ_CAN_RUN_SCRIPT nsresult InsertNodeWithTransaction(
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
/**
* InsertPaddingBRElementForEmptyLastLineWithTransaction() creates a padding
* <br> element with setting flags to NS_PADDING_FOR_EMPTY_LAST_LINE and
* inserts it around aPointToInsert.
*
* @param aPointToInsert The DOM point where should be <br> node inserted
* before.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE CreateElementResult
InsertPaddingBRElementForEmptyLastLineWithTransaction(
const EditorDOMPoint& aPointToInsert);
/**
* ReplaceContainerWithTransaction() creates new element whose name is
* aTagName, moves all children in aOldContainer to the new element, then,
@ -1619,8 +1633,8 @@ class EditorBase : public nsIEditor,
return false;
}
if (!aNode->IsContent() || IsMozEditorBogusNode(aNode) ||
!IsModifiableNode(*aNode)) {
if (!aNode->IsContent() || !IsModifiableNode(*aNode) ||
EditorBase::IsPaddingBRElementForEmptyEditor(*aNode)) {
return false;
}
@ -1638,26 +1652,34 @@ class EditorBase : public nsIEditor,
}
/**
* Returns true if aNode is a usual element node (not bogus node) or
* a text node. In other words, returns true if aNode is a usual element
* node or visible data node.
* Returns true if aNode is a usual element node (not padding <br> element
* for empty editor) or a text node. In other words, returns true if aNode
* is a usual element node or visible data node.
*/
bool IsElementOrText(const nsINode& aNode) const {
if (!aNode.IsContent() || IsMozEditorBogusNode(&aNode)) {
return false;
if (aNode.IsText()) {
return true;
}
return aNode.NodeType() == nsINode::ELEMENT_NODE ||
aNode.NodeType() == nsINode::TEXT_NODE;
return aNode.IsElement() &&
!EditorBase::IsPaddingBRElementForEmptyEditor(aNode);
}
/**
* Returns true if aNode is a MozEditorBogus node.
* Returns true if aNode is a <br> element and it's marked as padding for
* empty editor.
*/
bool IsMozEditorBogusNode(const nsINode* aNode) const {
return aNode && aNode->IsElement() &&
aNode->AsElement()->AttrValueIs(
kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
kMOZEditorBogusNodeValue, eCaseMatters);
static bool IsPaddingBRElementForEmptyEditor(const nsINode& aNode) {
const dom::HTMLBRElement* brElement = dom::HTMLBRElement::FromNode(&aNode);
return brElement && brElement->IsPaddingForEmptyEditor();
}
/**
* Returns true if aNode is a <br> element and it's marked as padding for
* empty last line.
*/
static bool IsPaddingBRElementForEmptyLastLine(const nsINode& aNode) {
const dom::HTMLBRElement* brElement = dom::HTMLBRElement::FromNode(&aNode);
return brElement && brElement->IsPaddingForEmptyLastLine();
}
/**
@ -2075,6 +2097,18 @@ class EditorBase : public nsIEditor,
MOZ_CAN_RUN_SCRIPT
void NotifyEditorObservers(NotificationForEditorObservers aNotification);
/**
* PrepareToInsertBRElement() returns a point where new <br> element should
* be inserted. If aPointToInsert points middle of a text node, this method
* splits the text node and returns the point before right node.
*
* @param aPointToInsert Candidate point to insert new <br> element.
* @return Computed point to insert new <br> element.
* If something failed, this is unset.
*/
MOZ_CAN_RUN_SCRIPT EditorDOMPoint
PrepareToInsertBRElement(const EditorDOMPoint& aPointToInsert);
private:
nsCOMPtr<nsISelectionController> mSelectionController;
RefPtr<Document> mDocument;

Просмотреть файл

@ -528,7 +528,7 @@ nsresult HTMLEditor::SetPositionToAbsolute(Element& aElement) {
nsINode* parentNode = aElement.GetParentNode();
if (parentNode->GetChildCount() == 1) {
RefPtr<Element> newBrElement =
InsertBrElementWithTransaction(EditorDOMPoint(parentNode, 0));
InsertBRElementWithTransaction(EditorDOMPoint(parentNode, 0));
if (NS_WARN_IF(!newBrElement)) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -20,17 +20,18 @@
#include "mozilla/HTMLEditor.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Move.h"
#include "mozilla/mozalloc.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/Preferences.h"
#include "mozilla/RangeUtils.h"
#include "mozilla/TextComposition.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/RangeBinding.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/StaticRange.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/RangeBinding.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/mozalloc.h"
#include "nsAString.h"
#include "nsAlgorithm.h"
#include "nsCRT.h"
@ -69,9 +70,6 @@ namespace mozilla {
using namespace dom;
// const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
// const static char* kMOZEditorBogusNodeValue="TRUE";
enum { kLonely = 0, kPrevSib = 1, kNextSib = 2, kBothSibs = 3 };
/********************************************************
@ -455,7 +453,7 @@ nsresult HTMLEditRules::AfterEditInner(EditSubAction aEditSubAction,
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to normalize Selection");
if (aEditSubAction == EditSubAction::eReplaceHeadWithHTMLSource ||
aEditSubAction == EditSubAction::eCreateBogusNode) {
aEditSubAction == EditSubAction::eCreatePaddingBRElementForEmptyEditor) {
return NS_OK;
}
@ -631,7 +629,10 @@ nsresult HTMLEditRules::AfterEditInner(EditSubAction aEditSubAction,
}
// detect empty doc
rv = CreateBogusNodeIfNeeded();
// XXX Need to investigate when the padding <br> element is removed because
// I don't see the <br> element with testing manually. If it won't be
// used, we can get rid of this cost.
rv = CreatePaddingBRElementForEmptyEditorIfNeeded();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -804,7 +805,9 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
}
}
bool HTMLEditRules::DocumentIsEmpty() { return !!mBogusNode; }
bool HTMLEditRules::DocumentIsEmpty() const {
return !!mPaddingBRElementForEmptyEditor;
}
nsresult HTMLEditRules::GetListState(bool* aMixed, bool* aOL, bool* aUL,
bool* aDL) {
@ -1237,16 +1240,17 @@ nsresult HTMLEditRules::WillInsert(bool* aCancel) {
return rv;
}
// Adjust selection to prevent insertion after a moz-BR. This next only
// works for collapsed selections right now, because selection is a pain to
// work with when not collapsed. (no good way to extend start or end of
// selection), so we ignore those types of selections.
// Adjust selection to prevent insertion after a padding <br> element for
// empty last line. This next only works for collapsed selections right
// now, because selection is a pain to work with when not collapsed. (no
// good way to extend start or end of selection), so we ignore those types
// of selections.
if (!SelectionRefPtr()->IsCollapsed()) {
return NS_OK;
}
// If we are after a mozBR in the same block, then move selection to be
// before it
// If we are after a padding <br> element for empty last line in the same
// block, then move selection to be before it
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
@ -1261,15 +1265,16 @@ nsresult HTMLEditRules::WillInsert(bool* aCancel) {
// Get prior node
nsCOMPtr<nsIContent> priorNode =
HTMLEditorRef().GetPreviousEditableHTMLNode(atStartOfSelection);
if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
if (priorNode && EditorBase::IsPaddingBRElementForEmptyLastLine(*priorNode)) {
RefPtr<Element> block1 =
HTMLEditorRef().GetBlock(*atStartOfSelection.GetContainer());
RefPtr<Element> block2 = HTMLEditorRef().GetBlockNodeParent(priorNode);
if (block1 && block1 == block2) {
// If we are here then the selection is right after a mozBR that is in
// the same block as the selection. We need to move the selection start
// to be before the mozBR.
// If we are here then the selection is right after a padding <br>
// element for empty last line that is in the same block as the
// selection. We need to move the selection start to be before the
// padding <br> element.
EditorRawDOMPoint point(priorNode);
ErrorResult error;
SelectionRefPtr()->Collapse(point, error);
@ -1474,7 +1479,7 @@ nsresult HTMLEditRules::WillInsertText(EditSubAction aEditSubAction,
// is it a return?
if (subStr.Equals(newlineStr)) {
RefPtr<Element> brElement = MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(
.InsertBRElementWithTransaction(
currentPoint, nsIEditor::eNone);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
@ -1641,19 +1646,21 @@ nsresult HTMLEditRules::WillInsertText(EditSubAction aEditSubAction,
nsresult HTMLEditRules::WillLoadHTML() {
MOZ_ASSERT(IsEditorDataAvailable());
// Delete mBogusNode if it exists. If we really need one,
// it will be added during post-processing in AfterEditInner().
if (mBogusNode) {
// A mutation event listener may recreate bogus node again during the
// call of DeleteNodeWithTransaction(). So, move it first.
nsCOMPtr<nsINode> bogusNode(std::move(mBogusNode));
DebugOnly<nsresult> rv =
MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*bogusNode);
// Delete mPaddingBRElementForEmptyEditor if it exists. If we really
// need one, it will be added during post-processing in AfterEditInner().
if (mPaddingBRElementForEmptyEditor) {
// A mutation event listener may recreate padding <br> element for empty
// editor again during the call of DeleteNodeWithTransaction(). So, move
// it first.
RefPtr<HTMLBRElement> paddingBRElement(
std::move(mPaddingBRElementForEmptyEditor));
DebugOnly<nsresult> rv = MOZ_KnownLive(HTMLEditorRef())
.DeleteNodeWithTransaction(*paddingBRElement);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove the bogus node");
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to remove the padding <br> element");
}
return NS_OK;
@ -1849,7 +1856,7 @@ EditActionResult HTMLEditRules::WillInsertParagraphSeparator() {
endOfBlockParent.SetToEndOf(blockParent);
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(endOfBlockParent);
.InsertBRElementWithTransaction(endOfBlockParent);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
@ -1937,7 +1944,7 @@ nsresult HTMLEditRules::InsertBRElement(const EditorDOMPoint& aPointToBreak) {
RefPtr<Element> brElement;
if (IsPlaintextEditor()) {
brElement = MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(aPointToBreak);
.InsertBRElementWithTransaction(aPointToBreak);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -2144,7 +2151,7 @@ EditActionResult HTMLEditRules::SplitMailCites() {
endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
RefPtr<Element> invisibleBrElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(endOfPreviousNodeOfSplitPoint);
.InsertBRElementWithTransaction(endOfPreviousNodeOfSplitPoint);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
@ -2159,7 +2166,7 @@ EditActionResult HTMLEditRules::SplitMailCites() {
EditorDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(pointToInsertBrNode);
.InsertBRElementWithTransaction(pointToInsertBrNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
@ -2210,7 +2217,7 @@ EditActionResult HTMLEditRules::SplitMailCites() {
// In case we're at the very end.
wsType == WSType::thisBlock) {
brElement = MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(pointToCreateNewBrNode);
.InsertBRElementWithTransaction(pointToCreateNewBrNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
}
@ -2283,8 +2290,9 @@ nsresult HTMLEditRules::WillDeleteSelection(
// CreateStyleForInsertText()
mDidDeleteSelection = true;
// If there is only bogus content, cancel the operation
if (mBogusNode) {
// If there is only padding <br> element for empty editor, cancel the
// operation.
if (mPaddingBRElementForEmptyEditor) {
*aCancel = true;
return NS_OK;
}
@ -3239,7 +3247,7 @@ nsresult HTMLEditRules::InsertBRIfNeeded() {
*nsGkAtoms::br)) {
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(atStartOfSelection,
.InsertBRElementWithTransaction(atStartOfSelection,
nsIEditor::ePrevious);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
@ -3862,7 +3870,7 @@ nsresult HTMLEditRules::DidDeleteSelection() {
if (atCiteNode.IsSet() && seenBR) {
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(atCiteNode);
.InsertBRElementWithTransaction(atCiteNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -4526,7 +4534,7 @@ nsresult HTMLEditRules::MakeBasicBlock(nsAtom& blockType) {
EditorDOMPoint pointToInsertBrNode(splitNodeResult.SplitPoint());
// Put a <br> element at the split point
brContent = MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(pointToInsertBrNode);
.InsertBRElementWithTransaction(pointToInsertBrNode);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -4645,8 +4653,8 @@ nsresult HTMLEditRules::DidMakeBasicBlock() {
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
}
nsresult rv =
InsertMozBRIfNeeded(MOZ_KnownLive(*atStartOfSelection.Container()));
nsresult rv = InsertPaddingBRElementForEmptyLastLineIfNeeded(
MOZ_KnownLive(*atStartOfSelection.Container()));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -6138,10 +6146,14 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Put in a moz-br so that it won't get deleted
CreateElementResult createMozBrResult = CreateMozBR(EditorDOMPoint(div, 0));
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
// Put in a padding <br> element for empty last line so that it won't get
// deleted.
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(
EditorDOMPoint(div, 0));
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
EditorRawDOMPoint atStartOfDiv(div, 0);
// Don't restore the selection
@ -6440,7 +6452,7 @@ nsresult HTMLEditRules::MaybeDeleteTopMostEmptyAncestor(
if (!HTMLEditUtils::IsList(atBlockParent.GetContainer())) {
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(atBlockParent);
.InsertBRElementWithTransaction(atBlockParent);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -7820,7 +7832,8 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
NS_WARNING_ASSERTION(splitHeaderResult.Succeeded(),
"Failed to split aHeader");
// If the previous heading of split point is empty, put a mozbr into it.
// If the previous heading of split point is empty, put a padding <br>
// element for empty last line into it.
nsCOMPtr<nsIContent> prevItem = HTMLEditorRef().GetPriorHTMLSibling(&aHeader);
if (prevItem) {
MOZ_DIAGNOSTIC_ASSERT(HTMLEditUtils::IsHeader(*prevItem));
@ -7830,10 +7843,12 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
return rv;
}
if (isEmptyNode) {
CreateElementResult createMozBrResult =
CreateMozBR(EditorDOMPoint(prevItem, 0));
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(
EditorDOMPoint(prevItem, 0));
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
}
}
@ -7877,7 +7892,7 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
// Append a <br> to it
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(EditorDOMPoint(pNode, 0));
.InsertBRElementWithTransaction(EditorDOMPoint(pNode, 0));
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -8024,7 +8039,7 @@ EditActionResult HTMLEditRules::ReturnInParagraph(Element& aParentDivOrP) {
brContent = HTMLEditorRef().GetPriorHTMLSibling(
atStartOfSelection.GetContainer());
if (!brContent || !HTMLEditorRef().IsVisibleBRElement(brContent) ||
TextEditUtils::HasMozAttr(brContent)) {
EditorBase::IsPaddingBRElementForEmptyLastLine(*brContent)) {
pointToInsertBR.Set(atStartOfSelection.GetContainer());
brContent = nullptr;
}
@ -8034,7 +8049,7 @@ EditActionResult HTMLEditRules::ReturnInParagraph(Element& aParentDivOrP) {
brContent =
HTMLEditorRef().GetNextHTMLSibling(atStartOfSelection.GetContainer());
if (!brContent || !HTMLEditorRef().IsVisibleBRElement(brContent) ||
TextEditUtils::HasMozAttr(brContent)) {
EditorBase::IsPaddingBRElementForEmptyLastLine(*brContent)) {
pointToInsertBR.Set(atStartOfSelection.GetContainer());
DebugOnly<bool> advanced = pointToInsertBR.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
@ -8072,11 +8087,11 @@ EditActionResult HTMLEditRules::ReturnInParagraph(Element& aParentDivOrP) {
nsCOMPtr<nsIContent> nearNode;
nearNode = HTMLEditorRef().GetPreviousEditableHTMLNode(atStartOfSelection);
if (!nearNode || !HTMLEditorRef().IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(nearNode)) {
EditorBase::IsPaddingBRElementForEmptyLastLine(*nearNode)) {
// is there a BR after it?
nearNode = HTMLEditorRef().GetNextEditableHTMLNode(atStartOfSelection);
if (!nearNode || !HTMLEditorRef().IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(nearNode)) {
EditorBase::IsPaddingBRElementForEmptyLastLine(*nearNode)) {
pointToInsertBR = atStartOfSelection;
splitAfterNewBR = true;
}
@ -8092,7 +8107,7 @@ EditActionResult HTMLEditRules::ReturnInParagraph(Element& aParentDivOrP) {
}
brContent = MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(pointToInsertBR);
.InsertBRElementWithTransaction(pointToInsertBR);
if (NS_WARN_IF(!CanHandleEditAction())) {
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
}
@ -8175,11 +8190,11 @@ nsresult HTMLEditRules::SplitParagraph(
}
// We need to ensure to both paragraphs visible even if they are empty.
// However, moz-<br> element isn't useful in this case because moz-<br>
// elements will be ignored by PlaintextSerializer. Additionally,
// moz-<br> will be exposed as <br> with Element.innerHTML. Therefore,
// we can use normal <br> elements for placeholder in this case.
// Note that Chromium also behaves so.
// However, padding <br> element for empty last line isn't useful in this
// case because it'll be ignored by PlaintextSerializer. Additionally,
// it'll be exposed as <br> with Element.innerHTML. Therefore, we can use
// normal <br> elements for placeholder in this case. Note that Chromium
// also behaves so.
rv = InsertBRIfNeeded(MOZ_KnownLive(*splitDivOrPResult.GetPreviousNode()));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -8300,7 +8315,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
// Append a <br> to it
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(EditorDOMPoint(pNode, 0));
.InsertBRElementWithTransaction(EditorDOMPoint(pNode, 0));
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -8361,10 +8376,12 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
return rv;
}
if (isEmptyNode) {
CreateElementResult createMozBrResult =
CreateMozBR(EditorDOMPoint(prevItem, 0));
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(
EditorDOMPoint(prevItem, 0));
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
} else {
rv = HTMLEditorRef().IsEmptyNode(&aListItem, &isEmptyNode, true);
@ -9243,7 +9260,7 @@ HTMLEditRules::InsertBRElementToEmptyListItemsAndTableCellsInChangedRange() {
}
iter.AppendList(functor, nodeArray);
// Put moz-br's into these empty li's and td's
// Put padding <br> elements for empty <li> and <td>.
for (auto& node : nodeArray) {
// Need to put br at END of node. It may have empty containers in it and
// still pass the "IsEmptyNode" test, and we want the br's to be after
@ -9251,11 +9268,11 @@ HTMLEditRules::InsertBRElementToEmptyListItemsAndTableCellsInChangedRange() {
// is in this node.
EditorDOMPoint endOfNode;
endOfNode.SetToEndOf(node);
// XXX This method should return nsreuslt due to may be destroyed by this
// CreateMozBr() call.
CreateElementResult createMozBrResult = CreateMozBR(endOfNode);
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(endOfNode);
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
}
return NS_OK;
@ -9455,14 +9472,16 @@ nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) {
if (point.GetContainer() == rootElement) {
// Our root node is completely empty. Don't add a <br> here.
// AfterEditInner() will add one for us when it calls
// CreateBogusNodeIfNeeded()!
// CreatePaddingBRElementForEmptyEditorIfNeeded()!
return NS_OK;
}
// we know we can skip the rest of this routine given the cirumstance
CreateElementResult createMozBrResult = CreateMozBR(point);
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(point);
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
return NS_OK;
}
@ -9473,7 +9492,8 @@ nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) {
return NS_OK; // we LIKE it when we are in a text node. that RULZ
}
// do we need to insert a special mozBR? We do if we are:
// Do we need to insert a padding <br> element for empty last line? We do
// if we are:
// 1) prior node is in same block where selection is AND
// 2) prior node is a br AND
// 3) that br is not visible
@ -9490,12 +9510,15 @@ nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) {
// need to insert special moz BR. Why? Because if we don't
// the user will see no new line for the break. Also, things
// like table cells won't grow in height.
CreateElementResult createMozBrResult = CreateMozBR(point);
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(point);
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
point.Set(createMozBrResult.GetNewNode());
// selection stays *before* moz-br, sticking to it
point.Set(createPaddingBRResult.GetNewNode());
// Selection stays *before* padding <br> element for empty last line,
// sticking to it.
ErrorResult error;
SelectionRefPtr()->SetInterlinePosition(true, error);
if (NS_WARN_IF(!CanHandleEditAction())) {
@ -9516,9 +9539,11 @@ nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) {
} else {
nsCOMPtr<nsIContent> nextNode =
HTMLEditorRef().GetNextEditableHTMLNodeInBlock(*nearNode);
if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
// selection between br and mozbr. make it stick to mozbr
// so that it will be on blank line.
if (nextNode &&
EditorBase::IsPaddingBRElementForEmptyLastLine(*nextNode)) {
// Selection between a <br> element and a padding <br> element for
// empty last line. Make it stick to the padding <br> element so
// that it will be on blank line.
IgnoredErrorResult ignoredError;
SelectionRefPtr()->SetInterlinePosition(true, ignoredError);
NS_WARNING_ASSERTION(!ignoredError.Failed(),
@ -9767,7 +9792,7 @@ nsresult HTMLEditRules::RemoveEmptyNodesInChangedRange() {
// but preserve br.
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(EditorDOMPoint(delNode));
.InsertBRElementWithTransaction(EditorDOMPoint(delNode));
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -10151,7 +10176,7 @@ nsresult HTMLEditRules::UpdateDocChangeRange(nsRange* aRange) {
}
nsresult HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
bool aInsertMozBR) {
bool aForPadding) {
MOZ_ASSERT(IsEditorDataAvailable());
if (!IsBlockNode(aNode)) {
@ -10167,13 +10192,24 @@ nsresult HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
return NS_OK;
}
CreateElementResult createBrResult =
!aInsertMozBR ? CreateBR(EditorDOMPoint(&aNode, 0))
: CreateMozBR(EditorDOMPoint(&aNode, 0));
if (NS_WARN_IF(createBrResult.Failed())) {
return createBrResult.Rv();
if (aForPadding) {
CreateElementResult createBRResult =
MOZ_KnownLive(HTMLEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(
EditorDOMPoint(&aNode, 0));
NS_WARNING_ASSERTION(createBRResult.Succeeded(),
"Failed to create padding <br> element");
return createBRResult.Rv();
}
return NS_OK;
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBRElementWithTransaction(EditorDOMPoint(&aNode, 0));
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(brElement, "Failed to create <br> element");
return brElement ? NS_OK : NS_ERROR_FAILURE;
}
void HTMLEditRules::DidCreateNode(Element& aNewElement) {
@ -10493,7 +10529,7 @@ nsresult HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode,
}
RefPtr<Element> brElement =
MOZ_KnownLive(HTMLEditorRef())
.InsertBrElementWithTransaction(pointToInsert);
.InsertBRElementWithTransaction(pointToInsert);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
@ -11095,22 +11131,25 @@ void HTMLEditRules::OnModifyDocument() {
// the editor
nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
// Delete our bogus node, if we have one, since the document might not be
// empty any more.
if (mBogusNode) {
// A mutation event listener may recreate bogus node again during the
// call of DeleteNodeWithTransaction(). So, move it first.
nsCOMPtr<nsIContent> bogusNode(std::move(mBogusNode));
DebugOnly<nsresult> rv =
MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*bogusNode);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove the bogus node");
// Delete our padding <br> element for empty editor, if we have one, since
// the document might not be empty any more.
if (mPaddingBRElementForEmptyEditor) {
// A mutation event listener may recreate padding <br> element for empty
// editor again during the call of DeleteNodeWithTransaction(). So, move
// it first.
RefPtr<HTMLBRElement> paddingBRElement(
std::move(mPaddingBRElementForEmptyEditor));
DebugOnly<nsresult> rv = MOZ_KnownLive(HTMLEditorRef())
.DeleteNodeWithTransaction(*paddingBRElement);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to remove the padding <br> element");
}
// Try to recreate the bogus node if needed.
DebugOnly<nsresult> rv = CreateBogusNodeIfNeeded();
// Try to recreate the padding <br> element for empty editor if needed.
DebugOnly<nsresult> rv = CreatePaddingBRElementForEmptyEditorIfNeeded();
NS_WARNING_ASSERTION(
rv.value != NS_ERROR_EDITOR_DESTROYED,
"The editor has been destroyed during creating a bogus node");
"The editor has been destroyed during creating a padding <br> element");
}
} // namespace mozilla

Просмотреть файл

@ -94,7 +94,7 @@ class HTMLEditRules : public TextEditRules {
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsresult DidDoAction(EditSubActionInfo& aInfo,
nsresult aResult) override;
virtual bool DocumentIsEmpty() override;
virtual bool DocumentIsEmpty() const override;
/**
* DocumentModified() is called when editor content is changed.
@ -193,7 +193,7 @@ class HTMLEditRules : public TextEditRules {
/**
* WillLoadHTML() is called before loading enter document from source.
* This removes bogus node if there is.
* This removes padding <br> element for empty editor if there is.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult WillLoadHTML();
@ -277,26 +277,28 @@ class HTMLEditRules : public TextEditRules {
}
/**
* Insert moz-<br> element (<br type="_moz">) into aNode when aNode is a
* Insert padding <br> element for empty last line into aNode when aNode is a
* block and it has no children.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult InsertMozBRIfNeeded(nsINode& aNode) {
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
InsertPaddingBRElementForEmptyLastLineIfNeeded(nsINode& aNode) {
return InsertBRIfNeededInternal(aNode, true);
}
/**
* Insert a normal <br> element or a moz-<br> element to aNode when
* aNode is a block and it has no children. Use InsertBRIfNeeded() or
* InsertMozBRIfNeeded() instead.
* Insert a normal <br> element or a padding <br> element for empty last line
* to aNode when aNode is a block and it has no children. Use
* InsertBRIfNeeded() or InsertPaddingBRElementForEmptyLastLineIfNeeded()
* instead.
*
* @param aNode Reference to a block parent.
* @param aInsertMozBR true if this should insert a moz-<br> element.
* Otherwise, i.e., this should insert a normal <br>
* element, false.
* @param aNode Reference to a block parent.
* @param aForPadding true if this should insert a <br> element for
* placing caret at empty last line.
* Otherwise, i.e., this should insert a normal
* <br> element, false.
*/
MOZ_CAN_RUN_SCRIPT
MOZ_MUST_USE nsresult InsertBRIfNeededInternal(nsINode& aNode,
bool aInsertMozBR);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
InsertBRIfNeededInternal(nsINode& aNode, bool aForPadding);
/**
* GetGoodSelPointForNode() finds where at a node you would want to set the
@ -536,8 +538,8 @@ class HTMLEditRules : public TextEditRules {
/**
* Called after creating a basic block, indenting, outdenting or aligning
* contents. This method inserts moz-<br> element if start container of
* Selection needs it.
* contents. This method inserts a padding <br> element for empty last line
* if start container of Selection needs it.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult DidMakeBasicBlock();

Просмотреть файл

@ -213,7 +213,9 @@ bool HTMLEditUtils::IsNamedAnchor(nsINode* aNode) {
bool HTMLEditUtils::IsMozDiv(nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsHTMLElement(nsGkAtoms::div) &&
TextEditUtils::HasMozAttr(aNode);
aNode->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"),
eIgnoreCase);
}
/**

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/EditAction.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/EventStates.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/mozInlineSpellChecker.h"
@ -1186,10 +1187,10 @@ nsresult HTMLEditor::InsertBrElementAtSelectionWithTransaction() {
return NS_ERROR_FAILURE;
}
// InsertBrElementWithTransaction() will set selection after the new <br>
// InsertBRElementWithTransaction() will set selection after the new <br>
// element.
RefPtr<Element> newBrElement =
InsertBrElementWithTransaction(atStartOfSelection, eNext);
InsertBRElementWithTransaction(atStartOfSelection, eNext);
if (NS_WARN_IF(!newBrElement)) {
return NS_ERROR_FAILURE;
}
@ -1644,7 +1645,7 @@ nsresult HTMLEditor::InsertElementAtSelectionAsAction(
"Failed to advance offset from inserted point");
// Collapse selection to the new <br> element node after creating it.
RefPtr<Element> newBrElement =
InsertBrElementWithTransaction(insertedPoint, ePrevious);
InsertBRElementWithTransaction(insertedPoint, ePrevious);
if (NS_WARN_IF(!newBrElement)) {
return NS_ERROR_FAILURE;
}
@ -3403,7 +3404,7 @@ nsresult HTMLEditor::DeleteNodeWithTransaction(nsINode& aNode) {
// XXX This is not a override method of EditorBase's method. This might
// cause not called accidentally. We need to investigate this issue.
if (NS_WARN_IF(!IsModifiableNode(*aNode.AsContent()) &&
!IsMozEditorBogusNode(aNode.AsContent()))) {
!EditorBase::IsPaddingBRElementForEmptyEditor(aNode))) {
return NS_ERROR_FAILURE;
}
nsresult rv = EditorBase::DeleteNodeWithTransaction(aNode);
@ -3565,6 +3566,67 @@ nsresult HTMLEditor::InsertTextWithTransaction(
aDocument, aStringToInsert, aPointToInsert, aPointAfterInsertedString);
}
already_AddRefed<Element> HTMLEditor::InsertBRElementWithTransaction(
const EditorDOMPoint& aPointToInsert, EDirection aSelect /* = eNone */) {
MOZ_ASSERT(IsEditActionDataAvailable());
EditorDOMPoint pointToInsert = PrepareToInsertBRElement(aPointToInsert);
if (NS_WARN_IF(!pointToInsert.IsSet())) {
return nullptr;
}
RefPtr<Element> newBRElement =
CreateNodeWithTransaction(*nsGkAtoms::br, pointToInsert);
if (NS_WARN_IF(!newBRElement)) {
return nullptr;
}
switch (aSelect) {
case eNone:
break;
case eNext: {
SelectionRefPtr()->SetInterlinePosition(true, IgnoreErrors());
// Collapse selection after the <br> node.
EditorRawDOMPoint afterBRElement(newBRElement);
if (afterBRElement.IsSet()) {
DebugOnly<bool> advanced = afterBRElement.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after the <br> element");
ErrorResult error;
SelectionRefPtr()->Collapse(afterBRElement, error);
NS_WARNING_ASSERTION(
!error.Failed(),
"Failed to collapse selection after the <br> element");
} else {
NS_WARNING("The <br> node is not in the DOM tree?");
}
break;
}
case ePrevious: {
SelectionRefPtr()->SetInterlinePosition(true, IgnoreErrors());
// Collapse selection at the <br> node.
EditorRawDOMPoint atBRElement(newBRElement);
if (atBRElement.IsSet()) {
ErrorResult error;
SelectionRefPtr()->Collapse(atBRElement, error);
NS_WARNING_ASSERTION(
!error.Failed(),
"Failed to collapse selection at the <br> element");
} else {
NS_WARNING("The <br> node is not in the DOM tree?");
}
break;
}
default:
NS_WARNING(
"aSelect has invalid value, the caller need to set selection "
"by itself");
break;
}
return newBRElement.forget();
}
void HTMLEditor::ContentAppended(nsIContent* aFirstNewContent) {
DoContentInserted(aFirstNewContent, eAppended);
}
@ -3616,8 +3678,8 @@ void HTMLEditor::DoContentInserted(nsIContent* aChild,
}
// We don't need to handle our own modifications
else if (!GetTopLevelEditSubAction() && container->IsEditable()) {
if (IsMozEditorBogusNode(aChild)) {
// Ignore insertion of the bogus node
if (EditorBase::IsPaddingBRElementForEmptyEditor(*aChild)) {
// Ignore insertion of the padding <br> element.
return;
}
RefPtr<HTMLEditRules> htmlRules = mRules->AsHTMLEditRules();
@ -3662,8 +3724,8 @@ void HTMLEditor::ContentRemoved(nsIContent* aChild,
// We don't need to handle our own modifications
} else if (!GetTopLevelEditSubAction() &&
aChild->GetParentNode()->IsEditable()) {
if (aChild && IsMozEditorBogusNode(aChild)) {
// Ignore removal of the bogus node
if (aChild && EditorBase::IsPaddingBRElementForEmptyEditor(*aChild)) {
// Ignore removal of the padding <br> element for empty editor.
return;
}
@ -3751,7 +3813,7 @@ nsresult HTMLEditor::SelectEntireDocument() {
RefPtr<TextEditRules> rules(mRules);
// If we're empty, don't select all children because that would select the
// bogus node.
// padding <br> element for empty editor.
if (rules->DocumentIsEmpty()) {
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
NS_WARNING_ASSERTION(
@ -3980,7 +4042,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
!sibling->IsHTMLElement(nsGkAtoms::br) && !IsBlockNode(child)) {
// Insert br node
RefPtr<Element> brElement =
InsertBrElementWithTransaction(EditorDOMPoint(&aElement, 0));
InsertBRElementWithTransaction(EditorDOMPoint(&aElement, 0));
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
@ -4000,7 +4062,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
// Insert br node
EditorDOMPoint endOfNode;
endOfNode.SetToEndOf(&aElement);
RefPtr<Element> brElement = InsertBrElementWithTransaction(endOfNode);
RefPtr<Element> brElement = InsertBRElementWithTransaction(endOfNode);
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
@ -4021,7 +4083,7 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
!sibling->IsHTMLElement(nsGkAtoms::br)) {
// Insert br node
RefPtr<Element> brElement =
InsertBrElementWithTransaction(EditorDOMPoint(&aElement, 0));
InsertBRElementWithTransaction(EditorDOMPoint(&aElement, 0));
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
@ -4745,7 +4807,7 @@ nsresult HTMLEditor::CopyLastEditableChildStylesWithTransaction(
}
RefPtr<Element> brElement =
InsertBrElementWithTransaction(EditorDOMPoint(firstClonsedElement, 0));
InsertBRElementWithTransaction(EditorDOMPoint(firstClonsedElement, 0));
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}
@ -5252,7 +5314,8 @@ void HTMLEditor::OnModifyDocument() {
return;
}
AutoEditActionDataSetter editActionData(*this, EditAction::eCreateBogusNode);
AutoEditActionDataSetter editActionData(
*this, EditAction::eCreatePaddingBRElementForEmptyEditor);
if (NS_WARN_IF(!editActionData.CanHandle())) {
return;
}

Просмотреть файл

@ -587,6 +587,24 @@ class HTMLEditor final : public TextEditor,
* and call it.
****************************************************************************/
/**
* InsertBRElementWithTransaction() creates a <br> element and inserts it
* before aPointToInsert. Then, tries to collapse selection at or after the
* new <br> node if aSelect is not eNone.
*
* @param aPointToInsert The DOM point where should be <br> node inserted
* before.
* @param aSelect If eNone, this won't change selection.
* If eNext, selection will be collapsed after
* the <br> element.
* If ePrevious, selection will be collapsed at
* the <br> element.
* @return The new <br> node. If failed to create new
* <br> node, returns nullptr.
*/
MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertBRElementWithTransaction(
const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);
/**
* DeleteSelectionWithTransaction() removes selected content or content
* around caret with transactions.
@ -841,11 +859,11 @@ class HTMLEditor final : public TextEditor,
* outIsEmptyNode must be non-null.
*/
nsresult IsEmptyNode(nsINode* aNode, bool* outIsEmptyBlock,
bool aMozBRDoesntCount = false,
bool aSingleBRDoesntCount = false,
bool aListOrCellNotEmpty = false,
bool aSafeToAskFrames = false);
nsresult IsEmptyNodeImpl(nsINode* aNode, bool* outIsEmptyBlock,
bool aMozBRDoesntCount, bool aListOrCellNotEmpty,
bool aSingleBRDoesntCount, bool aListOrCellNotEmpty,
bool aSafeToAskFrames, bool* aSeenBR);
static bool HasAttributes(Element* aElement) {

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/TextComposition.h"
#include "mozilla/TextEditor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/NodeFilterBinding.h"
#include "mozilla/dom/NodeIterator.h"
#include "mozilla/dom/Selection.h"
@ -62,7 +63,7 @@ using namespace dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(TextEditRules)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TextEditRules)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBogusNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaddingBRElementForEmptyEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedSelectionNode)
if (HTMLEditRules* htmlEditRules = tmp->AsHTMLEditRules()) {
HTMLEditRules* tmp = htmlEditRules;
@ -74,7 +75,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TextEditRules)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TextEditRules)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBogusNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaddingBRElementForEmptyEditor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedSelectionNode)
if (HTMLEditRules* htmlEditRules = tmp->AsHTMLEditRules()) {
HTMLEditRules* tmp = htmlEditRules;
@ -103,7 +104,7 @@ TextEditRules::TextEditRules()
void TextEditRules::InitFields() {
mTextEditor = nullptr;
mBogusNode = nullptr;
mPaddingBRElementForEmptyEditor = nullptr;
mCachedSelectionNode = nullptr;
mCachedSelectionOffset = 0;
mActionNesting = 0;
@ -139,7 +140,7 @@ nsresult TextEditRules::Init(TextEditor* aTextEditor) {
// Put in a magic <br> if needed. This method handles null selection,
// which should never happen anyway
nsresult rv = CreateBogusNodeIfNeeded();
nsresult rv = CreatePaddingBRElementForEmptyEditorIfNeeded();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -243,7 +244,7 @@ nsresult TextEditRules::AfterEdit(EditSubAction aEditSubAction,
}
// detect empty doc
rv = CreateBogusNodeIfNeeded();
rv = CreatePaddingBRElementForEmptyEditorIfNeeded();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -254,8 +255,8 @@ nsresult TextEditRules::AfterEdit(EditSubAction aEditSubAction,
return rv;
}
// Collapse the selection to the trailing moz-<br> if it's at the end of
// our text node.
// Collapse the selection to the trailing padding <br> element for empty
// last line if it's at the end of our text node.
rv = CollapseSelectionToTrailingBRIfNeeded();
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
@ -349,7 +350,7 @@ nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
}
}
bool TextEditRules::DocumentIsEmpty() {
bool TextEditRules::DocumentIsEmpty() const {
bool retVal = false;
if (!mTextEditor || NS_FAILED(mTextEditor->IsEmpty(&retVal))) {
retVal = true;
@ -378,19 +379,22 @@ nsresult TextEditRules::WillInsert(bool* aCancel) {
}
// check for the magic content node and delete it if it exists
if (!mBogusNode) {
if (!mPaddingBRElementForEmptyEditor) {
return NS_OK;
}
// A mutation event listener may recreate bogus node again during the
// call of DeleteNodeWithTransaction(). So, move it first.
nsCOMPtr<nsIContent> bogusNode(std::move(mBogusNode));
DebugOnly<nsresult> rv =
MOZ_KnownLive(TextEditorRef()).DeleteNodeWithTransaction(*bogusNode);
// A mutation event listener may recreate padding <br> element for empty
// editor again during the call of DeleteNodeWithTransaction(). So, move
// it first.
RefPtr<HTMLBRElement> paddingBRElement(
std::move(mPaddingBRElementForEmptyEditor));
DebugOnly<nsresult> rv = MOZ_KnownLive(TextEditorRef())
.DeleteNodeWithTransaction(*paddingBRElement);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove the bogus node");
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to remove the padding <br> element");
return NS_OK;
}
@ -498,8 +502,9 @@ nsresult TextEditRules::CollapseSelectionToTrailingBRIfNeeded() {
MOZ_ASSERT(IsEditorDataAvailable());
// we only need to execute the stuff below if we are a plaintext editor.
// html editors have a different mechanism for putting in mozBR's
// (because there are a bunch more places you have to worry about it in html)
// html editors have a different mechanism for putting in padding <br>
// element's (because there are a bunch more places you have to worry about
// it in html)
if (!IsPlaintextEditor()) {
return NS_OK;
}
@ -515,7 +520,8 @@ nsresult TextEditRules::CollapseSelectionToTrailingBRIfNeeded() {
}
// If we are at the end of the <textarea> element, we need to set the
// selection to stick to the moz-<br> at the end of the <textarea>.
// selection to stick to the padding <br> element for empty last line at the
// end of the <textarea>.
EditorRawDOMPoint selectionStartPoint(
EditorBase::GetStartPoint(*SelectionRefPtr()));
if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
@ -538,7 +544,7 @@ nsresult TextEditRules::CollapseSelectionToTrailingBRIfNeeded() {
}
nsINode* nextNode = selectionStartPoint.GetContainer()->GetNextSibling();
if (!nextNode || !TextEditUtils::IsMozBR(nextNode)) {
if (!nextNode || !EditorBase::IsPaddingBRElementForEmptyLastLine(*nextNode)) {
return NS_OK;
}
@ -886,28 +892,29 @@ nsresult TextEditRules::WillSetText(bool* aCancel, bool* aHandled,
// Additionally, for avoiding odd result, we should check whether we're in
// usual condition.
if (IsSingleLineEditor()) {
// If we're a single line text editor, i.e., <input>, there is only bogus-
// If we're a single line text editor, i.e., <input>, there is only padding
// <br> element. Otherwise, there should be only one text node. But note
// that even if there is a bogus node, it's already been removed by
// WillInsert(). So, at here, there should be only one text node or no
// children.
// that even if there is a padding <br> element for empty editor, it's
// already been removed by WillInsert(). So, at here, there should be only
// one text node or no children.
if (firstChild &&
(!EditorBase::IsTextNode(firstChild) || firstChild->GetNextSibling())) {
return NS_OK;
}
} else {
// If we're a multiline text editor, i.e., <textarea>, there is a moz-<br>
// element followed by scrollbar/resizer elements. Otherwise, a text node
// is followed by them.
// If we're a multiline text editor, i.e., <textarea>, there is a padding
// <br> element for empty last line followed by scrollbar/resizer elements.
// Otherwise, a text node is followed by them.
if (!firstChild) {
return NS_OK;
}
if (EditorBase::IsTextNode(firstChild)) {
if (!firstChild->GetNextSibling() ||
!TextEditUtils::IsMozBR(firstChild->GetNextSibling())) {
!EditorBase::IsPaddingBRElementForEmptyLastLine(
*firstChild->GetNextSibling())) {
return NS_OK;
}
} else if (!TextEditUtils::IsMozBR(firstChild)) {
} else if (!EditorBase::IsPaddingBRElementForEmptyLastLine(*firstChild)) {
return NS_OK;
}
}
@ -1011,8 +1018,9 @@ nsresult TextEditRules::WillDeleteSelection(
*aCancel = false;
*aHandled = false;
// if there is only bogus content, cancel the operation
if (mBogusNode) {
// if there is only padding <br> element for empty editor, cancel the
// operation.
if (mPaddingBRElementForEmptyEditor) {
*aCancel = true;
return NS_OK;
}
@ -1151,10 +1159,10 @@ nsresult TextEditRules::DidUndo(nsresult aResult) {
// else that might care. Since undo and redo are relatively rare, it makes
// sense to take the (small) performance hit here.
nsIContent* node = TextEditorRef().GetLeftmostChild(rootElement);
if (node && TextEditorRef().IsMozEditorBogusNode(node)) {
mBogusNode = node;
if (node && EditorBase::IsPaddingBRElementForEmptyEditor(*node)) {
mPaddingBRElementForEmptyEditor = static_cast<HTMLBRElement*>(node);
} else {
mBogusNode = nullptr;
mPaddingBRElementForEmptyEditor = nullptr;
}
return aResult;
}
@ -1188,16 +1196,16 @@ nsresult TextEditRules::DidRedo(nsresult aResult) {
uint32_t len = nodeList->Length();
if (len != 1) {
// only in the case of one br could there be the bogus node
mBogusNode = nullptr;
// only in the case of one br could there be the padding <br> element.
mPaddingBRElementForEmptyEditor = nullptr;
return NS_OK;
}
Element* brElement = nodeList->Item(0);
if (TextEditorRef().IsMozEditorBogusNode(brElement)) {
mBogusNode = brElement;
if (EditorBase::IsPaddingBRElementForEmptyEditor(*brElement)) {
mPaddingBRElementForEmptyEditor = static_cast<HTMLBRElement*>(brElement);
} else {
mBogusNode = nullptr;
mPaddingBRElementForEmptyEditor = nullptr;
}
return NS_OK;
}
@ -1221,8 +1229,9 @@ nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
return NS_OK;
}
// If there is a bogus node, there's no content. So output empty string.
if (mBogusNode) {
// If there is a padding <br> element, there's no content. So output empty
// string.
if (mPaddingBRElementForEmptyEditor) {
aOutString->Truncate();
*aHandled = true;
return NS_OK;
@ -1279,7 +1288,9 @@ nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
bool isTextarea = !isInput;
if (NS_WARN_IF(isInput && firstChildExceptText) ||
NS_WARN_IF(isTextarea && !firstChildExceptText) ||
NS_WARN_IF(isTextarea && !TextEditUtils::IsMozBR(firstChildExceptText) &&
NS_WARN_IF(isTextarea &&
!EditorBase::IsPaddingBRElementForEmptyLastLine(
*firstChildExceptText) &&
!firstChildExceptText->IsXULElement(nsGkAtoms::scrollbar))) {
return NS_OK;
}
@ -1302,8 +1313,8 @@ nsresult TextEditRules::WillOutputText(const nsAString* aOutputFormat,
nsresult TextEditRules::RemoveRedundantTrailingBR() {
MOZ_ASSERT(IsEditorDataAvailable());
// If the bogus node exists, we have no work to do
if (mBogusNode) {
// If the passing <br> element exists, we have no work to do.
if (mPaddingBRElementForEmptyEditor) {
return NS_OK;
}
@ -1317,35 +1328,24 @@ nsresult TextEditRules::RemoveRedundantTrailingBR() {
return NS_ERROR_NULL_POINTER;
}
uint32_t childCount = rootElement->GetChildCount();
if (childCount > 1) {
if (rootElement->GetChildCount() > 1) {
// The trailing br is redundant if it is the only remaining child node
return NS_OK;
}
RefPtr<nsIContent> child = rootElement->GetFirstChild();
if (!child || !child->IsElement()) {
return NS_OK;
}
RefPtr<Element> childElement = child->AsElement();
if (!TextEditUtils::IsMozBR(childElement)) {
RefPtr<HTMLBRElement> brElement =
HTMLBRElement::FromNodeOrNull(rootElement->GetFirstChild());
if (!brElement ||
!EditorBase::IsPaddingBRElementForEmptyLastLine(*brElement)) {
return NS_OK;
}
// Rather than deleting this node from the DOM tree we should instead
// morph this br into the bogus node
childElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::type, true);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
// morph this <br> element into the padding <br> element for editor.
mPaddingBRElementForEmptyEditor = std::move(brElement);
mPaddingBRElementForEmptyEditor->UnsetFlags(NS_PADDING_FOR_EMPTY_LAST_LINE);
mPaddingBRElementForEmptyEditor->SetFlags(NS_PADDING_FOR_EMPTY_EDITOR);
// set mBogusNode to be this <br>
mBogusNode = childElement;
// give it the bogus node attribute
childElement->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
kMOZEditorBogusNodeValue, false);
return NS_OK;
}
@ -1362,73 +1362,76 @@ nsresult TextEditRules::CreateTrailingBRIfNeeded() {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIContent> lastChild = rootElement->GetLastChild();
// assuming CreateBogusNodeIfNeeded() has been called first
if (NS_WARN_IF(!lastChild)) {
// Assuming CreatePaddingBRElementForEmptyEditorIfNeeded() has been
// called first.
if (NS_WARN_IF(!rootElement->GetLastChild())) {
return NS_ERROR_FAILURE;
}
if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
RefPtr<HTMLBRElement> brElement =
HTMLBRElement::FromNode(rootElement->GetLastChild());
if (!brElement) {
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
EditorDOMPoint endOfRoot;
endOfRoot.SetToEndOf(rootElement);
CreateElementResult createMozBrResult = CreateMozBR(endOfRoot);
if (NS_WARN_IF(createMozBrResult.Failed())) {
return createMozBrResult.Rv();
CreateElementResult createPaddingBRResult =
MOZ_KnownLive(TextEditorRef())
.InsertPaddingBRElementForEmptyLastLineWithTransaction(endOfRoot);
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
return createPaddingBRResult.Rv();
}
return NS_OK;
}
// Check to see if the trailing BR is a former bogus node - this will have
// stuck around if we previously morphed a trailing node into a bogus node.
if (!TextEditorRef().IsMozEditorBogusNode(lastChild)) {
// Check to see if the trailing BR is a former padding <br> element for empty
// editor - this will have stuck around if we previously morphed a trailing
// node into a padding <br> element.
if (!brElement->IsPaddingForEmptyEditor()) {
return NS_OK;
}
// Morph it back to a mozBR
lastChild->AsElement()->UnsetAttr(kNameSpaceID_None,
kMOZEditorBogusNodeAttrAtom, false);
lastChild->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"), true);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
}
// Morph it back to a padding <br> element for empty last line.
brElement->UnsetFlags(NS_PADDING_FOR_EMPTY_EDITOR);
brElement->SetFlags(NS_PADDING_FOR_EMPTY_LAST_LINE);
return NS_OK;
}
nsresult TextEditRules::CreateBogusNodeIfNeeded() {
nsresult TextEditRules::CreatePaddingBRElementForEmptyEditorIfNeeded() {
MOZ_ASSERT(IsEditorDataAvailable());
if (mBogusNode) {
if (mPaddingBRElementForEmptyEditor) {
// Let's not create more than one, ok?
return NS_OK;
}
// tell rules system to not do any post-processing
AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
TextEditorRef(), EditSubAction::eCreateBogusNode, nsIEditor::eNone);
TextEditorRef(), EditSubAction::eCreatePaddingBRElementForEmptyEditor,
nsIEditor::eNone);
RefPtr<Element> rootElement = TextEditorRef().GetRoot();
if (!rootElement) {
// We don't even have a body yet, don't insert any bogus nodes at
// We don't even have a body yet, don't insert any padding <br> elements at
// this point.
return NS_OK;
}
// Now we've got the body element. Iterate over the body element's children,
// looking for editable content. If no editable content is found, insert the
// bogus node.
// padding <br> element.
bool isRootEditable = TextEditorRef().IsEditable(rootElement);
for (nsIContent* rootChild = rootElement->GetFirstChild(); rootChild;
rootChild = rootChild->GetNextSibling()) {
if (TextEditorRef().IsMozEditorBogusNode(rootChild) || !isRootEditable ||
TextEditorRef().IsEditable(rootChild) ||
if (EditorBase::IsPaddingBRElementForEmptyEditor(*rootChild) ||
!isRootEditable || TextEditorRef().IsEditable(rootChild) ||
TextEditorRef().IsBlockNode(rootChild)) {
return NS_OK;
}
}
// Skip adding the bogus node if body is read-only.
// Skip adding the padding <br> element for empty editor if body
// is read-only.
if (!TextEditorRef().IsModifiableNode(*rootElement)) {
return NS_OK;
}
@ -1443,15 +1446,11 @@ nsresult TextEditRules::CreateBogusNodeIfNeeded() {
return NS_ERROR_FAILURE;
}
// set mBogusNode to be the newly created <br>
mBogusNode = newBrElement;
mPaddingBRElementForEmptyEditor =
static_cast<HTMLBRElement*>(newBrElement.get());
// Give it a special attribute.
newBrElement->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
kMOZEditorBogusNodeValue, false);
if (NS_WARN_IF(mBogusNode != newBrElement)) {
return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
}
newBrElement->SetFlags(NS_PADDING_FOR_EMPTY_EDITOR);
// Put the node in the document.
nsresult rv = MOZ_KnownLive(TextEditorRef())
@ -1557,44 +1556,6 @@ nsresult TextEditRules::TruncateInsertionIfNeeded(const nsAString* aInString,
return NS_OK;
}
CreateElementResult TextEditRules::CreateBRInternal(
const EditorDOMPoint& aPointToInsert, bool aCreateMozBR) {
MOZ_ASSERT(IsEditorDataAvailable());
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return CreateElementResult(NS_ERROR_FAILURE);
}
RefPtr<Element> brElement =
MOZ_KnownLive(TextEditorRef())
.InsertBrElementWithTransaction(aPointToInsert);
if (NS_WARN_IF(!CanHandleEditAction())) {
return CreateElementResult(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!brElement)) {
return CreateElementResult(NS_ERROR_FAILURE);
}
// give it special moz attr
if (!aCreateMozBR) {
return CreateElementResult(brElement.forget());
}
// XXX Why do we need to set this attribute with transaction?
nsresult rv = MOZ_KnownLive(TextEditorRef())
.SetAttributeWithTransaction(*brElement, *nsGkAtoms::type,
NS_LITERAL_STRING("_moz"));
// XXX Don't we need to remove the new <br> element from the DOM tree
// in these case?
if (NS_WARN_IF(!CanHandleEditAction())) {
return CreateElementResult(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return CreateElementResult(NS_ERROR_FAILURE);
}
return CreateElementResult(brElement.forget());
}
bool TextEditRules::IsPasswordEditor() const {
return mTextEditor ? mTextEditor->IsPasswordEditor() : false;
}

Просмотреть файл

@ -26,6 +26,7 @@ class EditSubActionInfo;
class HTMLEditor;
class HTMLEditRules;
namespace dom {
class HTMLBRElement;
class Selection;
} // namespace dom
@ -100,7 +101,7 @@ class TextEditRules {
* nodes. Otherwise, i.e., there is no meaningful content,
* return true.
*/
virtual bool DocumentIsEmpty();
virtual bool DocumentIsEmpty() const;
bool DontEchoPassword() const;
@ -130,7 +131,9 @@ class TextEditRules {
*/
void HandleNewLines(nsString& aString);
bool HasBogusNode() { return !!mBogusNode; }
bool HasPaddingBRElementForEmptyEditor() const {
return !!mPaddingBRElementForEmptyEditor;
}
protected:
void InitFields();
@ -263,9 +266,11 @@ class TextEditRules {
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult CreateTrailingBRIfNeeded();
/**
* Creates a bogus <br> node if the root element has no editable content.
* Creates a padding <br> element for empty editor if the root element has no
* editable content.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult CreateBogusNodeIfNeeded();
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
CreatePaddingBRElementForEmptyEditorIfNeeded();
/**
* Returns a truncated insertion string if insertion would place us over
@ -275,46 +280,6 @@ class TextEditRules {
nsAString* aOutString, int32_t aMaxLength,
bool* aTruncated);
/**
* Create a normal <br> element and insert it to aPointToInsert.
*
* @param aPointToInsert The point where the new <br> element will be
* inserted.
* @return Returns created <br> element or an error code
* if couldn't create new <br> element.
*/
MOZ_CAN_RUN_SCRIPT CreateElementResult
CreateBR(const EditorDOMPoint& aPointToInsert) {
CreateElementResult ret = CreateBRInternal(aPointToInsert, false);
#ifdef DEBUG
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
if (!CanHandleEditAction()) {
MOZ_ASSERT(ret.Rv() == NS_ERROR_EDITOR_DESTROYED);
}
#endif // #ifdef DEBUG
return ret;
}
/**
* Create a moz-<br> element and insert it to aPointToInsert.
*
* @param aPointToInsert The point where the new moz-<br> element will be
* inserted.
* @return Returns created <br> element or an error code
* if couldn't create new <br> element.
*/
MOZ_CAN_RUN_SCRIPT CreateElementResult
CreateMozBR(const EditorDOMPoint& aPointToInsert) {
CreateElementResult ret = CreateBRInternal(aPointToInsert, true);
#ifdef DEBUG
// If editor is destroyed, it must return NS_ERROR_EDITOR_DESTROYED.
if (!CanHandleEditAction()) {
MOZ_ASSERT(ret.Rv() == NS_ERROR_EDITOR_DESTROYED);
}
#endif // #ifdef DEBUG
return ret;
}
void UndefineCaretBidiLevel();
nsresult CheckBidiLevelForDeletion(const EditorRawDOMPoint& aSelectionPoint,
@ -326,7 +291,8 @@ class TextEditRules {
* text node if:
* - the editor is text editor
* - and Selection is collapsed at the end of the text node
* - and the text node is followed by moz-<br>.
* - and the text node is followed by a padding <br> element for empty last
* line.
*/
MOZ_MUST_USE nsresult CollapseSelectionToTrailingBRIfNeeded();
@ -341,20 +307,6 @@ class TextEditRules {
private:
TextEditor* MOZ_NON_OWNING_REF mTextEditor;
/**
* Create a normal <br> element or a moz-<br> element and insert it to
* aPointToInsert.
*
* @param aParentToInsert The point where the new <br> element will be
* inserted.
* @param aCreateMozBR true if the caller wants to create a moz-<br>
* element. Otherwise, false.
* @return Returns created <br> element and error code.
* If it succeeded, never returns nullptr.
*/
MOZ_CAN_RUN_SCRIPT CreateElementResult
CreateBRInternal(const EditorDOMPoint& aPointToInsert, bool aCreateMozBR);
protected:
/**
* AutoSafeEditorData grabs editor instance and related instances during
@ -436,8 +388,9 @@ class TextEditRules {
*/
inline already_AddRefed<nsINode> GetTextNodeAroundSelectionStartContainer();
// Magic node acts as placeholder in empty doc.
nsCOMPtr<nsIContent> mBogusNode;
// mPaddingBRElementForEmptyEditor should be used for placing caret
// at proper position when editor is empty.
RefPtr<dom::HTMLBRElement> mPaddingBRElementForEmptyEditor;
// Cached selected node.
nsCOMPtr<nsINode> mCachedSelectionNode;
// Cached selected offset.

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/TextEditor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "nsAString.h"
#include "nsCOMPtr.h"
#include "nsCaseTreatment.h"
@ -20,6 +21,8 @@
namespace mozilla {
using namespace dom;
/******************************************************************************
* TextEditUtils
******************************************************************************/
@ -40,28 +43,6 @@ bool TextEditUtils::IsBreak(nsINode* aNode) {
return aNode->IsHTMLElement(nsGkAtoms::br);
}
/**
* IsMozBR() returns true if aNode is an html br node with |type = _moz|.
*/
bool TextEditUtils::IsMozBR(nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsHTMLElement(nsGkAtoms::br) &&
aNode->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"),
eIgnoreCase);
}
/**
* HasMozAttr() returns true if aNode has type attribute and its value is
* |_moz|. (Used to indicate div's and br's we use in mail compose rules)
*/
bool TextEditUtils::HasMozAttr(nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsElement() && aNode->AsElement()->AttrValueIs(
kNameSpaceID_None, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"), eIgnoreCase);
}
/******************************************************************************
* AutoEditInitRulesTrigger
******************************************************************************/

Просмотреть файл

@ -19,8 +19,6 @@ class TextEditUtils final {
// from TextEditRules:
static bool IsBody(nsINode* aNode);
static bool IsBreak(nsINode* aNode);
static bool IsMozBR(nsINode* aNode);
static bool HasMozAttr(nsINode* aNode);
};
/***************************************************************************

Просмотреть файл

@ -440,105 +440,6 @@ nsresult TextEditor::InsertLineBreakAsAction(nsIPrincipal* aPrincipal) {
return NS_OK;
}
already_AddRefed<Element> TextEditor::InsertBrElementWithTransaction(
const EditorDOMPoint& aPointToInsert, EDirection aSelect /* = eNone */) {
MOZ_ASSERT(IsEditActionDataAvailable());
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
return nullptr;
}
// We need to insert a <br> node.
RefPtr<Element> newBRElement;
if (aPointToInsert.IsInTextNode()) {
EditorDOMPoint pointInContainer;
if (aPointToInsert.IsStartOfContainer()) {
// Insert before the text node.
pointInContainer.Set(aPointToInsert.GetContainer());
if (NS_WARN_IF(!pointInContainer.IsSet())) {
return nullptr;
}
} else if (aPointToInsert.IsEndOfContainer()) {
// Insert after the text node.
pointInContainer.Set(aPointToInsert.GetContainer());
if (NS_WARN_IF(!pointInContainer.IsSet())) {
return nullptr;
}
DebugOnly<bool> advanced = pointInContainer.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset to after the text node");
} else {
MOZ_DIAGNOSTIC_ASSERT(aPointToInsert.IsSetAndValid());
// Unfortunately, we need to split the text node at the offset.
ErrorResult error;
nsCOMPtr<nsIContent> newLeftNode =
SplitNodeWithTransaction(aPointToInsert, error);
if (NS_WARN_IF(error.Failed())) {
error.SuppressException();
return nullptr;
}
Unused << newLeftNode;
// Insert new <br> before the right node.
pointInContainer.Set(aPointToInsert.GetContainer());
}
// Create a <br> node.
newBRElement = CreateNodeWithTransaction(*nsGkAtoms::br, pointInContainer);
if (NS_WARN_IF(!newBRElement)) {
return nullptr;
}
} else {
newBRElement = CreateNodeWithTransaction(*nsGkAtoms::br, aPointToInsert);
if (NS_WARN_IF(!newBRElement)) {
return nullptr;
}
}
switch (aSelect) {
case eNone:
break;
case eNext: {
SelectionRefPtr()->SetInterlinePosition(true, IgnoreErrors());
// Collapse selection after the <br> node.
EditorRawDOMPoint afterBRElement(newBRElement);
if (afterBRElement.IsSet()) {
DebugOnly<bool> advanced = afterBRElement.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset after the <br> element");
ErrorResult error;
SelectionRefPtr()->Collapse(afterBRElement, error);
NS_WARNING_ASSERTION(
!error.Failed(),
"Failed to collapse selection after the <br> element");
} else {
NS_WARNING("The <br> node is not in the DOM tree?");
}
break;
}
case ePrevious: {
SelectionRefPtr()->SetInterlinePosition(true, IgnoreErrors());
// Collapse selection at the <br> node.
EditorRawDOMPoint atBRElement(newBRElement);
if (atBRElement.IsSet()) {
ErrorResult error;
SelectionRefPtr()->Collapse(atBRElement, error);
NS_WARNING_ASSERTION(
!error.Failed(),
"Failed to collapse selection at the <br> element");
} else {
NS_WARNING("The <br> node is not in the DOM tree?");
}
break;
}
default:
NS_WARNING(
"aSelect has invalid value, the caller need to set selection "
"by itself");
break;
}
return newBRElement.forget();
}
nsresult TextEditor::ExtendSelectionForDelete(nsIEditor::EDirection* aAction) {
MOZ_ASSERT(IsEditActionDataAvailable());
@ -1441,12 +1342,13 @@ nsresult TextEditor::IsEmpty(bool* aIsEmpty) const {
*aIsEmpty = true;
if (mRules->HasBogusNode()) {
if (mRules->HasPaddingBRElementForEmptyEditor()) {
return NS_OK;
}
// Even if there is no bogus node, we should be detected as empty editor
// if all the children are text nodes and these have no content.
// Even if there is no padding <br> element for empty editor, we should be
// detected as empty editor if all the children are text nodes and these
// have no content.
Element* rootElement = GetRoot();
if (!rootElement) {
// XXX Why don't we return an error in such case??
@ -1481,7 +1383,8 @@ TextEditor::GetTextLength(int32_t* aCount) {
// initialize out params
*aCount = 0;
// special-case for empty document, to account for the bogus node
// special-case for empty document, to account for the padding <br> element
// for empty editor.
bool isEmpty = false;
nsresult rv = IsEmpty(&isEmpty);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -2163,7 +2066,7 @@ nsresult TextEditor::SelectEntireDocument() {
RefPtr<TextEditRules> rules(mRules);
// If we're empty, don't select all children because that would select the
// bogus node.
// padding <br> element for empty editor.
if (rules->DocumentIsEmpty()) {
nsresult rv = SelectionRefPtr()->Collapse(rootElement, 0);
NS_WARNING_ASSERTION(
@ -2183,14 +2086,14 @@ nsresult TextEditor::SelectEntireDocument() {
childNode = childNode->GetPreviousSibling();
}
if (childNode && TextEditUtils::IsMozBR(childNode)) {
if (childNode && EditorBase::IsPaddingBRElementForEmptyLastLine(*childNode)) {
ErrorResult error;
MOZ_KnownLive(SelectionRefPtr())
->SetStartAndEndInLimiter(RawRangeBoundary(rootElement, 0),
EditorRawDOMPoint(childNode), error);
NS_WARNING_ASSERTION(!error.Failed(),
"Failed to select all children of the editor root "
"element except the moz-<br> element");
"element except the padding <br> element");
return error.StealNSResult();
}

Просмотреть файл

@ -167,9 +167,9 @@ class TextEditor : public EditorBase,
const nsAString& aValue) override;
/**
* IsEmpty() checks whether the editor is empty. If editor has only bogus
* node, returns true. If editor's root element has non-empty text nodes or
* other nodes like <br>, returns false.
* IsEmpty() checks whether the editor is empty. If editor has only padding
* <br> element for empty editor, returns true. If editor's root element has
* non-empty text nodes or other nodes like <br>, returns false.
*/
nsresult IsEmpty(bool* aIsEmpty) const;
bool IsEmpty() const {
@ -466,24 +466,6 @@ class TextEditor : public EditorBase,
MOZ_CAN_RUN_SCRIPT
nsresult ReplaceSelectionAsSubAction(const nsAString& aString);
/**
* InsertBrElementWithTransaction() creates a <br> element and inserts it
* before aPointToInsert. Then, tries to collapse selection at or after the
* new <br> node if aSelect is not eNone.
*
* @param aPointToInsert The DOM point where should be <br> node inserted
* before.
* @param aSelect If eNone, this won't change selection.
* If eNext, selection will be collapsed after
* the <br> element.
* If ePrevious, selection will be collapsed at
* the <br> element.
* @return The new <br> node. If failed to create new
* <br> node, returns nullptr.
*/
MOZ_CAN_RUN_SCRIPT already_AddRefed<Element> InsertBrElementWithTransaction(
const EditorDOMPoint& aPointToInsert, EDirection aSelect = eNone);
/**
* Extends the selection for given deletion operation
* If done, also update aAction to what's actually left to do after the

Просмотреть файл

@ -237,7 +237,7 @@ already_AddRefed<Element> WSRunObject::InsertBreak(
RefPtr<Element> newBrElement =
MOZ_KnownLive(mHTMLEditor)
->InsertBrElementWithTransaction(pointToInsert, aSelect);
->InsertBRElementWithTransaction(pointToInsert, aSelect);
if (NS_WARN_IF(!newBrElement)) {
return nullptr;
}
@ -1845,7 +1845,7 @@ nsresult WSRunObject::CheckTrailingNBSPOfRun(WSFragment* aRun) {
// they type 2 spaces.
RefPtr<Element> brElement =
htmlEditor->InsertBrElementWithTransaction(aRun->EndPoint());
htmlEditor->InsertBRElementWithTransaction(aRun->EndPoint());
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -57,7 +57,8 @@ SimpleTest.waitForFocus(() => {
if (editor.rootElement.childNodes.length > 0) {
is(editor.rootElement.childNodes.length, 1, "There should be only one <br> node");
is(editor.rootElement.firstChild.tagName.toLowerCase(), "br", "The node should be a <br> element node");
is(editor.rootElement.firstChild.getAttribute("_moz_editor_bogus_node"), null, "The <br> should not be a bogus node");
ok(!SpecialPowers.wrap(editor.rootElement.firstChild).isPaddingForEmptyEditor,
"The <br> should not be a padding <br> element");
}
} else {
ok(!editor.rootElement.hasChildNodes(),

Просмотреть файл

@ -18,10 +18,10 @@ https://bugzilla.mozilla.org/show_bug.cgi=id=1385905
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
function ensureNoMozBR() {
function ensureNoPaddingBR() {
for (let br of document.querySelectorAll("#editor > div > br")) {
isnot(br.getAttribute("type"), "_moz",
"mozBR shouldn't be used with this test");
ok(!SpecialPowers.wrap(br).isPaddingForEmptyLastLine,
"padding <br> element shouldn't be used with this test");
}
}
document.execCommand("defaultparagraphseparator", false, "div");
@ -35,15 +35,15 @@ SimpleTest.waitForFocus(() => {
sendString("x");
is(editor.innerHTML, "<div>x<br></div><div>contents</div>",
"Typing 'x' at the empty <div> element should just insert 'x' into the <div> element");
ensureNoMozBR();
ensureNoPaddingBR();
synthesizeKey("KEY_Enter");
is(editor.innerHTML, "<div>x</div><div><br></div><div>contents</div>",
"Typing Enter next to 'x' in the first <div> element should split the <div> element and inserts <br> element to a new <div> element");
ensureNoMozBR();
ensureNoPaddingBR();
synthesizeKey("KEY_Enter");
is(editor.innerHTML, "<div>x</div><div><br></div><div><br></div><div>contents</div>",
"Typing Enter in the empty <div> should split the <div> element and inserts <br> element to a new <div> element");
ensureNoMozBR();
ensureNoPaddingBR();
SimpleTest.finish();
});
</script>

Просмотреть файл

@ -30,42 +30,42 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=471319
let t1 = SpecialPowers.wrap($("t1"));
// Test 1: Undo on an empty editor - the editor should not forget about
// the bogus node
// the padding <br> element for empty editor.
let t1Editor = t1.editor;
// Did the editor recognize the new bogus node?
// Did the editor recognize the new padding <br> element?
t1Editor.undo(1);
ok(!t1.value, "<br> still recognized as bogus node on undo");
ok(!t1.value, "<br> still recognized as padding on undo");
// Test 2: Redo on an empty editor - the editor should not forget about
// the bogus node
// the padding <br> element for empty editor.
let t2 = SpecialPowers.wrap($("t2"));
let t2Editor = t2.editor;
// Did the editor recognize the new bogus node?
// Did the editor recognize the new padding <br> element?
t2Editor.redo(1);
ok(!t2.value, "<br> still recognized as bogus node on redo");
ok(!t2.value, "<br> still recognized as padding on redo");
// Test 3: Undoing a batched transaction where both end points of the
// transaction are the bogus node - the bogus node should still be
// recognized as bogus
// transaction are the padding <br> element for empty editor - the
// <br> element should still be recognized as padding.
t1Editor.transactionManager.beginBatch(null);
t1.value = "mozilla";
t1.value = "";
t1Editor.transactionManager.endBatch(false);
t1Editor.undo(1);
ok(!t1.value,
"recreated <br> from undo transaction recognized as bogus");
"recreated <br> from undo transaction recognized as padding");
// Test 4: Redoing a batched transaction where both end points of the
// transaction are the bogus node - the bogus node should still be
// recognized as bogus
// transaction are the padding <br> element for empty editor - the
// <br> element should still be recognized padding.
t1Editor.redo(1);
ok(!t1.value,
"recreated <br> from redo transaction recognized as bogus");
"recreated <br> from redo transaction recognized as padding");
SimpleTest.finish();
}
</script>

Просмотреть файл

@ -41,8 +41,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=471722
editor.cut();
is(t1.value, "", "initial text was removed");
// So now we will have emptied the textfield
// and the editor will have created a bogus node
// So now we will have emptied the textfield and the editor will have
// created a padding <br> element for empty editor.
// Check the transaction is in the undo stack...
var t1Enabled = {};
var t1CanUndo = {};
@ -53,18 +53,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=471722
editor.undo(1);
is(t1.value, "minefield", "text reinserted");
// So now, the cut should be in the redo stack,
// so executing the redo will clear the text once again
// and reinsert the bogus node that was removed after undo.
// This will require the editor to figure out that we have a
// bogus node again...
// So now, the cut should be in the redo stack, so executing the redo
// will clear the text once again and reinsert the padding <br>
// element for empty editor that was removed after undo.
// This will require the editor to figure out that we have a padding
// <br> element again...
var t1CanRedo = {};
editor.canRedo(t1Enabled, t1CanRedo);
ok(t1CanRedo.value, "redo is enabled");
editor.redo(1);
// Did the editor notice a bogus node reappeared?
is(t1.value, "", "editor found bogus node");
// Did the editor notice a padding <br> element for empty editor
// reappeared?
is(t1.value, "", "editor found padding <br> element");
} catch (e) {
ok(false, "test failed with error " + e);
}

Просмотреть файл

@ -69,7 +69,8 @@ SimpleTest.waitForFocus(function() {
is(textNode.textContent, "foo bar", "Backspace should work correctly");
var snapshot = snapshotWindow(win, false);
ok(compareSnapshots(snapshot, ref, true)[0], "No bogus node should exist in the document");
ok(compareSnapshots(snapshot, ref, true)[0],
"No padding <br> element should exist in the document");
callback();
}, {once: true});

Просмотреть файл

@ -34,7 +34,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=740784
synthesizeKey("KEY_Backspace");
synthesizeKey("z", {accelKey: true});
// Was the former bogus node changed to a mozBR?
is(t1.value, "a", "trailing <br> correctly ignored");
SimpleTest.finish();

Просмотреть файл

@ -12,6 +12,7 @@
#include <map>
#include "base/file_path.h"
#include "base/process.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/time.h"

Просмотреть файл

@ -22,6 +22,8 @@ include('../build/moz.configure/rust.configure',
when='--enable-compile-environment')
include('../build/moz.configure/bindgen.configure',
when='--enable-compile-environment')
include('../build/moz.configure/lto-pgo.configure',
when='--enable-compile-environment')
@depends('JS_STANDALONE')
def js_standalone(value):

Просмотреть файл

@ -3909,6 +3909,19 @@ bool js::IsPromiseForAsync(JSObject* promise) {
MOZ_MUST_USE bool js::AsyncFunctionThrown(JSContext* cx,
Handle<PromiseObject*> resultPromise,
HandleValue reason) {
if (resultPromise->state() != JS::PromiseState::Pending) {
// OOM after resolving promise.
// Report a warning and ignore the result.
if (!JS_ReportErrorFlagsAndNumberASCII(
cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
JSMSG_UNHANDLABLE_PROMISE_REJECTION_WARNING)) {
if (cx->isExceptionPending()) {
cx->clearPendingException();
}
}
return true;
}
return RejectPromiseInternal(cx, resultPromise, reason);
}

Просмотреть файл

@ -242,10 +242,8 @@ bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta,
if (!bytecodeSection().code().growByUninitialized(delta)) {
return false;
}
// If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
// reserve a type set to store its result.
if (CodeSpec[op].format & JOF_TYPESET) {
if (BytecodeOpHasTypeSet(op)) {
bytecodeSection().incrementNumTypeSets();
}

Просмотреть файл

@ -0,0 +1,227 @@
// Throwing error after resolving async function's promise should not
// overwrite the promise's state or value/reason.
// This situation can happen either with debugger interaction or OOM.
// This testcase relies on the fact that there's a breakpoint after resolving
// the async function's promise, before leaving the async function's frame.
// This function searches for the last breakpoint before leaving the frame.
//
// - `declCode` should declare an async function `f`, and the function should
// set global variable `returning` to `true` just before return
// - `callCode` should call the function `f` and make sure the function's
// execution reaches the last breakpoint
function searchLastBreakpointBeforeReturn(declCode, callCode) {
const g = newGlobal({ newCompartment: true });
const dbg = new Debugger(g);
g.eval(declCode);
let hit = false;
let offset = 0;
dbg.onEnterFrame = function(frame) {
if (frame.callee && frame.callee.name == "f") {
frame.onStep = () => {
if (!g.returning) {
return undefined;
}
offset = frame.offset;
return undefined;
};
}
};
g.eval(callCode);
drainJobQueue();
assertEq(offset != 0, true);
return offset;
}
function testWithoutAwait() {
const declCode = `
var returning = false;
async function f() {
return (returning = true, "expected");
};
`;
const callCode = `
var p = f();
`;
const offset = searchLastBreakpointBeforeReturn(declCode, callCode);
const g = newGlobal({ newCompartment: true });
const dbg = new Debugger(g);
g.eval(declCode);
let onPromiseSettledCount = 0;
dbg.onPromiseSettled = function(promise) {
onPromiseSettledCount++;
// No promise should be rejected.
assertEq(promise.promiseState, "fulfilled");
// Async function's promise should have expected value.
if (onPromiseSettledCount == 1) {
assertEq(promise.promiseValue, "expected");
}
};
let hitBreakpoint = false;
dbg.onEnterFrame = function(frame) {
if (frame.callee && frame.callee.name == "f") {
frame.script.setBreakpoint(offset, {
hit() {
hitBreakpoint = true;
return { throw: "unexpected" };
}
});
}
};
enableLastWarning();
g.eval(`
var fulfilledValue;
var rejected = false;
`);
g.eval(callCode);
// The execution reaches to the last breakpoint without running job queue.
assertEq(hitBreakpoint, true);
const warn = getLastWarning();
assertEq(warn.message,
"unhandlable error after resolving async function's promise");
clearLastWarning();
// Add reaction handler after resolution.
// This handler's job will be enqueued immediately.
g.eval(`
p.then(x => {
fulfilledValue = x;
}, e => {
rejected = true;
});
`);
// Run the above handler.
drainJobQueue();
assertEq(g.fulfilledValue, "expected");
assertEq(onPromiseSettledCount >= 1, true);
}
function testWithAwait() {
const declCode = `
var resolve;
var p = new Promise(r => { resolve = r });
var returning = false;
async function f() {
await p;
return (returning = true, "expected");
};
`;
const callCode = `
var p = f();
`;
const resolveCode = `
resolve("resolve");
`;
const offset = searchLastBreakpointBeforeReturn(declCode,
callCode + resolveCode);
const g = newGlobal({newCompartment: true});
const dbg = new Debugger(g);
g.eval(declCode);
let onPromiseSettledCount = 0;
dbg.onPromiseSettled = function(promise) {
onPromiseSettledCount++;
// No promise should be rejected.
assertEq(promise.promiseState, "fulfilled");
// Async function's promise should have expected value.
if (onPromiseSettledCount == 3) {
assertEq(promise.promiseValue, "expected");
}
};
let hitBreakpoint = false;
dbg.onEnterFrame = function(frame) {
if (frame.callee && frame.callee.name == "f") {
frame.script.setBreakpoint(offset, {
hit() {
hitBreakpoint = true;
return { throw: "unexpected" };
}
});
}
};
enableLastWarning();
g.eval(`
var fulfilledValue1;
var fulfilledValue2;
var rejected = false;
`);
g.eval(callCode);
assertEq(getLastWarning(), null);
// Add reaction handler before resolution.
// This handler's job will be enqueued when `p` is resolved.
g.eval(`
p.then(x => {
fulfilledValue1 = x;
}, e => {
rejected = true;
});
`);
g.eval(resolveCode);
// Run the remaining part of async function, and the above handler.
drainJobQueue();
// The execution reaches to the last breakpoint after running job queue for
// resolving `p`.
assertEq(hitBreakpoint, true);
const warn = getLastWarning();
assertEq(warn.message,
"unhandlable error after resolving async function's promise");
clearLastWarning();
assertEq(g.fulfilledValue1, "expected");
assertEq(g.rejected, false);
// Add reaction handler after resolution.
// This handler's job will be enqueued immediately.
g.eval(`
p.then(x => {
fulfilledValue2 = x;
}, e => {
rejected = true;
});
`);
// Run the above handler.
drainJobQueue();
assertEq(g.fulfilledValue2, "expected");
assertEq(g.rejected, false);
assertEq(onPromiseSettledCount >= 3, true);
}
testWithoutAwait();
testWithAwait();

Просмотреть файл

@ -22,6 +22,7 @@
#include "jit/RematerializedFrame.h"
#include "js/Utility.h"
#include "vm/ArgumentsObject.h"
#include "vm/BytecodeUtil.h"
#include "vm/TraceLogging.h"
#include "jit/JitFrames-inl.h"
@ -1134,7 +1135,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
} else {
// If the opcode is monitored we should monitor the top stack value when
// we finish the bailout in FinishBailoutToBaseline.
if (resumeAfter && (CodeSpec[op].format & JOF_TYPESET)) {
if (resumeAfter && BytecodeOpHasTypeSet(op)) {
builder.setMonitorPC(pc);
}
jsbytecode* resumePC = GetResumePC(script, pc, resumeAfter);
@ -1326,7 +1327,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
// Ensure we have a TypeMonitor fallback stub so we don't crash in JIT code
// when we try to enter it. See callers of offsetOfFallbackMonitorStub.
if (CodeSpec[*pc].format & JOF_TYPESET) {
if (BytecodeOpHasTypeSet(JSOp(*pc))) {
ICFallbackStub* fallbackStub = icEntry.fallbackStub();
if (!fallbackStub->toMonitoredFallbackStub()->getFallbackMonitorStub(
cx, script)) {
@ -1869,7 +1870,7 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg) {
// Monitor the top stack value if we are resuming after a JOF_TYPESET op.
if (jsbytecode* monitorPC = bailoutInfo->monitorPC) {
MOZ_ASSERT(CodeSpec[*monitorPC].format & JOF_TYPESET);
MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*monitorPC)));
MOZ_ASSERT(GetNextPc(monitorPC) == topFrame->interpreterPC());
RootedScript script(cx, topFrame->script());

Просмотреть файл

@ -34,6 +34,7 @@
#include "jit/VMFunctions.h"
#include "js/Conversions.h"
#include "js/GCVector.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSFunction.h"
#include "vm/Opcodes.h"
#include "vm/SelfHosting.h"
@ -224,7 +225,7 @@ bool JitScript::initICEntriesAndBytecodeTypeMap(JSContext* cx,
// Note: if the script is very large there will be more JOF_TYPESET ops
// than bytecode type sets. See JSScript::MaxBytecodeTypeSets.
if ((CodeSpec[op].format & JOF_TYPESET) &&
if (BytecodeOpHasTypeSet(op) &&
typeMapIndex < JSScript::MaxBytecodeTypeSets) {
typeMap[typeMapIndex] = script->pcToOffset(pc);
typeMapIndex++;

Просмотреть файл

@ -22,6 +22,7 @@
#include "jit/Lowering.h"
#include "jit/MIRGraph.h"
#include "vm/ArgumentsObject.h"
#include "vm/BytecodeUtil.h"
#include "vm/EnvironmentObject.h"
#include "vm/Instrumentation.h"
#include "vm/Opcodes.h"
@ -654,7 +655,7 @@ AbortReasonOr<Ok> IonBuilder::analyzeNewLoopTypes(
last = earlier;
}
if (CodeSpec[*last].format & JOF_TYPESET) {
if (BytecodeOpHasTypeSet(JSOp(*last))) {
TemporaryTypeSet* typeSet = bytecodeTypes(last);
if (!typeSet->empty()) {
MIRType type = typeSet->getKnownMIRType();

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/BinarySearch.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSScript.h"
#include "vm/TypeInference.h"
@ -42,7 +43,7 @@ template <typename TYPESET>
uint32_t* bytecodeMap,
uint32_t* hint,
TYPESET* typeArray) {
MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*pc)));
uint32_t offset = script->pcToOffset(pc);
// See if this pc is the next typeset opcode after the last one looked up.

Просмотреть файл

@ -13,6 +13,7 @@
#include "jit/BaselineIC.h"
#include "jit/BytecodeAnalysis.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSScript.h"
#include "vm/Stack.h"
#include "vm/TypeInference.h"
@ -258,7 +259,7 @@ void JitScript::printTypes(JSContext* cx, HandleScript script) {
fprintf(stderr, "%s", sprinter.string());
}
if (CodeSpec[*pc].format & JOF_TYPESET) {
if (BytecodeOpHasTypeSet(JSOp(*pc))) {
StackTypeSet* types = bytecodeTypes(sweep, script, pc);
fprintf(stderr, " typeset %u:", unsigned(types - typeArray(sweep)));
types->print();

Просмотреть файл

@ -644,6 +644,9 @@ MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "P
MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable")
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
// Async Function
MSG_DEF(JSMSG_UNHANDLABLE_PROMISE_REJECTION_WARNING, 0, JSEXN_WARN, "unhandlable error after resolving async function's promise")
// Async Iteration
MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_SYNTAXERR, "'for await' loop should be used with 'of'")
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")

Просмотреть файл

@ -11254,8 +11254,8 @@ int main(int argc, char** argv, char** envp) {
if (cpuCount < 0) {
cpuCount = op.getIntOption("thread-count"); // Legacy name
}
if (cpuCount >= 0) {
SetFakeCPUCount(cpuCount);
if (cpuCount >= 0 && !SetFakeCPUCount(cpuCount)) {
return 1;
}
size_t nurseryBytes = JS::DefaultNurseryBytes;

Просмотреть файл

@ -633,6 +633,10 @@ static inline int32_t GetBytecodeInteger(jsbytecode* pc) {
inline bool BytecodeOpHasIC(JSOp op) { return CodeSpec[op].format & JOF_IC; }
inline bool BytecodeOpHasTypeSet(JSOp op) {
return CodeSpec[op].format & JOF_TYPESET;
}
/*
* Counts accumulated for a single opcode in a script. The counts tracked vary
* between opcodes, and this structure ensures that counts are accessed in a

Просмотреть файл

@ -71,7 +71,7 @@ bool js::CreateHelperThreadsState() {
return false;
}
gHelperThreadState = helperThreadState.release();
if (!gHelperThreadState->initializeHelperContexts()) {
if (!gHelperThreadState->ensureContextListForThreadCount()) {
js_delete(gHelperThreadState);
return false;
}
@ -106,12 +106,17 @@ static size_t ThreadCountForCPUCount(size_t cpuCount) {
return Max<size_t>(cpuCount, 2);
}
void js::SetFakeCPUCount(size_t count) {
bool js::SetFakeCPUCount(size_t count) {
// This must be called before the threads have been initialized.
MOZ_ASSERT(!HelperThreadState().threads);
HelperThreadState().cpuCount = count;
HelperThreadState().threadCount = ThreadCountForCPUCount(count);
if (!HelperThreadState().ensureContextListForThreadCount()) {
return false;
}
return true;
}
void JS::SetProfilingThreadCallbacks(
@ -1202,9 +1207,16 @@ void GlobalHelperThreadState::finishThreads() {
threads.reset(nullptr);
}
bool GlobalHelperThreadState::initializeHelperContexts() {
bool GlobalHelperThreadState::ensureContextListForThreadCount() {
if (helperContexts_.length() >= threadCount) {
return true;
}
AutoLockHelperThreadState lock;
for (size_t i = 0; i < threadCount; i++) {
// SetFakeCPUCount() may cause the context list to contain less contexts
// than there are helper threads, which could potentially lead to a crash.
// Append more initialized contexts to the list until there are enough.
while (helperContexts_.length() < threadCount) {
UniquePtr<JSContext> cx =
js::MakeUnique<JSContext>(nullptr, JS::ContextOptions());
// To initialize context-specific protected data, the context must

Просмотреть файл

@ -171,7 +171,7 @@ class GlobalHelperThreadState {
void finish();
void finishThreads();
MOZ_MUST_USE bool initializeHelperContexts();
MOZ_MUST_USE bool ensureContextListForThreadCount();
JSContext* getFirstUnusedContext(AutoLockHelperThreadState& locked);
void destroyHelperContexts(AutoLockHelperThreadState& lock);
@ -492,7 +492,7 @@ bool EnsureHelperThreadsInitialized();
// This allows the JS shell to override GetCPUCount() when passed the
// --thread-count=N option.
void SetFakeCPUCount(size_t count);
bool SetFakeCPUCount(size_t count);
// Get the current helper thread, or null.
HelperThread* CurrentHelperThread();

Просмотреть файл

@ -3444,7 +3444,7 @@ void JitScript::MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
/* static */
void JitScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
jsbytecode* pc, const js::Value& rval) {
MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*pc)));
if (!script->jitScript()) {
return;

Просмотреть файл

@ -10803,6 +10803,9 @@ void nsCSSFrameConstructor::FinishBuildingColumns(
nsFrameList finalList;
while (aColumnContentSiblings.NotEmpty()) {
// Tag every ColumnSet except the last one.
prevColumnSet->SetProperty(nsIFrame::HasColumnSpanSiblings(), true);
nsIFrame* f = aColumnContentSiblings.RemoveFirstChild();
if (f->IsColumnSpan()) {
// Do nothing for column-span wrappers. Just move it to the final

Просмотреть файл

@ -245,7 +245,6 @@ nsresult nsLayoutStatics::Initialize() {
MediaManager::StartupInit();
CubebUtils::InitLibrary();
nsContentSink::InitializeStatics();
nsHtml5Module::InitializeStatics();
mozilla::dom::FallbackEncoding::Initialize();
nsLayoutUtils::Initialize();

Просмотреть файл

@ -7,6 +7,7 @@
/* rendering object for HTML <br> elements */
#include "mozilla/PresShell.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "gfxContext.h"
#include "nsCOMPtr.h"
#include "nsContainerFrame.h"
@ -247,11 +248,10 @@ nsIFrame::FrameSearchResult BRFrame::PeekOffsetWord(
#ifdef ACCESSIBILITY
a11y::AccType BRFrame::AccessibleType() {
nsIContent* parent = mContent->GetParent();
if (parent && parent->IsRootOfNativeAnonymousSubtree() &&
parent->GetChildCount() == 1) {
// This <br> is the only node in a text control, therefore it is the hacky
// "bogus node" used when there is no text in the control
dom::HTMLBRElement* brElement = dom::HTMLBRElement::FromNode(mContent);
if (brElement->IsPaddingForEmptyEditor()) {
// This <br> is a "padding <br> element" used when there is no text in the
// editor.
return a11y::eNoType;
}

Просмотреть файл

@ -3575,6 +3575,8 @@ void nsBlockFrame::ReflowBlockFrame(BlockReflowInput& aState,
availSize.BSize(wm) -= aState.BorderPadding().BEnd(wm);
}
// Bug 1569701: We need to use GetEffectiveComputedBSize() to get
// correct block-size if ColumnSetWrapper is fragmented.
nscoord contentBSize = aState.mReflowInput.ComputedBSize();
if (aState.mReflowInput.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE) {
contentBSize =

Просмотреть файл

@ -917,37 +917,71 @@ nsColumnSetFrame::ColumnBalanceData nsColumnSetFrame::ReflowChildren(
contentSize.BSize(wm) = std::max(contentSize.BSize(wm), contentBEnd);
mLastFrameStatus = aStatus;
// Apply computed and min/max values
if (aConfig.mComputedBSize != NS_UNCONSTRAINEDSIZE) {
if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
if (StaticPrefs::layout_css_column_span_enabled()) {
MOZ_ASSERT(borderPadding.IsAllZero(),
"Only our parent ColumnSetWrapper can have border and padding!");
if (computedSize.BSize(wm) != NS_UNCONSTRAINEDSIZE &&
!GetProperty(nsIFrame::HasColumnSpanSiblings())) {
MOZ_ASSERT(aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
"Available block-size should be constrained because it's "
"restricted by the computed block-size when our reflow input "
"is created in nsBlockFrame::ReflowBlockFrame()!");
// If a) our parent ColumnSetWrapper has constrained block-size
// (nsBlockFrame::ReflowBlockFrame() applies the block-size constraint
// when creating BlockReflowInput for ColumnSetFrame); and b) we are the
// sole ColumnSet or the last ColumnSet continuation split by column-spans
// in a ColumnSetWrapper, extend our block-size to consume the available
// block-size so that the column-rules are drawn to the content block-end
// edge of the multicol container.
contentSize.BSize(wm) =
std::min(contentSize.BSize(wm), aConfig.mComputedBSize);
} else {
contentSize.BSize(wm) = aConfig.mComputedBSize;
std::max(contentSize.BSize(wm), aReflowInput.AvailableBSize());
// But don't consume more block-size than what is left in the
// ColumnSetWrapper.
//
// Bug 1569701: If we use the effective computed block-size of
// ColumnSetWrapper when creating BlockReflowInput for ColumnSet, the
// available block-size should always less than or equal to the effective
// computed block-size. This std::min() won't be needed.
contentSize.BSize(wm) =
std::min(contentSize.BSize(wm), computedSize.BSize(wm));
}
} else if (aReflowInput.mStyleDisplay->IsContainSize()) {
// If we are intrinsically sized, but are size contained,
// we need to behave as if we have no contents. Our BSize
// should be zero or minBSize if specified.
contentSize.BSize(wm) = aReflowInput.ApplyMinMaxBSize(0);
} else {
// We add the "consumed" block-size back in so that we're applying
// constraints to the correct bSize value, then subtract it again
// after we've finished with the min/max calculation. This prevents us from
// having a last continuation that is smaller than the min bSize. but which
// has prev-in-flows, trigger a larger bSize than actually required.
contentSize.BSize(wm) = aReflowInput.ApplyMinMaxBSize(
contentSize.BSize(wm), aConfig.mConsumedBSize);
}
if (aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE) {
contentSize.ISize(wm) = aReflowInput.ComputedISize();
} else {
contentSize.ISize(wm) =
aReflowInput.ApplyMinMaxISize(contentSize.ISize(wm));
// Apply computed and min/max values
if (aConfig.mComputedBSize != NS_UNCONSTRAINEDSIZE) {
if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
contentSize.BSize(wm) =
std::min(contentSize.BSize(wm), aConfig.mComputedBSize);
} else {
contentSize.BSize(wm) = aConfig.mComputedBSize;
}
} else if (aReflowInput.mStyleDisplay->IsContainSize()) {
// If we are intrinsically sized, but are size contained,
// we need to behave as if we have no contents. Our BSize
// should be zero or minBSize if specified.
contentSize.BSize(wm) = aReflowInput.ApplyMinMaxBSize(0);
} else {
// We add the "consumed" block-size back in so that we're applying
// constraints to the correct bSize value, then subtract it again
// after we've finished with the min/max calculation. This prevents us
// from having a last continuation that is smaller than the min bSize. but
// which has prev-in-flows, trigger a larger bSize than actually required.
contentSize.BSize(wm) = aReflowInput.ApplyMinMaxBSize(
contentSize.BSize(wm), aConfig.mConsumedBSize);
}
if (aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE) {
contentSize.ISize(wm) = aReflowInput.ComputedISize();
} else {
contentSize.ISize(wm) =
aReflowInput.ApplyMinMaxISize(contentSize.ISize(wm));
}
contentSize.ISize(wm) += borderPadding.IStartEnd(wm);
contentSize.BSize(wm) += borderPadding.BStartEnd(wm);
}
contentSize.ISize(wm) += borderPadding.IStartEnd(wm);
contentSize.BSize(wm) += borderPadding.BStartEnd(wm);
aDesiredSize.SetSize(wm, contentSize);
aDesiredSize.mOverflowAreas = overflowRects;
aDesiredSize.UnionOverflowAreasWithDesiredBounds();

Просмотреть файл

@ -49,7 +49,7 @@ pref(layout.css.column-span.enabled,true) == first-line-first-letter.html first-
# column-span enabled. These lines can be removed once the pref becomes
# default-enabled (Bug 1426010).
default-preferences pref(layout.css.column-span.enabled,true)
fails == min-width-2.html min-width-2-ref.html # Bug 1548100
== min-width-2.html min-width-2-ref.html
== column-balancing-nested-001.html column-balancing-nested-001-ref.html
== zero-height-nondirty-reflow.html zero-height-nondirty-reflow-ref.html
default-preferences

Просмотреть файл

@ -260,8 +260,7 @@ css-multicol/multicol-rule-000.xht
fuzzy-if(!OSX,0-135,0-1584) css-multicol/multicol-rule-001.xht
fails-if(!OSX) random-if(OSX) css-multicol/multicol-rule-002.xht
css-multicol/multicol-rule-003.xht
# Bug 1548100
pref(layout.css.column-span.enabled,true) fails css-multicol/multicol-rule-004.xht
pref(layout.css.column-span.enabled,true) css-multicol/multicol-rule-004.xht
css-multicol/multicol-rule-color-001.xht
fuzzy(0-106,0-354) css-multicol/multicol-rule-dashed-000.xht
fuzzy(0-106,0-354) css-multicol/multicol-rule-dotted-000.xht

Просмотреть файл

@ -125,7 +125,7 @@ fuzzy-if(skiaContent,0-64,0-2) == css-multicol/multicol-reduce-000.xht css-multi
fuzzy-if(!OSX,0-135,0-1584) == css-multicol/multicol-rule-001.xht css-multicol/multicol-rule-001-ref.xht
fails-if(!OSX) random-if(OSX) == css-multicol/multicol-rule-002.xht css-multicol/multicol-rule-ref.xht
== css-multicol/multicol-rule-003.xht css-multicol/multicol-rule-003-ref.xht
pref(layout.css.column-span.enabled,true) fails == css-multicol/multicol-rule-004.xht css-multicol/multicol-rule-004-ref.xht
pref(layout.css.column-span.enabled,true) == css-multicol/multicol-rule-004.xht css-multicol/multicol-rule-004-ref.xht
== css-multicol/multicol-rule-color-001.xht css-multicol/multicol-rule-color-001-ref.xht
== css-multicol/multicol-rule-color-inherit-001.xht css-multicol/multicol-rule-color-inherit-001-ref.xht
== css-multicol/multicol-rule-color-inherit-002.xht css-multicol/multicol-rule-color-inherit-001-ref.xht

Просмотреть файл

@ -137,22 +137,14 @@ class InfallibleAllocPolicy {
class StackTrace : public phc::StackTrace {
public:
StackTrace() : phc::StackTrace(), mSkipped(false) {}
bool IsEmpty() const { return mLength == 0 && !mSkipped; }
StackTrace() : phc::StackTrace() {}
void Clear() {
mLength = 0;
mSkipped = false;
}
void Fill();
void FillSkipped() {
mLength = 0;
mSkipped = true;
}
private:
static void StackWalkCallback(uint32_t aFrameNumber, void* aPc, void* aSp,
void* aClosure) {
@ -162,11 +154,6 @@ class StackTrace : public phc::StackTrace {
st->mLength++;
MOZ_ASSERT(st->mLength == aFrameNumber);
}
// There are some rare cases (see FillSkipped's call sites) where we want to
// get a stack trace but cannot do so safely. When this field is set it
// indicates such a stack trace.
bool mSkipped;
};
// WARNING WARNING WARNING: this function must only be called when GMut::sMutex
@ -190,7 +177,6 @@ class StackTrace : public phc::StackTrace {
//
void StackTrace::Fill() {
mLength = 0;
mSkipped = false;
#if defined(XP_WIN) && defined(_M_IX86)
// This avoids MozStackWalk(), which causes unusably slow startup on Win32
@ -558,16 +544,16 @@ class GMut {
size_t mUsableSize;
// The allocation stack.
// - NeverAllocated: empty.
// - InUse: non-empty.
// - Freed: non-empty.
StackTrace mAllocStack;
// - NeverAllocated: Nothing.
// - InUse: Some.
// - Freed: Some.
Maybe<StackTrace> mAllocStack;
// The free stack.
// - NeverAllocated: empty.
// - InUse: empty.
// - Freed: non-empty.
StackTrace mFreeStack;
// - NeverAllocated: Nothing.
// - InUse: Some.
// - Freed: Some.
Maybe<StackTrace> mFreeStack;
// The time at which the page is available for reuse, as measured against
// GAtomic::sNow. When the page is in use this value will be kMaxTime.
@ -620,8 +606,8 @@ class GMut {
page.mState = PageState::InUse;
page.mArenaId = aArenaId;
page.mUsableSize = aUsableSize;
page.mAllocStack = aAllocStack;
page.mFreeStack.Clear();
page.mAllocStack = Some(aAllocStack);
page.mFreeStack = Nothing();
page.mReuseTime = kMaxTime;
}
@ -641,7 +627,7 @@ class GMut {
page.mUsableSize = aNewUsableSize;
// We could just keep the original alloc stack, but the realloc stack is
// more recent and therefore seems more useful.
page.mAllocStack = aAllocStack;
page.mAllocStack = Some(aAllocStack);
// page.mFreeStack is not changed.
// page.mReuseTime is not changed.
};
@ -667,7 +653,7 @@ class GMut {
// page.mAllocStack is left unchanged, for reporting on UAF.
page.mFreeStack = aFreeStack;
page.mFreeStack = Some(aFreeStack);
page.mReuseTime = GAtomic::Now() + aReuseDelay;
}
@ -776,8 +762,8 @@ class GMut {
MOZ_ASSERT(aPage.mState == PageState::InUse);
// There is nothing to assert about aPage.mArenaId.
MOZ_ASSERT(aPage.mUsableSize > 0);
MOZ_ASSERT(!aPage.mAllocStack.IsEmpty());
MOZ_ASSERT(aPage.mFreeStack.IsEmpty());
MOZ_ASSERT(aPage.mAllocStack.isSome());
MOZ_ASSERT(aPage.mFreeStack.isNothing());
MOZ_ASSERT(aPage.mReuseTime == kMaxTime);
}
@ -789,8 +775,8 @@ class GMut {
MOZ_ASSERT(isFresh || aPage.mState == PageState::Freed);
MOZ_ASSERT_IF(isFresh, aPage.mArenaId == Nothing());
MOZ_ASSERT(isFresh == (aPage.mUsableSize == 0));
MOZ_ASSERT(isFresh == (aPage.mAllocStack.IsEmpty()));
MOZ_ASSERT(isFresh == (aPage.mFreeStack.IsEmpty()));
MOZ_ASSERT(isFresh == (aPage.mAllocStack.isNothing()));
MOZ_ASSERT(isFresh == (aPage.mFreeStack.isNothing()));
MOZ_ASSERT(aPage.mReuseTime != kMaxTime);
#endif
}
@ -1023,8 +1009,7 @@ MOZ_ALWAYS_INLINE static void* PageRealloc(const Maybe<arena_id_t>& aArenaId,
// Get the stack trace *before* locking the mutex.
StackTrace stack;
if (GTls::IsDisabledOnCurrentThread()) {
// PHC is disabled on this thread. Get a dummy stack.
stack.FillSkipped();
// PHC is disabled on this thread. Leave the stack empty.
} else {
// Disable on this thread *before* getting the stack trace.
disable.emplace();
@ -1097,8 +1082,7 @@ MOZ_ALWAYS_INLINE static void PageFree(const Maybe<arena_id_t>& aArenaId,
// Get the stack trace *before* locking the mutex.
StackTrace freeStack;
if (GTls::IsDisabledOnCurrentThread()) {
// PHC is disabled on this thread. Get a dummy stack.
freeStack.FillSkipped();
// PHC is disabled on this thread. Leave the stack empty.
} else {
// Disable on this thread *before* getting the stack trace.
disable.emplace();
@ -1153,7 +1137,7 @@ static size_t replace_malloc_usable_size(usable_ptr_t aPtr) {
MutexAutoLock lock(GMut::sMutex);
// Check for malloc_usable_size() of a freed block.
gMut->EnsureInUse(lock, aPtr, *i);
gMut->EnsureInUse(lock, const_cast<void*>(aPtr), *i);
return gMut->PageUsableSize(lock, *i);
}

Просмотреть файл

@ -8,13 +8,16 @@
#define PHC_h
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include <stdint.h>
#include <stdlib.h>
namespace mozilla {
namespace phc {
// Note: a more compact stack trace representation could be achieved with
// Note: a stack trace may have no frames due to a collection problem.
//
// Also note: a more compact stack trace representation could be achieved with
// some effort.
struct StackTrace {
public:
@ -70,8 +73,8 @@ class AddrInfo {
// The allocation and free stack traces of the containing PHC allocation, if
// there is one.
StackTrace mAllocStack;
StackTrace mFreeStack;
mozilla::Maybe<StackTrace> mAllocStack;
mozilla::Maybe<StackTrace> mFreeStack;
// Default to no PHC info.
AddrInfo()

Просмотреть файл

@ -16,10 +16,10 @@ bool PHCInfoEq(phc::AddrInfo& aInfo, phc::AddrInfo::Kind aKind, void* aBaseAddr,
return aInfo.mKind == aKind && aInfo.mBaseAddr == aBaseAddr &&
aInfo.mUsableSize == aUsableSize &&
// Proper stack traces will have at least 3 elements.
(aHasAllocStack ? (aInfo.mAllocStack.mLength > 2)
: (aInfo.mAllocStack.mLength == 0)) &&
(aHasFreeStack ? (aInfo.mFreeStack.mLength > 2)
: (aInfo.mFreeStack.mLength == 0));
(aHasAllocStack ? (aInfo.mAllocStack->mLength > 2)
: (aInfo.mAllocStack.isNothing())) &&
(aHasFreeStack ? (aInfo.mFreeStack->mLength > 2)
: (aInfo.mFreeStack.isNothing()));
}
bool JeInfoEq(jemalloc_ptr_info_t& aInfo, PtrInfoTag aTag, void* aAddr,
@ -70,7 +70,7 @@ TEST(PHC, TestPHCBasics)
ASSERT_TRUE(ReplaceMalloc::IsPHCAllocation(p, &phcInfo));
ASSERT_TRUE(
PHCInfoEq(phcInfo, phc::AddrInfo::Kind::InUsePage, p, 32ul, true, false));
ASSERT_EQ(malloc_usable_size(p), 32ul);
ASSERT_EQ(moz_malloc_usable_size(p), 32ul);
jemalloc_ptr_info(p, &jeInfo);
ASSERT_TRUE(JeInfoEq(jeInfo, TagLiveAlloc, p, 32, 0));
@ -78,7 +78,7 @@ TEST(PHC, TestPHCBasics)
ASSERT_TRUE(ReplaceMalloc::IsPHCAllocation(p + 10, &phcInfo));
ASSERT_TRUE(
PHCInfoEq(phcInfo, phc::AddrInfo::Kind::InUsePage, p, 32ul, true, false));
ASSERT_EQ(malloc_usable_size(p), 32ul);
ASSERT_EQ(moz_malloc_usable_size(p), 32ul);
jemalloc_ptr_info(p + 10, &jeInfo);
ASSERT_TRUE(JeInfoEq(jeInfo, TagLiveAlloc, p, 32, 0));

Просмотреть файл

@ -23,7 +23,7 @@
# Please follow the existing prefs naming convention when considering adding a
# new pref, and don't create a new pref group unless it's appropriate and there
# are likely to be multiple prefs within that group. (If you do, you'll need to
# update the `groups` variable in modules/libpref/moz.build.)
# update the `pref_groups` variable in modules/libpref/moz.build.)
#
# Definitions
# -----------
@ -974,6 +974,99 @@
mirror: always
#endif
#---------------------------------------------------------------------------
# Prefs starting with "content."
#---------------------------------------------------------------------------
# Back off timer notification after count.
# -1 means never.
- name: content.notify.backoffcount
type: int32_t
value: -1
mirror: always
# Notification interval in microseconds.
# The notification interval has a dramatic effect on how long it takes to
# initially display content for slow connections. The current value
# provides good incremental display of content without causing an increase
# in page load time. If this value is set below 1/10 of a second it starts
# to impact page load performance.
# See bugzilla bug 72138 for more info.
- name: content.notify.interval
type: int32_t
value: 120000
mirror: always
# Do we notify based on time?
- name: content.notify.ontimer
type: bool
value: true
mirror: always
# How many times to deflect in interactive mode.
- name: content.sink.interactive_deflect_count
type: int32_t
value: 0
mirror: always
# How many times to deflect in perf mode.
- name: content.sink.perf_deflect_count
type: int32_t
value: 200
mirror: always
# Parse mode for handling pending events.
# 0 = don't check for pending events
# 1 = don't deflect if there are pending events
# 2 = bail if there are pending events
- name: content.sink.pending_event_mode
type: int32_t
# ifdef XP_WIN
value: 1
# else
value: 0
# endif
mirror: always
# How often to probe for pending events. 1 = every token.
- name: content.sink.event_probe_rate
type: int32_t
value: 1
mirror: always
# How long to stay off the event loop in interactive mode.
- name: content.sink.interactive_parse_time
type: int32_t
value: 3000
mirror: always
# How long to stay off the event loop in perf mode.
- name: content.sink.perf_parse_time
type: int32_t
value: 360000
mirror: always
# How long to be in interactive mode after an event.
- name: content.sink.interactive_time
type: uint32_t
value: 750000
mirror: always
# How long to stay in perf mode after initial loading.
- name: content.sink.initial_perf_time
type: uint32_t
value: 2000000
mirror: always
# Should we switch between perf-mode and interactive-mode?
# 0 = Switch
# 1 = Interactive mode
# 2 = Perf mode
- name: content.sink.enable_perf_mode
type: int32_t
value: 0
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "device."
#---------------------------------------------------------------------------

Просмотреть файл

@ -1117,11 +1117,6 @@ pref("dom.use_components_shim", false);
pref("dom.use_components_shim", true);
#endif // NIGHTLY_BUILD
// Parsing perf prefs. For now just mimic what the old code did.
#ifndef XP_WIN
pref("content.sink.pending_event_mode", 0);
#endif
// Disable popups from plugins by default
// 0 = openAllowed
// 1 = openControlled

Просмотреть файл

@ -32,6 +32,7 @@ pref_groups = [
'canvas',
'channelclassifier',
'clipboard',
'content',
'device',
'devtools',
'dom',

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozAutoDocUpdate.h"
#include "mozilla/IdleTaskRunner.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_content.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/StaticPrefs_view_source.h"
#include "mozilla/css/Loader.h"
@ -315,9 +316,10 @@ void nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync() {
&BackgroundFlushCallback,
"nsHtml5TreeOpExecutor::BackgroundFlushCallback",
250, // The hard deadline: 250ms.
nsContentSink::sInteractiveParseTime / 1000, // Required budget.
true, // repeating
[] { return false; }); // MayStopProcessing
StaticPrefs::content_sink_interactive_parse_time() /
1000, // Required budget.
true, // repeating
[] { return false; }); // MayStopProcessing
}
}

Просмотреть файл

@ -0,0 +1,2 @@
[multicol-breaking-nobackground-000.html]
prefs: [layout.css.column-span.enabled:true]

Просмотреть файл

@ -0,0 +1,2 @@
[multicol-breaking-nobackground-001.html]
prefs: [layout.css.column-span.enabled:true]

Просмотреть файл

@ -0,0 +1,2 @@
[multicol-rule-nested-balancing-001.html]
prefs: [layout.css.column-span.enabled:true]

Просмотреть файл

@ -0,0 +1,2 @@
[multicol-rule-nested-balancing-002.html]
prefs: [layout.css.column-span.enabled:true]

Просмотреть файл

@ -0,0 +1,2 @@
[multicol-span-all-rule-001.html]
prefs: [layout.css.column-span.enabled:true]

Просмотреть файл

@ -1,19 +0,0 @@
[event-handler-all-document-element-events.svg]
[oncut: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncut: the content attribute must execute when an event is dispatched]
expected: FAIL
[oncopy: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncopy: the content attribute must execute when an event is dispatched]
expected: FAIL
[onpaste: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[onpaste: the content attribute must execute when an event is dispatched]
expected: FAIL

Просмотреть файл

@ -52,7 +52,7 @@
<div class="outer">
<div class="blueborders"></div>
<div class="innerbg" style="left: 0"></div>
<div class="inner lefthalf" style="left: 0; height: 60px">
<div class="inner lefthalf" style="left: 0">
AAAAA<br>
BBBBB<br>
CCCCC

Просмотреть файл

@ -5,6 +5,7 @@
<link rel="author" title="Mozilla" href="https://mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-breaking-000-ref.html">
<style>

Просмотреть файл

@ -67,7 +67,7 @@
JJJJJ
</div>
<div class="innerbg" style="left: 204px"></div>
<div class="inner lefthalf" style="left: 204px; height: 80px">
<div class="inner lefthalf" style="left: 204px">
KKKKK<br>
LLLLL<br>
MMMMM<br>

Просмотреть файл

@ -5,6 +5,7 @@
<link rel="author" title="Mozilla" href="https://mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-breaking-001-ref.html">
<style>

Просмотреть файл

@ -77,7 +77,7 @@
</div>
<div class="border-bottom" style="left: 0"></div>
<div class="innerbg" style="left: 204px"></div>
<div class="inner lefthalf" style="left: 204px; height: 80px">
<div class="inner lefthalf" style="left: 204px">
KKKKK<br>
LLLLL<br>
MMMMM<br>

Просмотреть файл

@ -6,6 +6,7 @@
<link rel="author" title="Mozilla" href="https://mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="help" href="https://drafts.csswg.org/css-break/#break-decoration">
<link rel="match" href="multicol-breaking-004-ref.html">
<style>

Просмотреть файл

@ -32,7 +32,7 @@
</style>
<div class="outer">
<div class="inner lefthalf" style="left: 0; height: 60px">
<div class="inner lefthalf" style="left: 0">
AAAAA<br>
BBBBB<br>
CCCCC

Просмотреть файл

@ -5,6 +5,7 @@
<link rel="author" title="Mozilla" href="https://mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-breaking-nobackground-000-ref.html">
<style>

Просмотреть файл

@ -46,7 +46,7 @@
IIIII<br>
JJJJJ
</div>
<div class="inner lefthalf" style="left: 204px; height: 80px">
<div class="inner lefthalf" style="left: 204px">
KKKKK<br>
LLLLL<br>
MMMMM<br>

Просмотреть файл

@ -5,6 +5,7 @@
<link rel="author" title="Mozilla" href="https://mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-breaking-nobackground-001-ref.html">
<style>

Просмотреть файл

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test Reference: Test the column rules' block-size with nested balancing multicol container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<style>
.outer {
column-count: 2;
column-rule: 6px solid black;
column-fill: auto;
width: 400px;
height: 250px;
}
.inner {
column-count: 2;
column-rule: 3px solid gray;
column-fill: auto;
height: 200px;
}
.outer-block {
background-color: lightgreen;
height: 200px;
}
.inner-block {
background-color: lightblue;
height: 150px;
}
.space {
height: 50px;
}
</style>
<article class="outer">
<div class="outer-block"></div>
<div class="space"></div>
<article class="inner">
<div class="inner-block"></div><div class="space"></div>
<div class="inner-block"></div><div class="space"></div>
</article>
</article>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test the column rules' block-size with nested balancing multicol container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#cf">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-gaps-and-rules">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-rule-nested-balancing-001-ref.html">
<meta name="assert" content="This test verifies that the column-rules are extended to the content block-end edges of their corresponding inner and outer multicol container.">
<style>
.outer {
column-count: 2;
column-rule: 6px solid black;
width: 400px;
height: 250px;
}
.inner {
column-count: 2;
column-rule: 3px solid gray;
height: 200px;
}
.outer-block {
background-color: lightgreen;
height: 200px;
}
.inner-block {
background-color: lightblue;
height: 300px;
}
</style>
<article class="outer">
<div class="outer-block"></div>
<article class="inner">
<div class="inner-block"></div>
</article>
</article>
</html>

Просмотреть файл

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test Reference: Test the column rules' block-size with nested balancing multicol container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<style>
.outer {
column-count: 2;
column-rule: 6px solid black;
column-fill: auto;
width: 400px;
height: 250px;
}
.inner {
column-count: 2;
column-rule: 3px solid gray;
column-fill: auto;
height: 200px;
}
.outer-block {
background-color: lightgreen;
height: 200px;
}
.inner-block {
background-color: lightblue;
height: 200px;
}
.space {
height: 50px;
}
</style>
<article class="outer">
<div class="outer-block"></div>
<div class="space"></div>
<article class="inner">
<div class="inner-block"></div>
<div class="inner-block"></div>
</article>
</article>
</html>

Просмотреть файл

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test the column rules' block-size with nested balancing multicol container</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#cf">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-gaps-and-rules">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-rule-nested-balancing-002-ref.html">
<meta name="assert" content="This test verifies that the column-rules are extended to the content block-end edges of their corresponding inner and outer multicol container, where the inner container has height: auto.">
<style>
.outer {
column-count: 2;
column-rule: 6px solid black;
width: 400px;
height: 250px;
}
.inner {
column-count: 2;
column-rule: 3px solid gray;
height: auto;
}
.outer-block {
background-color: lightgreen;
height: 200px;
}
.inner-block {
background-color: lightblue;
height: 400px;
}
</style>
<article class="outer">
<div class="outer-block"></div>
<article class="inner">
<div class="inner-block"></div>
</article>
</article>
</html>

Просмотреть файл

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test the column-rule's block-size</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<style>
article {
column-count: 2;
column-rule: 6px solid;
width: 400px;
height: 500px;
background-color: lightgreen;
border: 2em solid purple;
padding: 2em;
}
div.block {
width: 100px;
height: 200px;
}
div.column-span {
column-span: all;
height: 50px;
background-color: lightblue;
}
</style>
<article>
<div class="block">block1</div>
<div class="column-span">column-span1</div>
<div class="block">block2</div>
<div class="column-span">column-span2</div>
<div class="block" style="height: 400px;">block3</div>
</article>
</html>

Просмотреть файл

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<title>CSS Multi-column Layout Test: Test the column rule's block-size</title>
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
<link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-gaps-and-rules">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
<link rel="match" href="multicol-span-all-rule-001-ref.html">
<meta name="assert" content="This test verifies that the column-rule after the last column-span is extended to the content block-end edge of the multicol container.">
<style>
article {
column-count: 2;
column-rule: 6px solid;
width: 400px;
height: 500px;
background-color: lightgreen;
border: 2em solid purple;
padding: 2em;
}
div.block {
width: 100px;
height: 200px;
}
div.column-span {
column-span: all;
height: 50px;
background-color: lightblue;
}
</style>
<article>
<!-- Each block spreads its height evenly into two columns, and
each column contains 100px height. -->
<div class="block">block1</div>
<div class="column-span">column-span1</div>
<div class="block">block2</div>
<div class="column-span">column-span2</div>
<!-- The column rule after column-span2 should extend to the content edge
of the multicol container as if block3 has "height: 400px;" -->
<div class="block">block3</div>
</article>
</html>

Просмотреть файл

@ -929,11 +929,17 @@ LoginManagerPrompter.prototype = {
this.log("promptToSavePassword");
var notifyObj = this._getPopupNote();
if (notifyObj) {
this._showLoginCaptureDoorhanger(aLogin, "password-save", {
dismissed: this._inPrivateBrowsing || dismissed,
notifySaved,
extraAttr: notifySaved ? "attention" : "",
});
this._showLoginCaptureDoorhanger(
aLogin,
"password-save",
{
dismissed: this._inPrivateBrowsing || dismissed,
extraAttr: notifySaved ? "attention" : "",
},
{
notifySaved,
}
);
Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
} else {
this._showSaveLoginDialog(aLogin);
@ -949,8 +955,19 @@ LoginManagerPrompter.prototype = {
* @param {string} type
* This is "password-save" or "password-change" depending on the
* original notification type. This is used for telemetry and tests.
* @param {object} showOptions
* Options to pass along to PopupNotifications.show().
* @param {bool} [options.notifySaved = false]
* Whether to indicate to the user that the login was already saved.
* @param {string} [options.messageStringID = undefined]
* An optional string ID to override the default message.
*/
_showLoginCaptureDoorhanger(login, type, options = {}) {
_showLoginCaptureDoorhanger(
login,
type,
showOptions = {},
{ notifySaved = false, messageStringID } = {}
) {
let { browser } = this._getNotifyWindow();
if (!browser) {
return;
@ -975,6 +992,10 @@ LoginManagerPrompter.prototype = {
let initialMsgNames =
type == "password-save" ? saveMsgNames : changeMsgNames;
if (messageStringID) {
changeMsgNames.prompt = messageStringID;
}
let brandBundle = Services.strings.createBundle(BRAND_BUNDLE);
let brandShortName = brandBundle.GetStringFromName("brandShortName");
let host = this._getShortDisplayHost(login.origin);
@ -1293,11 +1314,11 @@ LoginManagerPrompter.prototype = {
return false;
},
},
options
showOptions
)
);
if (options.notifySaved) {
if (notifySaved) {
let notification = popupNote.getNotification(notificationID);
let anchor = notification.anchorElement;
anchor.ownerGlobal.ConfirmationHint.show(anchor, "passwordSaved");
@ -1437,11 +1458,31 @@ LoginManagerPrompter.prototype = {
login.formActionOrigin = aNewLogin.formActionOrigin;
login.password = aNewLogin.password;
login.username = aNewLogin.username;
this._showLoginCaptureDoorhanger(login, "password-change", {
dismissed,
notifySaved,
extraAttr: notifySaved ? "attention" : "",
});
let messageStringID;
if (
aOldLogin.username === "" &&
login.username !== "" &&
login.password == aOldLogin.password
) {
// If the saved password matches the password we're prompting with then we
// are only prompting to let the user add a username since there was one in
// the form. Change the message so the purpose of the prompt is clearer.
messageStringID = "updateLoginMsgAddUsername";
}
this._showLoginCaptureDoorhanger(
login,
"password-change",
{
dismissed,
extraAttr: notifySaved ? "attention" : "",
},
{
notifySaved,
messageStringID,
}
);
let oldGUID = aOldLogin.QueryInterface(Ci.nsILoginMetaInfo).guid;
Services.obs.notifyObservers(

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше