зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. r=merge a=merge on a CLOSED TREE
This commit is contained in:
Коммит
71f4a218d8
|
@ -41,7 +41,6 @@ module.exports = {
|
|||
"security/**",
|
||||
"testing/**",
|
||||
"tools/profiler/**",
|
||||
"xpcom/**"
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/use-services": "off",
|
||||
|
|
|
@ -1436,6 +1436,19 @@ GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc,
|
|||
return disp.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
AccessibleWrap::IsRootForHWND()
|
||||
{
|
||||
if (IsRoot()) {
|
||||
return true;
|
||||
}
|
||||
HWND thisHwnd = GetHWNDFor(this);
|
||||
AccessibleWrap* parent = static_cast<AccessibleWrap*>(Parent());
|
||||
MOZ_ASSERT(parent);
|
||||
HWND parentHwnd = GetHWNDFor(parent);
|
||||
return thisHwnd != parentHwnd;
|
||||
}
|
||||
|
||||
already_AddRefed<IAccessible>
|
||||
AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
|
||||
{
|
||||
|
@ -1484,8 +1497,9 @@ AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
|
|||
// Child indices (> 0) are handled below for both local and remote children.
|
||||
if (XRE_IsParentProcess() && !IsProxy() &&
|
||||
varChild.lVal < 0 && !sIDGen.IsChromeID(varChild.lVal)) {
|
||||
if (!IsRoot()) {
|
||||
// Bug 1422201: accChild with a remote id is only valid on the root accessible.
|
||||
if (!IsRootForHWND()) {
|
||||
// Bug 1422201, 1424657: accChild with a remote id is only valid on the
|
||||
// root accessible for an HWND.
|
||||
// Otherwise, we might return remote accessibles which aren't descendants
|
||||
// of this accessible. This would confuse clients which use accChild to
|
||||
// check whether something is a descendant of a document.
|
||||
|
|
|
@ -180,6 +180,12 @@ private:
|
|||
const LayoutDeviceIntRect& aCaretRect);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Determine whether this is the root accessible for its HWND.
|
||||
*/
|
||||
bool
|
||||
IsRootForHWND();
|
||||
|
||||
/**
|
||||
* Find an accessible by the given child ID in cached documents.
|
||||
*/
|
||||
|
|
|
@ -161,7 +161,7 @@ async function doTest(aBrowser) {
|
|||
let trackLoaded = false;
|
||||
|
||||
let audioListener = () => {
|
||||
audio.removeEventListener("canplaythrough", audioListener);
|
||||
audio.removeEventListener("suspend", audioListener);
|
||||
|
||||
audioLoaded = true;
|
||||
if (audioLoaded && trackLoaded) {
|
||||
|
@ -180,7 +180,7 @@ async function doTest(aBrowser) {
|
|||
|
||||
// Add the event listeners before everything in case we lose events.
|
||||
audioTrack.addEventListener("load", trackListener);
|
||||
audio.addEventListener("canplaythrough", audioListener);
|
||||
audio.addEventListener("suspend", audioListener);
|
||||
|
||||
// Assign attributes for the audio element.
|
||||
audioSource.setAttribute("src", audioURL + URLSuffix);
|
||||
|
@ -198,12 +198,12 @@ async function doTest(aBrowser) {
|
|||
// Append the video element into the body, and wait until it's finished.
|
||||
await new Promise(resolve => {
|
||||
let listener = () => {
|
||||
video.removeEventListener("canplaythrough", listener);
|
||||
video.removeEventListener("suspend", listener);
|
||||
resolve();
|
||||
};
|
||||
|
||||
// Add the event listener before everything in case we lose the event.
|
||||
video.addEventListener("canplaythrough", listener);
|
||||
video.addEventListener("suspend", listener);
|
||||
|
||||
// Assign attributes for the video element.
|
||||
video.setAttribute("src", videoURL + URLSuffix);
|
||||
|
|
|
@ -1888,11 +1888,11 @@ Function ShouldInstall64Bit
|
|||
|
||||
; Lenovo OneKey Theater can theoretically be in a directory other than this
|
||||
; one, because some installer versions let you change it, but it's unlikely.
|
||||
${If} ${FileExists} "C:\Program Files (x86)\Lenovo\Onekey Theater\windowsapihookdll64.dll"
|
||||
${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Onekey Theater\windowsapihookdll64.dll"
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
${If} ${FileExists} "C:\Program Files (x86)\Lenovo\Energy Management\Energy Management.exe"
|
||||
${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Energy Management\Energy Management.exe"
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
|
|
|
@ -420,6 +420,18 @@ void Elf::normalize()
|
|||
ehdr->e_shoff = shdr_section->getOffset();
|
||||
ehdr->e_entry = eh_entry.getValue();
|
||||
ehdr->e_shstrndx = eh_shstrndx->getIndex();
|
||||
|
||||
// Check sections consistency
|
||||
unsigned int minOffset = 0;
|
||||
for (ElfSection *section = ehdr; section != nullptr; section = section->getNext()) {
|
||||
unsigned int offset = section->getOffset();
|
||||
if (offset < minOffset) {
|
||||
throw std::runtime_error("Sections overlap");
|
||||
}
|
||||
if (section->getType() != SHT_NOBITS) {
|
||||
minOffset = offset + section->getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Elf::write(std::ofstream &file)
|
||||
|
|
|
@ -901,13 +901,14 @@ void undo_file(const char *name, bool backup = false)
|
|||
fprintf(stderr, "Not elfhacked. Skipping\n");
|
||||
return;
|
||||
}
|
||||
if (data != text->getNext()) {
|
||||
fprintf(stderr, elfhack_data " section not following " elfhack_text ". Skipping\n");
|
||||
|
||||
ElfSegment *first = data->getSegmentByType(PT_LOAD);
|
||||
ElfSegment *second = text->getSegmentByType(PT_LOAD);
|
||||
if (first != second) {
|
||||
fprintf(stderr, elfhack_data " and " elfhack_text " not in the same segment. Skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ElfSegment *first = elf.getSegmentByType(PT_LOAD);
|
||||
ElfSegment *second = elf.getSegmentByType(PT_LOAD, first);
|
||||
second = elf.getSegmentByType(PT_LOAD, first);
|
||||
ElfSegment *filler = nullptr;
|
||||
// If the second PT_LOAD is a filler from elfhack --fill, check the third.
|
||||
if (second->isElfHackFillerSegment()) {
|
||||
|
|
|
@ -421,6 +421,8 @@ public:
|
|||
file.write(data, getSize());
|
||||
}
|
||||
|
||||
ElfSegment *getSegmentByType(unsigned int type);
|
||||
|
||||
private:
|
||||
friend class ElfSegment;
|
||||
|
||||
|
@ -433,8 +435,6 @@ private:
|
|||
segments.erase(i, i + 1);
|
||||
}
|
||||
|
||||
ElfSegment *getSegmentByType(unsigned int type);
|
||||
|
||||
void insertInSegments(std::vector<ElfSegment *> &segs);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -9,8 +9,14 @@
|
|||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { debugLocalAddon, debugRemoteAddon, isTemporaryID, parseFileUri, uninstallAddon } =
|
||||
require("../../modules/addon");
|
||||
const {
|
||||
debugLocalAddon,
|
||||
debugRemoteAddon,
|
||||
isLegacyTemporaryExtension,
|
||||
isTemporaryID,
|
||||
parseFileUri,
|
||||
uninstallAddon
|
||||
} = require("../../modules/addon");
|
||||
const Services = require("Services");
|
||||
|
||||
loader.lazyImporter(this, "BrowserToolboxProcess",
|
||||
|
@ -24,6 +30,7 @@ const Strings = Services.strings.createBundle(
|
|||
|
||||
const TEMP_ID_URL = "https://developer.mozilla.org/Add-ons" +
|
||||
"/WebExtensions/WebExtensions_and_the_Add-on_ID";
|
||||
const LEGACY_WARNING_URL = "https://wiki.mozilla.org/Add-ons/Future_of_Bootstrap";
|
||||
|
||||
function filePathForTarget(target) {
|
||||
// Only show file system paths, and only for temporarily installed add-ons.
|
||||
|
@ -90,7 +97,7 @@ function internalIDForTarget(target) {
|
|||
|
||||
function showMessages(target) {
|
||||
const messages = [
|
||||
...warningMessages(target.warnings),
|
||||
...warningMessages(target),
|
||||
...infoMessages(target),
|
||||
];
|
||||
if (messages.length > 0) {
|
||||
|
@ -112,15 +119,37 @@ function infoMessages(target) {
|
|||
Strings.GetStringFromName("temporaryID.learnMore")
|
||||
)));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
function warningMessages(warnings = []) {
|
||||
return warnings.map((warning) => {
|
||||
function warningMessages(target) {
|
||||
let messages = [];
|
||||
|
||||
if (isLegacyTemporaryExtension(target.form)) {
|
||||
messages.push(dom.li(
|
||||
{
|
||||
className: "addon-target-warning-message addon-target-message"
|
||||
},
|
||||
Strings.GetStringFromName("legacyExtensionWarning"),
|
||||
" ",
|
||||
dom.a(
|
||||
{
|
||||
href: LEGACY_WARNING_URL,
|
||||
target: "_blank"
|
||||
},
|
||||
Strings.GetStringFromName("legacyExtensionWarning.learnMore"))
|
||||
));
|
||||
}
|
||||
|
||||
let warnings = target.warnings || [];
|
||||
messages = messages.concat(warnings.map((warning) => {
|
||||
return dom.li(
|
||||
{ className: "addon-target-warning-message addon-target-message" },
|
||||
warning);
|
||||
});
|
||||
}));
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
class AddonTarget extends Component {
|
||||
|
|
|
@ -81,6 +81,19 @@ exports.isTemporaryID = function (addonID) {
|
|||
return AddonManagerPrivate.isTemporaryInstallID(addonID);
|
||||
};
|
||||
|
||||
exports.isLegacyTemporaryExtension = function (addonForm) {
|
||||
if (!addonForm.type) {
|
||||
// If about:debugging is connected to an older then 59 remote Firefox, and type is
|
||||
// not available on the addon/webextension actors, return false to avoid showing
|
||||
// irrelevant warning messages.
|
||||
return false;
|
||||
}
|
||||
return addonForm.type == "extension" &&
|
||||
addonForm.temporarilyInstalled &&
|
||||
!addonForm.isWebExtension &&
|
||||
!addonForm.isAPIExtension;
|
||||
};
|
||||
|
||||
exports.parseFileUri = function (url) {
|
||||
// Strip a leading slash from Windows drive letter URIs.
|
||||
// file:///home/foo ~> /home/foo
|
||||
|
|
|
@ -520,7 +520,7 @@ MarkupView.prototype = {
|
|||
}
|
||||
|
||||
let parent = target, container;
|
||||
while (parent !== this.doc.body) {
|
||||
while (parent) {
|
||||
if (parent.container) {
|
||||
container = parent.container;
|
||||
break;
|
||||
|
|
|
@ -106,6 +106,15 @@ temporaryID = This WebExtension has a temporary ID.
|
|||
# the user to MDN.
|
||||
temporaryID.learnMore = Learn more
|
||||
|
||||
# LOCALIZATION NOTE (legacyExtensionWarning):
|
||||
# This string is displayed as a warning message when loading a temporary legacy extension.
|
||||
legacyExtensionWarning = This is a legacy extension, be aware that these are no longer fully supported. Please read the linked documentation and then proceed with caution.
|
||||
|
||||
# LOCALIZATION NOTE (temporaryID.learnMore):
|
||||
# This string is displayed as a link next to the legacyExtensionWarning message and leads
|
||||
# the user to https://wiki.mozilla.org/Add-ons/Future_of_Bootstrap.
|
||||
legacyExtensionWarning.learnMore = Learn more
|
||||
|
||||
# LOCALIZATION NOTE (selectAddonFromFile2):
|
||||
# This string is displayed as the title of the file picker that appears when
|
||||
# the user clicks the 'Load Temporary Add-on' button
|
||||
|
|
|
@ -85,6 +85,9 @@ BrowserAddonActor.prototype = {
|
|||
iconURL: this._addon.iconURL,
|
||||
debuggable: this._addon.isDebuggable,
|
||||
temporarilyInstalled: this._addon.temporarilyInstalled,
|
||||
type: this._addon.type,
|
||||
isWebExtension: this._addon.isWebExtension,
|
||||
isAPIExtension: this._addon.isAPIExtension,
|
||||
consoleActor: this._consoleActor.actorID,
|
||||
|
||||
traits: {
|
||||
|
|
|
@ -73,7 +73,9 @@ const WebExtensionParentActor = protocol.ActorClassWithSpec(webExtensionSpec, {
|
|||
iconURL: this.addon.iconURL,
|
||||
debuggable: this.addon.isDebuggable,
|
||||
temporarilyInstalled: this.addon.temporarilyInstalled,
|
||||
isWebExtension: true,
|
||||
type: this.addon.type,
|
||||
isWebExtension: this.addon.isWebExtension,
|
||||
isAPIExtension: this.addon.isAPIExtension,
|
||||
manifestURL: policy && policy.getURL("manifest.json"),
|
||||
warnings: ExtensionParent.DebugUtils.getExtensionManifestWarnings(this.id),
|
||||
};
|
||||
|
|
|
@ -146,7 +146,7 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
|||
MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
|
||||
MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
|
||||
JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(errorNumber),
|
||||
static_cast<unsigned>(errorNumber),
|
||||
funcNameStr.get(), ifaceName.get());
|
||||
return false;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ TErrorResult<CleanupPolicy>::SetPendingExceptionWithMessage(JSContext* aCx)
|
|||
args[argCount] = nullptr;
|
||||
|
||||
JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(message->mErrorNumber),
|
||||
static_cast<unsigned>(message->mErrorNumber),
|
||||
argCount > 0 ? args : nullptr);
|
||||
|
||||
ClearMessage();
|
||||
|
|
|
@ -159,13 +159,4 @@ BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseMediaResource::DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset)
|
||||
{
|
||||
if (aNumBytes <= 0) {
|
||||
return;
|
||||
}
|
||||
mCallback->NotifyBytesConsumed(aNumBytes, aOffset);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -133,10 +133,6 @@ protected:
|
|||
// then the request is added back to the load group.
|
||||
void ModifyLoadFlags(nsLoadFlags aFlags);
|
||||
|
||||
// Dispatches an event to call MediaDecoder::NotifyBytesConsumed(aNumBytes, aOffset)
|
||||
// on the main thread. This is called automatically after every read.
|
||||
void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset);
|
||||
|
||||
RefPtr<MediaResourceCallback> mCallback;
|
||||
|
||||
// Channel used to download the media data. Must be accessed
|
||||
|
|
|
@ -170,30 +170,11 @@ ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged(
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
|
||||
int64_t aOffset)
|
||||
{
|
||||
RefPtr<ResourceCallback> self = this;
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||
"ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed",
|
||||
[=]() {
|
||||
if (self->mDecoder) {
|
||||
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
|
||||
}
|
||||
});
|
||||
mAbstractMainThread->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
|
||||
: MediaDecoder(aInit)
|
||||
, mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
|
||||
, mWatchManager(this, aInit.mOwner->AbstractMainThread())
|
||||
{
|
||||
mResourceCallback->Connect(this);
|
||||
|
||||
// mIgnoreProgressData
|
||||
mWatchManager.Watch(mLogicallySeeking, &ChannelMediaDecoder::SeekingChanged);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -260,7 +241,6 @@ MediaDecoderStateMachine* ChannelMediaDecoder::CreateStateMachine()
|
|||
void
|
||||
ChannelMediaDecoder::Shutdown()
|
||||
{
|
||||
mWatchManager.Shutdown();
|
||||
mResourceCallback->Disconnect();
|
||||
MediaDecoder::Shutdown();
|
||||
|
||||
|
@ -335,7 +315,17 @@ ChannelMediaDecoder::NotifyDownloadEnded(nsresult aStatus)
|
|||
|
||||
MediaDecoderOwner* owner = GetOwner();
|
||||
if (NS_SUCCEEDED(aStatus) || aStatus == NS_BASE_STREAM_CLOSED) {
|
||||
UpdatePlaybackRate(ComputePlaybackRate());
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableFunction("ChannelMediaDecoder::UpdatePlaybackRate", [
|
||||
stats = mPlaybackStatistics,
|
||||
res = RefPtr<BaseMediaResource>(mResource),
|
||||
duration = mDuration
|
||||
]() {
|
||||
auto rate = ComputePlaybackRate(stats, res, duration);
|
||||
UpdatePlaybackRate(rate, res);
|
||||
});
|
||||
nsresult rv = GetStateMachine()->OwnerThread()->Dispatch(r.forget());
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
owner->DownloadSuspended();
|
||||
// NotifySuspendedStatusChanged will tell the element that download
|
||||
// has been suspended "by the cache", which is true since we never
|
||||
|
@ -349,36 +339,11 @@ ChannelMediaDecoder::NotifyDownloadEnded(nsresult aStatus)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
||||
AbstractThread::AutoEnter context(AbstractMainThread());
|
||||
|
||||
if (mIgnoreProgressData) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(GetStateMachine());
|
||||
mDecoderPosition = aOffset + aBytes;
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::SeekingChanged()
|
||||
{
|
||||
// Stop updating the bytes downloaded for progress notifications when
|
||||
// seeking to prevent wild changes to the progress notification.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mIgnoreProgressData = mLogicallySeeking;
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelMediaDecoder::CanPlayThroughImpl()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(GetStateMachine(), false);
|
||||
return GetStatistics(ComputePlaybackRate()).CanPlayThrough();
|
||||
return mCanPlayThrough;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -423,7 +388,17 @@ ChannelMediaDecoder::DurationChanged()
|
|||
AbstractThread::AutoEnter context(AbstractMainThread());
|
||||
MediaDecoder::DurationChanged();
|
||||
// Duration has changed so we should recompute playback rate
|
||||
UpdatePlaybackRate(ComputePlaybackRate());
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableFunction("ChannelMediaDecoder::UpdatePlaybackRate", [
|
||||
stats = mPlaybackStatistics,
|
||||
res = RefPtr<BaseMediaResource>(mResource),
|
||||
duration = mDuration
|
||||
]() {
|
||||
auto rate = ComputePlaybackRate(stats, res, duration);
|
||||
UpdatePlaybackRate(rate, res);
|
||||
});
|
||||
nsresult rv = GetStateMachine()->OwnerThread()->Dispatch(r.forget());
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -431,36 +406,59 @@ ChannelMediaDecoder::DownloadProgressed()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
||||
AbstractThread::AutoEnter context(AbstractMainThread());
|
||||
GetOwner()->DownloadProgressed();
|
||||
auto rate = ComputePlaybackRate();
|
||||
UpdatePlaybackRate(rate);
|
||||
MediaStatistics stats = GetStatistics(rate);
|
||||
GetStateMachine()->DispatchCanPlayThrough(stats.CanPlayThrough());
|
||||
mResource->ThrottleReadahead(ShouldThrottleDownload(stats));
|
||||
|
||||
using StatsPromise = MozPromise<MediaStatistics, bool, true>;
|
||||
InvokeAsync(GetStateMachine()->OwnerThread(),
|
||||
__func__,
|
||||
[
|
||||
playbackStats = mPlaybackStatistics,
|
||||
res = RefPtr<BaseMediaResource>(mResource),
|
||||
duration = mDuration,
|
||||
pos = mPlaybackPosition
|
||||
]() {
|
||||
auto rate = ComputePlaybackRate(playbackStats, res, duration);
|
||||
UpdatePlaybackRate(rate, res);
|
||||
MediaStatistics stats = GetStatistics(rate, res, pos);
|
||||
return StatsPromise::CreateAndResolve(stats, __func__);
|
||||
})
|
||||
->Then(
|
||||
mAbstractMainThread,
|
||||
__func__,
|
||||
[ =, self = RefPtr<ChannelMediaDecoder>(this) ](MediaStatistics aStats) {
|
||||
if (IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
mCanPlayThrough = aStats.CanPlayThrough();
|
||||
GetStateMachine()->DispatchCanPlayThrough(mCanPlayThrough);
|
||||
mResource->ThrottleReadahead(ShouldThrottleDownload(aStats));
|
||||
AbstractThread::AutoEnter context(AbstractMainThread());
|
||||
GetOwner()->DownloadProgressed();
|
||||
},
|
||||
[]() { MOZ_ASSERT_UNREACHABLE("Promise not resolved"); });
|
||||
}
|
||||
|
||||
ChannelMediaDecoder::PlaybackRateInfo
|
||||
ChannelMediaDecoder::ComputePlaybackRate()
|
||||
/* static */ ChannelMediaDecoder::PlaybackRateInfo
|
||||
ChannelMediaDecoder::ComputePlaybackRate(const MediaChannelStatistics& aStats,
|
||||
BaseMediaResource* aResource,
|
||||
double aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mResource);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
int64_t length = mResource->GetLength();
|
||||
if (mozilla::IsFinite<double>(mDuration) && mDuration > 0 && length >= 0) {
|
||||
return { uint32_t(length / mDuration), true };
|
||||
int64_t length = aResource->GetLength();
|
||||
if (mozilla::IsFinite<double>(aDuration) && aDuration > 0 && length >= 0) {
|
||||
return { uint32_t(length / aDuration), true };
|
||||
}
|
||||
|
||||
bool reliable = false;
|
||||
uint32_t rate = mPlaybackStatistics.GetRate(&reliable);
|
||||
uint32_t rate = aStats.GetRate(&reliable);
|
||||
return { rate, reliable };
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::UpdatePlaybackRate(const PlaybackRateInfo& aInfo)
|
||||
/* static */ void
|
||||
ChannelMediaDecoder::UpdatePlaybackRate(const PlaybackRateInfo& aInfo,
|
||||
BaseMediaResource* aResource)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mResource);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
uint32_t rate = aInfo.mRate;
|
||||
|
||||
|
@ -473,23 +471,23 @@ ChannelMediaDecoder::UpdatePlaybackRate(const PlaybackRateInfo& aInfo)
|
|||
rate = std::max(rate, 10000u);
|
||||
}
|
||||
|
||||
mResource->SetPlaybackRate(rate);
|
||||
aResource->SetPlaybackRate(rate);
|
||||
}
|
||||
|
||||
MediaStatistics
|
||||
ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo)
|
||||
/* static */ MediaStatistics
|
||||
ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo,
|
||||
BaseMediaResource* aRes,
|
||||
int64_t aPlaybackPosition)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mResource);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
MediaStatistics result;
|
||||
result.mDownloadRate =
|
||||
mResource->GetDownloadRate(&result.mDownloadRateReliable);
|
||||
result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
|
||||
result.mTotalBytes = mResource->GetLength();
|
||||
result.mDownloadRate = aRes->GetDownloadRate(&result.mDownloadRateReliable);
|
||||
result.mDownloadPosition = aRes->GetCachedDataEnd(aPlaybackPosition);
|
||||
result.mTotalBytes = aRes->GetLength();
|
||||
result.mPlaybackRate = aInfo.mRate;
|
||||
result.mPlaybackRateReliable = aInfo.mReliable;
|
||||
result.mPlaybackPosition = mPlaybackPosition;
|
||||
result.mPlaybackPosition = aPlaybackPosition;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ class ChannelMediaDecoder
|
|||
void NotifyDataEnded(nsresult aStatus) override;
|
||||
void NotifyPrincipalChanged() override;
|
||||
void NotifySuspendedStatusChanged(bool aSuspendedByCache) override;
|
||||
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
|
||||
|
||||
static void TimerCallback(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
|
@ -121,8 +120,6 @@ private:
|
|||
// by the MediaResource read functions.
|
||||
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
|
||||
|
||||
void SeekingChanged();
|
||||
|
||||
bool CanPlayThroughImpl() override final;
|
||||
|
||||
bool IsLiveStream() override final;
|
||||
|
@ -133,28 +130,26 @@ private:
|
|||
bool mReliable; // True if mRate is a reliable estimate.
|
||||
};
|
||||
// The actual playback rate computation.
|
||||
PlaybackRateInfo ComputePlaybackRate();
|
||||
static PlaybackRateInfo ComputePlaybackRate(
|
||||
const MediaChannelStatistics& aStats,
|
||||
BaseMediaResource* aResource,
|
||||
double aDuration);
|
||||
|
||||
// Something has changed that could affect the computed playback rate,
|
||||
// so recompute it.
|
||||
void UpdatePlaybackRate(const PlaybackRateInfo& aInfo);
|
||||
static void UpdatePlaybackRate(const PlaybackRateInfo& aInfo,
|
||||
BaseMediaResource* aResource);
|
||||
|
||||
// Return statistics. This is used for progress events and other things.
|
||||
// This can be called from any thread. It's only a snapshot of the
|
||||
// current state, since other threads might be changing the state
|
||||
// at any time.
|
||||
MediaStatistics GetStatistics(const PlaybackRateInfo& aInfo);
|
||||
static MediaStatistics GetStatistics(const PlaybackRateInfo& aInfo,
|
||||
BaseMediaResource* aRes,
|
||||
int64_t aPlaybackPosition);
|
||||
|
||||
bool ShouldThrottleDownload(const MediaStatistics& aStats);
|
||||
|
||||
WatchManager<ChannelMediaDecoder> mWatchManager;
|
||||
|
||||
// True when seeking or otherwise moving the play position around in
|
||||
// such a manner that progress event data is inaccurate. This is set
|
||||
// during seek and duration operations to prevent the progress indicator
|
||||
// from jumping around. Read/Write on the main thread only.
|
||||
bool mIgnoreProgressData = false;
|
||||
|
||||
// Data needed to estimate playback data rate. The timeline used for
|
||||
// this estimate is "decode time" (where the "current time" is the
|
||||
// time of the last decoded video frame).
|
||||
|
@ -169,6 +164,8 @@ private:
|
|||
// during decoder seek operations, but it's updated at the end when we
|
||||
// start playing back again.
|
||||
int64_t mPlaybackPosition = 0;
|
||||
|
||||
bool mCanPlayThrough = false;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -621,12 +621,7 @@ nsresult ChannelMediaResource::ReadAt(int64_t aOffset,
|
|||
uint32_t* aBytes)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
|
||||
nsresult rv = mCacheStream.ReadAt(aOffset, aBuffer, aCount, aBytes);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DispatchBytesConsumed(*aBytes, aOffset);
|
||||
}
|
||||
return rv;
|
||||
return mCacheStream.ReadAt(aOffset, aBuffer, aCount, aBytes);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -778,8 +773,7 @@ ChannelMediaResource::RecreateChannel()
|
|||
void
|
||||
ChannelMediaResource::CacheClientNotifyDataReceived()
|
||||
{
|
||||
SystemGroup::Dispatch(
|
||||
TaskCategory::Other,
|
||||
mCallback->AbstractMainThread()->Dispatch(
|
||||
NewRunnableMethod("MediaResourceCallback::NotifyDataArrived",
|
||||
mCallback.get(),
|
||||
&MediaResourceCallback::NotifyDataArrived));
|
||||
|
|
|
@ -171,9 +171,6 @@ FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
rv = UnsafeRead(aBuffer, aCount, aBytes);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DispatchBytesConsumed(*aBytes, aOffset);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -2436,7 +2436,7 @@ MediaCacheStream::GetNextCachedData(int64_t aOffset)
|
|||
int64_t
|
||||
MediaCacheStream::GetCachedDataEnd(int64_t aOffset)
|
||||
{
|
||||
// TODO: Assert non-main thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
AutoLock lock(mMediaCache->Monitor());
|
||||
return GetCachedDataEndInternal(lock, aOffset);
|
||||
}
|
||||
|
@ -2542,18 +2542,14 @@ MediaCacheStream::SetReadMode(ReadMode aMode)
|
|||
void
|
||||
MediaCacheStream::SetPlaybackRate(uint32_t aBytesPerSecond)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aBytesPerSecond > 0, "Zero playback rate not allowed");
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||
"MediaCacheStream::SetPlaybackRate",
|
||||
[ =, client = RefPtr<ChannelMediaResource>(mClient) ]() {
|
||||
AutoLock lock(mMediaCache->Monitor());
|
||||
if (!mClosed && mPlaybackBytesPerSecond != aBytesPerSecond) {
|
||||
mPlaybackBytesPerSecond = aBytesPerSecond;
|
||||
mMediaCache->QueueUpdate(lock);
|
||||
}
|
||||
});
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
AutoLock lock(mMediaCache->Monitor());
|
||||
if (!mClosed && mPlaybackBytesPerSecond != aBytesPerSecond) {
|
||||
mPlaybackBytesPerSecond = aBytesPerSecond;
|
||||
mMediaCache->QueueUpdate(lock);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2947,7 +2943,7 @@ nsresult MediaCacheStream::GetCachedRanges(MediaByteRangeSet& aRanges)
|
|||
double
|
||||
MediaCacheStream::GetDownloadRate(bool* aIsReliable)
|
||||
{
|
||||
// TODO: Assert non-main thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
AutoLock lock(mMediaCache->Monitor());
|
||||
return mDownloadStatistics.GetRate(aIsReliable);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ public:
|
|||
}
|
||||
mAccumulatedBytes += aBytes;
|
||||
}
|
||||
double GetRateAtLastStop(bool* aReliable) {
|
||||
double GetRateAtLastStop(bool* aReliable) const
|
||||
{
|
||||
double seconds = mAccumulatedTime.ToSeconds();
|
||||
*aReliable = (seconds >= 1.0) ||
|
||||
(mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD);
|
||||
|
@ -68,7 +69,8 @@ public:
|
|||
return 0.0;
|
||||
return static_cast<double>(mAccumulatedBytes)/seconds;
|
||||
}
|
||||
double GetRate(bool* aReliable) {
|
||||
double GetRate(bool* aReliable) const
|
||||
{
|
||||
TimeDuration time = mAccumulatedTime;
|
||||
if (mIsStarted) {
|
||||
time += TimeStamp::Now() - mLastStartTime;
|
||||
|
|
|
@ -652,12 +652,6 @@ protected:
|
|||
// background.
|
||||
bool mIsBackgroundVideoDecodingAllowed;
|
||||
|
||||
// Current decoding position in the stream. This is where the decoder
|
||||
// is up to consuming the stream. This is not adjusted during decoder
|
||||
// seek operations, but it's updated at the end when we start playing
|
||||
// back again.
|
||||
int64_t mDecoderPosition = 0;
|
||||
|
||||
public:
|
||||
AbstractCanonical<double>* CanonicalVolume() { return &mVolume; }
|
||||
AbstractCanonical<bool>* CanonicalPreservesPitch()
|
||||
|
|
|
@ -833,15 +833,6 @@ public:
|
|||
mSeekJob = Move(aSeekJob);
|
||||
mVisibility = aVisibility;
|
||||
|
||||
// Always switch off the blank decoder otherwise we might become visible
|
||||
// in the middle of seeking and won't have a valid video frame to show
|
||||
// when seek is done.
|
||||
if (mMaster->mVideoDecodeSuspended) {
|
||||
mMaster->mVideoDecodeSuspended = false;
|
||||
mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::ExitVideoSuspend);
|
||||
Reader()->SetVideoBlankDecode(false);
|
||||
}
|
||||
|
||||
// Suppressed visibility comes from two cases: (1) leaving dormant state,
|
||||
// and (2) resuming suspended video decoder. We want both cases to be
|
||||
// transparent to the user. So we only notify the change when the seek
|
||||
|
@ -884,8 +875,7 @@ public:
|
|||
|
||||
void HandleResumeVideoDecoding(const TimeUnit&) override
|
||||
{
|
||||
// We set mVideoDecodeSuspended to false in Enter().
|
||||
MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
|
||||
// Do nothing. We will resume video decoding in the decoding state.
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -2116,6 +2106,10 @@ StateObject::HandleResumeVideoDecoding(const TimeUnit& aTarget)
|
|||
{
|
||||
MOZ_ASSERT(mMaster->mVideoDecodeSuspended);
|
||||
|
||||
mMaster->mVideoDecodeSuspended = false;
|
||||
mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::ExitVideoSuspend);
|
||||
Reader()->SetVideoBlankDecode(false);
|
||||
|
||||
// Start counting recovery time from right now.
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
|
||||
|
@ -2278,6 +2272,12 @@ DecodingState::Enter()
|
|||
{
|
||||
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
|
||||
|
||||
if (mMaster->mVideoDecodeSuspended &&
|
||||
mMaster->mVideoDecodeMode == VideoDecodeMode::Normal) {
|
||||
StateObject::HandleResumeVideoDecoding(mMaster->GetMediaTime());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMaster->mVideoDecodeMode == VideoDecodeMode::Suspend &&
|
||||
!mMaster->mVideoDecodeSuspendTimer.IsScheduled() &&
|
||||
!mMaster->mVideoDecodeSuspended) {
|
||||
|
|
|
@ -196,6 +196,9 @@ public:
|
|||
DECODER_STATE_SHUTDOWN
|
||||
};
|
||||
|
||||
// Returns the state machine task queue.
|
||||
TaskQueue* OwnerThread() const { return mTaskQueue; }
|
||||
|
||||
RefPtr<MediaDecoder::DebugInfoPromise> RequestDebugInfo();
|
||||
|
||||
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
|
@ -337,9 +340,6 @@ private:
|
|||
bool HasVideo() const { return mInfo.ref().HasVideo(); }
|
||||
const MediaInfo& Info() const { return mInfo.ref(); }
|
||||
|
||||
// Returns the state machine task queue.
|
||||
TaskQueue* OwnerThread() const { return mTaskQueue; }
|
||||
|
||||
// Schedules the shared state machine thread to run the state machine.
|
||||
void ScheduleStateMachine();
|
||||
|
||||
|
|
|
@ -58,9 +58,6 @@ public:
|
|||
// Notify that the "cache suspended" status of MediaResource changes.
|
||||
virtual void NotifySuspendedStatusChanged(bool aSuspendedByCache) {}
|
||||
|
||||
// Notify the number of bytes read from the resource.
|
||||
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) {}
|
||||
|
||||
protected:
|
||||
virtual ~MediaResourceCallback() {}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,7 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
DIRS += [
|
||||
'rlz',
|
||||
'widevine-adapter',
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
rogerta@chromium.org
|
||||
thakis@chromium.org
|
||||
|
||||
# COMPONENT: Internals>Core
|
|
@ -0,0 +1,4 @@
|
|||
Code taken from rlz project in Chromium repository: https://chromium.googlesource.com/chromium/src.git/+/6f3478dfd7d29b9872871718bd08493ed0c8bc8e
|
||||
|
||||
Note: base/ contains wrappers/dummies to provide implementations of the
|
||||
Chromium APIs that this code relies upon.
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef FAKE_ASSERT_H_
|
||||
#define FAKE_ASSERT_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define ASSERT_STRING(x) { assert(false); }
|
||||
#define VERIFY(x) { assert(x); };
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/crc8.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// The CRC lookup table used for ATM HES (Polynomial = 0x07).
|
||||
// These are 256 unique 8-bit values.
|
||||
const unsigned char kCrcTable[256] = {
|
||||
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
|
||||
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
||||
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
|
||||
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
|
||||
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
|
||||
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
|
||||
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
|
||||
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
|
||||
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
|
||||
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
|
||||
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
|
||||
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
|
||||
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
|
||||
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
|
||||
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
|
||||
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
|
||||
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
|
||||
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
|
||||
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
|
||||
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
|
||||
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
|
||||
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
|
||||
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
|
||||
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
|
||||
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
|
||||
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
|
||||
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
|
||||
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
|
||||
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
|
||||
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
|
||||
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
|
||||
};
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool Crc8::Generate(const unsigned char *data, int length,
|
||||
unsigned char* check_sum) {
|
||||
if (!check_sum)
|
||||
return false;
|
||||
|
||||
*check_sum = 0;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
// The inital and final constants are as used in the ATM HEC.
|
||||
static const unsigned char kInitial = 0x00;
|
||||
static const unsigned char kFinal = 0x55;
|
||||
unsigned char crc = kInitial;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
crc = kCrcTable[(data[i] ^ crc) & 0xFFU];
|
||||
}
|
||||
|
||||
*check_sum = crc ^ kFinal;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Crc8::Verify(const unsigned char* data, int length,
|
||||
unsigned char check_sum, bool* matches) {
|
||||
if (!matches)
|
||||
return false;
|
||||
|
||||
*matches = false;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
unsigned char calculated_crc;
|
||||
if (!Generate(data, length, &calculated_crc))
|
||||
return false;
|
||||
|
||||
*matches = check_sum == calculated_crc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Crc8 utility functions.
|
||||
|
||||
#ifndef RLZ_LIB_CRC8_H_
|
||||
#define RLZ_LIB_CRC8_H_
|
||||
|
||||
namespace rlz_lib {
|
||||
// CRC-8 methods:
|
||||
class Crc8 {
|
||||
public:
|
||||
static bool Generate(const unsigned char* data,
|
||||
int length,
|
||||
unsigned char* check_sum);
|
||||
static bool Verify(const unsigned char* data,
|
||||
int length,
|
||||
unsigned char checksum,
|
||||
bool * matches);
|
||||
};
|
||||
}; // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_CRC8_H_
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "rlz/lib/machine_id.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "rlz/lib/assert.h"
|
||||
#include "rlz/lib/crc8.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
// Note: The original machine_id.cc code depends on Chromium's sha1 implementation.
|
||||
// Using Mozilla's implmentation as replacement to reduce the dependency of
|
||||
// some external files.
|
||||
#include "mozilla/SHA1.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool GetMachineId(std::string* machine_id) {
|
||||
if (!machine_id)
|
||||
return false;
|
||||
|
||||
static std::string calculated_id;
|
||||
static bool calculated = false;
|
||||
if (calculated) {
|
||||
*machine_id = calculated_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> sid_bytes;
|
||||
int volume_id;
|
||||
if (!GetRawMachineId(&sid_bytes, &volume_id))
|
||||
return false;
|
||||
|
||||
if (!testing::GetMachineIdImpl(sid_bytes, volume_id, machine_id))
|
||||
return false;
|
||||
|
||||
calculated = true;
|
||||
calculated_id = *machine_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
bool GetMachineIdImpl(const std::vector<uint8_t>& sid_bytes,
|
||||
int volume_id,
|
||||
std::string* machine_id) {
|
||||
machine_id->clear();
|
||||
|
||||
// The ID should be the SID hash + the Hard Drive SNo. + checksum byte.
|
||||
static const int kSizeWithoutChecksum = mozilla::SHA1Sum::kHashSize + sizeof(int);
|
||||
std::basic_string<unsigned char> id_binary(kSizeWithoutChecksum + 1, 0);
|
||||
|
||||
if (!sid_bytes.empty()) {
|
||||
// In order to be compatible with the old version of RLZ, the hash of the
|
||||
// SID must be done with all the original bytes from the unicode string.
|
||||
// However, the chromebase SHA1 hash function takes only an std::string as
|
||||
// input, so the unicode string needs to be converted to std::string
|
||||
// "as is".
|
||||
size_t byte_count = sid_bytes.size() * sizeof(std::vector<uint8_t>::value_type);
|
||||
const char* buffer = reinterpret_cast<const char*>(sid_bytes.data());
|
||||
|
||||
// Note that digest can have embedded nulls.
|
||||
mozilla::SHA1Sum SHA1;
|
||||
mozilla::SHA1Sum::Hash hash;
|
||||
SHA1.update(buffer, byte_count);
|
||||
SHA1.finish(hash);
|
||||
std::string digest(reinterpret_cast<char*>(hash), mozilla::SHA1Sum::kHashSize);
|
||||
VERIFY(digest.size() == mozilla::SHA1Sum::kHashSize);
|
||||
std::copy(digest.begin(), digest.end(), id_binary.begin());
|
||||
}
|
||||
|
||||
// Convert from int to binary (makes big-endian).
|
||||
for (size_t i = 0; i < sizeof(int); i++) {
|
||||
int shift_bits = 8 * (sizeof(int) - i - 1);
|
||||
id_binary[mozilla::SHA1Sum::kHashSize + i] = static_cast<unsigned char>(
|
||||
(volume_id >> shift_bits) & 0xFF);
|
||||
}
|
||||
|
||||
// Append the checksum byte.
|
||||
if (!sid_bytes.empty() || (0 != volume_id))
|
||||
rlz_lib::Crc8::Generate(id_binary.c_str(),
|
||||
kSizeWithoutChecksum,
|
||||
&id_binary[kSizeWithoutChecksum]);
|
||||
|
||||
return rlz_lib::BytesToString(
|
||||
id_binary.c_str(), kSizeWithoutChecksum + 1, machine_id);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef RLZ_LIB_MACHINE_ID_H_
|
||||
#define RLZ_LIB_MACHINE_ID_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Gets the unique ID for the machine used for RLZ tracking purposes. On
|
||||
// Windows, this ID is derived from the Windows machine SID, and is the string
|
||||
// representation of a 20 byte hash + 4 bytes volum id + a 1 byte checksum.
|
||||
// Included in financial pings with events, unless explicitly forbidden by the
|
||||
// calling application.
|
||||
bool GetMachineId(std::string* machine_id);
|
||||
|
||||
// Retrieves a raw machine identifier string and a machine-specific
|
||||
// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute
|
||||
// the Crc8 of that, and return a hex-encoded string of that data.
|
||||
bool GetRawMachineId(std::vector<uint8_t>* data, int* more_data);
|
||||
|
||||
namespace testing {
|
||||
bool GetMachineIdImpl(const std::vector<uint8_t>& sid_bytes,
|
||||
int volume_id,
|
||||
std::string* machine_id);
|
||||
} // namespace testing
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_MACHINE_ID_H_
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string) {
|
||||
if (!string)
|
||||
return false;
|
||||
|
||||
string->clear();
|
||||
if (data_len < 1 || !data)
|
||||
return false;
|
||||
|
||||
static const char kHex[] = "0123456789ABCDEF";
|
||||
|
||||
// Fix the buffer size to begin with to avoid repeated re-allocation.
|
||||
string->resize(data_len * 2);
|
||||
int index = data_len;
|
||||
while (index--) {
|
||||
string->at(2 * index) = kHex[data[index] >> 4]; // high digit
|
||||
string->at(2 * index + 1) = kHex[data[index] & 0x0F]; // low digit
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#ifndef RLZ_LIB_STRING_UTILS_H_
|
||||
#define RLZ_LIB_STRING_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string);
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif // RLZ_LIB_STRING_UTILS_H_
|
|
@ -0,0 +1,322 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/network/IOEthernetController.h>
|
||||
#include <IOKit/network/IOEthernetInterface.h>
|
||||
#include <IOKit/network/IONetworkInterface.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
// Note: The original machine_id_mac.cc code is in namespace rlz_lib below.
|
||||
// It depends on some external files, which would bring in a log of Chromium
|
||||
// code if imported as well.
|
||||
// Instead only the necessary code has been extracted from the relevant files,
|
||||
// and further combined and reduced to limit the maintenance burden.
|
||||
|
||||
// [Extracted from base/logging.h]
|
||||
#define DCHECK assert
|
||||
|
||||
namespace base {
|
||||
|
||||
// [Extracted from base/mac/scoped_typeref.h and base/mac/scoped_cftyperef.h]
|
||||
template<typename T>
|
||||
class ScopedCFTypeRef {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
explicit ScopedCFTypeRef(T object)
|
||||
: object_(object) {
|
||||
}
|
||||
|
||||
ScopedCFTypeRef(const ScopedCFTypeRef<T>& that) = delete;
|
||||
ScopedCFTypeRef(ScopedCFTypeRef<T>&& that) = delete;
|
||||
|
||||
~ScopedCFTypeRef() {
|
||||
if (object_)
|
||||
CFRelease(object_);
|
||||
}
|
||||
|
||||
ScopedCFTypeRef& operator=(const ScopedCFTypeRef<T>& that) = delete;
|
||||
ScopedCFTypeRef& operator=(ScopedCFTypeRef<T>&& that) = delete;
|
||||
|
||||
operator T() const {
|
||||
return object_;
|
||||
}
|
||||
|
||||
// ScopedCFTypeRef<>::release() is like scoped_ptr<>::release. It is NOT
|
||||
// a wrapper for CFRelease().
|
||||
T release() {
|
||||
T temp = object_;
|
||||
object_ = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
T object_;
|
||||
};
|
||||
|
||||
namespace mac {
|
||||
|
||||
// [Extracted from base/mac/scoped_ioobject.h]
|
||||
// Just like ScopedCFTypeRef but for io_object_t and subclasses.
|
||||
template<typename IOT>
|
||||
class ScopedIOObject {
|
||||
public:
|
||||
typedef IOT element_type;
|
||||
|
||||
explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
|
||||
: object_(object) {
|
||||
}
|
||||
|
||||
~ScopedIOObject() {
|
||||
if (object_)
|
||||
IOObjectRelease(object_);
|
||||
}
|
||||
|
||||
ScopedIOObject(const ScopedIOObject&) = delete;
|
||||
void operator=(const ScopedIOObject&) = delete;
|
||||
|
||||
void reset(IOT object = IO_OBJECT_NULL) {
|
||||
if (object_)
|
||||
IOObjectRelease(object_);
|
||||
object_ = object;
|
||||
}
|
||||
|
||||
operator IOT() const {
|
||||
return object_;
|
||||
}
|
||||
|
||||
private:
|
||||
IOT object_;
|
||||
};
|
||||
|
||||
// [Extracted from base/mac/foundation_util.h]
|
||||
template<typename T>
|
||||
T CFCast(const CFTypeRef& cf_val);
|
||||
|
||||
template<>
|
||||
CFDataRef
|
||||
CFCast<CFDataRef>(const CFTypeRef& cf_val) {
|
||||
if (cf_val == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (CFGetTypeID(cf_val) == CFDataGetTypeID()) {
|
||||
return (CFDataRef)(cf_val);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
CFStringRef
|
||||
CFCast<CFStringRef>(const CFTypeRef& cf_val) {
|
||||
if (cf_val == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (CFGetTypeID(cf_val) == CFStringGetTypeID()) {
|
||||
return (CFStringRef)(cf_val);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace mac
|
||||
|
||||
// [Extracted from base/strings/sys_string_conversions_mac.mm]
|
||||
static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
|
||||
|
||||
template<typename StringType>
|
||||
static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
|
||||
CFStringEncoding encoding) {
|
||||
CFIndex length = CFStringGetLength(cfstring);
|
||||
if (length == 0)
|
||||
return StringType();
|
||||
|
||||
CFRange whole_string = CFRangeMake(0, length);
|
||||
CFIndex out_size;
|
||||
CFIndex converted = CFStringGetBytes(cfstring,
|
||||
whole_string,
|
||||
encoding,
|
||||
0, // lossByte
|
||||
false, // isExternalRepresentation
|
||||
NULL, // buffer
|
||||
0, // maxBufLen
|
||||
&out_size);
|
||||
if (converted == 0 || out_size == 0)
|
||||
return StringType();
|
||||
|
||||
// out_size is the number of UInt8-sized units needed in the destination.
|
||||
// A buffer allocated as UInt8 units might not be properly aligned to
|
||||
// contain elements of StringType::value_type. Use a container for the
|
||||
// proper value_type, and convert out_size by figuring the number of
|
||||
// value_type elements per UInt8. Leave room for a NUL terminator.
|
||||
typename StringType::size_type elements =
|
||||
out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
|
||||
|
||||
std::vector<typename StringType::value_type> out_buffer(elements);
|
||||
converted = CFStringGetBytes(cfstring,
|
||||
whole_string,
|
||||
encoding,
|
||||
0, // lossByte
|
||||
false, // isExternalRepresentation
|
||||
reinterpret_cast<UInt8*>(&out_buffer[0]),
|
||||
out_size,
|
||||
NULL); // usedBufLen
|
||||
if (converted == 0)
|
||||
return StringType();
|
||||
|
||||
out_buffer[elements - 1] = '\0';
|
||||
return StringType(&out_buffer[0], elements - 1);
|
||||
}
|
||||
|
||||
std::string SysCFStringRefToUTF8(CFStringRef ref)
|
||||
{
|
||||
return CFStringToSTLStringWithEncodingT<std::string>(ref,
|
||||
kNarrowStringEncoding);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
// See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html
|
||||
|
||||
// The caller is responsible for freeing |matching_services|.
|
||||
bool FindEthernetInterfaces(io_iterator_t* matching_services) {
|
||||
base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict(
|
||||
IOServiceMatching(kIOEthernetInterfaceClass));
|
||||
if (!matching_dict)
|
||||
return false;
|
||||
|
||||
base::ScopedCFTypeRef<CFMutableDictionaryRef> primary_interface(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
if (!primary_interface)
|
||||
return false;
|
||||
|
||||
CFDictionarySetValue(
|
||||
primary_interface, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
|
||||
CFDictionarySetValue(
|
||||
matching_dict, CFSTR(kIOPropertyMatchKey), primary_interface);
|
||||
|
||||
kern_return_t kern_result = IOServiceGetMatchingServices(
|
||||
kIOMasterPortDefault, matching_dict.release(), matching_services);
|
||||
|
||||
return kern_result == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator,
|
||||
uint8_t* buffer, size_t buffer_size) {
|
||||
if (buffer_size < kIOEthernetAddressSize)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
|
||||
bzero(buffer, buffer_size);
|
||||
base::mac::ScopedIOObject<io_object_t> primary_interface;
|
||||
for (primary_interface.reset(IOIteratorNext(primary_interface_iterator));
|
||||
primary_interface;
|
||||
primary_interface.reset(IOIteratorNext(primary_interface_iterator))) {
|
||||
io_object_t primary_interface_parent;
|
||||
kern_return_t kern_result = IORegistryEntryGetParentEntry(
|
||||
primary_interface, kIOServicePlane, &primary_interface_parent);
|
||||
base::mac::ScopedIOObject<io_object_t> primary_interface_parent_deleter(
|
||||
primary_interface_parent);
|
||||
success = kern_result == KERN_SUCCESS;
|
||||
|
||||
if (!success)
|
||||
continue;
|
||||
|
||||
base::ScopedCFTypeRef<CFTypeRef> mac_data(
|
||||
IORegistryEntryCreateCFProperty(primary_interface_parent,
|
||||
CFSTR(kIOMACAddress),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
CFDataRef mac_data_data = base::mac::CFCast<CFDataRef>(mac_data);
|
||||
if (mac_data_data) {
|
||||
CFDataGetBytes(
|
||||
mac_data_data, CFRangeMake(0, kIOEthernetAddressSize), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GetMacAddress(unsigned char* buffer, size_t size) {
|
||||
io_iterator_t primary_interface_iterator;
|
||||
if (!FindEthernetInterfaces(&primary_interface_iterator))
|
||||
return false;
|
||||
bool result = GetMACAddressFromIterator(
|
||||
primary_interface_iterator, buffer, size);
|
||||
IOObjectRelease(primary_interface_iterator);
|
||||
return result;
|
||||
}
|
||||
|
||||
CFStringRef CopySerialNumber() {
|
||||
base::mac::ScopedIOObject<io_service_t> expert_device(
|
||||
IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||
IOServiceMatching("IOPlatformExpertDevice")));
|
||||
if (!expert_device)
|
||||
return NULL;
|
||||
|
||||
base::ScopedCFTypeRef<CFTypeRef> serial_number(
|
||||
IORegistryEntryCreateCFProperty(expert_device,
|
||||
CFSTR(kIOPlatformSerialNumberKey),
|
||||
kCFAllocatorDefault,
|
||||
0));
|
||||
CFStringRef serial_number_cfstring =
|
||||
base::mac::CFCast<CFStringRef>(serial_number.release());
|
||||
if (!serial_number_cfstring)
|
||||
return NULL;
|
||||
|
||||
return serial_number_cfstring;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GetRawMachineId(std::vector<uint8_t>* data, int* more_data) {
|
||||
uint8_t mac_address[kIOEthernetAddressSize];
|
||||
|
||||
std::string id;
|
||||
if (GetMacAddress(mac_address, sizeof(mac_address))) {
|
||||
id += "mac:";
|
||||
static const char hex[] =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
for (int i = 0; i < kIOEthernetAddressSize; ++i) {
|
||||
uint8_t byte = mac_address[i];
|
||||
id += hex[byte >> 4];
|
||||
id += hex[byte & 0xF];
|
||||
}
|
||||
}
|
||||
|
||||
// A MAC address is enough to uniquely identify a machine, but it's only 6
|
||||
// bytes, 3 of which are manufacturer-determined. To make brute-forcing the
|
||||
// SHA1 of this harder, also append the system's serial number.
|
||||
CFStringRef serial = CopySerialNumber();
|
||||
if (serial) {
|
||||
if (!id.empty()) {
|
||||
id += ' ';
|
||||
}
|
||||
id += "serial:";
|
||||
id += base::SysCFStringRefToUTF8(serial);
|
||||
CFRelease(serial);
|
||||
}
|
||||
|
||||
// Get the contents of the string 'id' as a bunch of bytes.
|
||||
data->assign(&id[0], &id[id.size()]);
|
||||
|
||||
// On windows, this is set to the volume id. Since it's not scrambled before
|
||||
// being sent, just set it to 1.
|
||||
*more_data = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -0,0 +1,34 @@
|
|||
# -*- 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/.
|
||||
|
||||
# Note: build rlz in its own moz.build, so it doesn't pickup any of
|
||||
# Chromium IPC's headers used in the moz.build of the parent file.
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['OS_TARGET'] in ['WINNT', 'Darwin']:
|
||||
UNIFIED_SOURCES += [
|
||||
'lib/crc8.cc',
|
||||
'lib/machine_id.cc',
|
||||
'lib/string_utils.cc',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
UNIFIED_SOURCES += [
|
||||
'win/lib/machine_id_win.cc',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'Darwin':
|
||||
UNIFIED_SOURCES += [
|
||||
'mac/lib/machine_id_mac.cc',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'-framework IOKit',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <windows.h>
|
||||
#include <sddl.h> // For ConvertSidToStringSidW.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetSystemVolumeSerialNumber(int* number) {
|
||||
if (!number)
|
||||
return false;
|
||||
|
||||
*number = 0;
|
||||
|
||||
// Find the system root path (e.g: C:\).
|
||||
wchar_t system_path[MAX_PATH + 1];
|
||||
if (!GetSystemDirectoryW(system_path, MAX_PATH))
|
||||
return false;
|
||||
|
||||
wchar_t* first_slash = wcspbrk(system_path, L"\\/");
|
||||
if (first_slash != NULL)
|
||||
*(first_slash + 1) = 0;
|
||||
|
||||
DWORD number_local = 0;
|
||||
if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
|
||||
NULL, 0))
|
||||
return false;
|
||||
|
||||
*number = (int)number_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
|
||||
static const DWORD kStartDomainLength = 128; // reasonable to start with
|
||||
|
||||
std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[kStartDomainLength]);
|
||||
DWORD domain_size = kStartDomainLength;
|
||||
DWORD sid_dword_size = sid_size;
|
||||
SID_NAME_USE sid_name_use;
|
||||
|
||||
BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
|
||||
&sid_dword_size, domain_buffer.get(),
|
||||
&domain_size, &sid_name_use);
|
||||
if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// We could have gotten the insufficient buffer error because
|
||||
// one or both of sid and szDomain was too small. Check for that
|
||||
// here.
|
||||
if (sid_dword_size > sid_size)
|
||||
return false;
|
||||
|
||||
if (domain_size > kStartDomainLength)
|
||||
domain_buffer.reset(new wchar_t[domain_size]);
|
||||
|
||||
success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
|
||||
domain_buffer.get(), &domain_size,
|
||||
&sid_name_use);
|
||||
}
|
||||
|
||||
return success != FALSE;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ConvertSidToBytes(SID* sid) {
|
||||
std::wstring sid_string;
|
||||
#if _WIN32_WINNT >= 0x500
|
||||
wchar_t* sid_buffer = NULL;
|
||||
if (ConvertSidToStringSidW(sid, &sid_buffer)) {
|
||||
sid_string = sid_buffer;
|
||||
LocalFree(sid_buffer);
|
||||
}
|
||||
#else
|
||||
SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
|
||||
|
||||
if(sia->Value[0] || sia->Value[1]) {
|
||||
base::SStringPrintf(
|
||||
&sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
|
||||
SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
|
||||
(USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
|
||||
(USHORT)sia->Value[5]);
|
||||
} else {
|
||||
ULONG authority = 0;
|
||||
for (int i = 2; i < 6; ++i) {
|
||||
authority <<= 8;
|
||||
authority |= sia->Value[i];
|
||||
}
|
||||
base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
|
||||
}
|
||||
|
||||
int sub_auth_count = *::GetSidSubAuthorityCount(sid);
|
||||
for(int i = 0; i < sub_auth_count; ++i)
|
||||
base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
|
||||
#endif
|
||||
|
||||
// Get the contents of the string as a bunch of bytes.
|
||||
return std::vector<uint8_t>(
|
||||
reinterpret_cast<uint8_t*>(&sid_string[0]),
|
||||
reinterpret_cast<uint8_t*>(&sid_string[sid_string.size()]));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GetRawMachineId(std::vector<uint8_t>* sid_bytes, int* volume_id) {
|
||||
// Calculate the Windows SID.
|
||||
|
||||
wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||
DWORD size = mozilla::ArrayLength(computer_name);
|
||||
|
||||
if (GetComputerNameW(computer_name, &size)) {
|
||||
char sid_buffer[SECURITY_MAX_SID_SIZE];
|
||||
SID* sid = reinterpret_cast<SID*>(sid_buffer);
|
||||
if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
|
||||
*sid_bytes = ConvertSidToBytes(sid);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the system drive volume serial number.
|
||||
*volume_id = 0;
|
||||
if (!GetSystemVolumeSerialNumber(volume_id)) {
|
||||
ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
|
||||
*volume_id = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -1731,9 +1731,10 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
|||
// If we cannot insert a <p>/<div> element at the selection, we should insert
|
||||
// a <br> element instead.
|
||||
if (insertBRElement) {
|
||||
nsresult rv = StandardBreakImpl(*atStartOfSelection.GetContainer(),
|
||||
atStartOfSelection.Offset(), aSelection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = InsertBRElement(aSelection, atStartOfSelection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
*aHandled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1767,8 +1768,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
|||
}
|
||||
if (NS_WARN_IF(blockParent == host)) {
|
||||
// Didn't create a new block for some reason, fall back to <br>
|
||||
rv = StandardBreakImpl(*atStartOfSelection.GetContainer(),
|
||||
atStartOfSelection.Offset(), aSelection);
|
||||
rv = InsertBRElement(aSelection, atStartOfSelection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1784,8 +1784,10 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
|||
bool isEmpty;
|
||||
IsEmptyBlock(*blockParent, &isEmpty);
|
||||
if (isEmpty) {
|
||||
nsCOMPtr<Element> br = htmlEditor->CreateBR(blockParent,
|
||||
blockParent->Length());
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(atStartOfSelection);
|
||||
EditorRawDOMPoint endOfBlockParent;
|
||||
endOfBlockParent.SetToEndOf(blockParent);
|
||||
RefPtr<Element> br = htmlEditor->CreateBR(endOfBlockParent);
|
||||
NS_ENSURE_STATE(br);
|
||||
}
|
||||
|
||||
|
@ -1816,6 +1818,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
|||
blockParent->IsHTMLElement(nsGkAtoms::p)) ||
|
||||
(separator != ParagraphSeparator::br &&
|
||||
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(atStartOfSelection);
|
||||
// Paragraphs: special rules to look for <br>s
|
||||
EditActionResult result = ReturnInParagraph(aSelection, *blockParent);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
|
@ -1829,113 +1832,142 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
|||
// If not already handled then do the standard thing
|
||||
if (!(*aHandled)) {
|
||||
*aHandled = true;
|
||||
return StandardBreakImpl(*atStartOfSelection.GetContainer(),
|
||||
atStartOfSelection.Offset(), aSelection);
|
||||
return InsertBRElement(aSelection, atStartOfSelection);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLEditRules::StandardBreakImpl(nsINode& aNode,
|
||||
int32_t aOffset,
|
||||
Selection& aSelection)
|
||||
HTMLEditRules::InsertBRElement(Selection& aSelection,
|
||||
const EditorDOMPoint& aPointToBreak)
|
||||
{
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
if (NS_WARN_IF(!aPointToBreak.IsSet())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
nsCOMPtr<Element> brNode;
|
||||
bool bAfterBlock = false;
|
||||
bool bBeforeBlock = false;
|
||||
nsCOMPtr<nsINode> node = &aNode;
|
||||
bool brElementIsAfterBlock = false;
|
||||
bool brElementIsBeforeBlock = false;
|
||||
|
||||
// First, insert a <br> element.
|
||||
RefPtr<Element> brElement;
|
||||
if (IsPlaintextEditor()) {
|
||||
brNode = htmlEditor->CreateBR(node, aOffset);
|
||||
NS_ENSURE_STATE(brNode);
|
||||
brElement = htmlEditor->CreateBR(aPointToBreak.AsRaw());
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
WSRunObject wsObj(htmlEditor, node, aOffset);
|
||||
EditorDOMPoint pointToBreak(aPointToBreak);
|
||||
WSRunObject wsObj(htmlEditor, pointToBreak.GetContainer(),
|
||||
pointToBreak.Offset());
|
||||
int32_t visOffset = 0;
|
||||
WSType wsType;
|
||||
nsCOMPtr<nsINode> visNode;
|
||||
wsObj.PriorVisibleNode(node, aOffset, address_of(visNode),
|
||||
&visOffset, &wsType);
|
||||
wsObj.PriorVisibleNode(pointToBreak.GetContainer(), pointToBreak.Offset(),
|
||||
address_of(visNode), &visOffset, &wsType);
|
||||
if (wsType & WSType::block) {
|
||||
bAfterBlock = true;
|
||||
brElementIsAfterBlock = true;
|
||||
}
|
||||
wsObj.NextVisibleNode(node, aOffset, address_of(visNode),
|
||||
&visOffset, &wsType);
|
||||
wsObj.NextVisibleNode(pointToBreak.GetContainer(), pointToBreak.Offset(),
|
||||
address_of(visNode), &visOffset, &wsType);
|
||||
if (wsType & WSType::block) {
|
||||
bBeforeBlock = true;
|
||||
brElementIsBeforeBlock = true;
|
||||
}
|
||||
// If the container of the break is a link, we need to split it and
|
||||
// insert new <br> between the split links.
|
||||
nsCOMPtr<nsIDOMNode> linkDOMNode;
|
||||
if (htmlEditor->IsInLink(GetAsDOMNode(node), address_of(linkDOMNode))) {
|
||||
// Split the link
|
||||
if (htmlEditor->IsInLink(pointToBreak.GetContainerAsDOMNode(),
|
||||
address_of(linkDOMNode))) {
|
||||
nsCOMPtr<Element> linkNode = do_QueryInterface(linkDOMNode);
|
||||
NS_ENSURE_STATE(linkNode || !linkDOMNode);
|
||||
if (NS_WARN_IF(!linkNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SplitNodeResult splitLinkNodeResult =
|
||||
htmlEditor->SplitNodeDeep(*linkNode, EditorRawDOMPoint(node, aOffset),
|
||||
htmlEditor->SplitNodeDeep(*linkNode, pointToBreak.AsRaw(),
|
||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||
if (NS_WARN_IF(splitLinkNodeResult.Failed())) {
|
||||
return splitLinkNodeResult.Rv();
|
||||
}
|
||||
EditorRawDOMPoint splitPoint(splitLinkNodeResult.SplitPoint());
|
||||
node = splitPoint.GetContainer();
|
||||
aOffset = splitPoint.Offset();
|
||||
pointToBreak = splitLinkNodeResult.SplitPoint();
|
||||
}
|
||||
brNode =
|
||||
wsObj.InsertBreak(aSelection, EditorRawDOMPoint(node, aOffset),
|
||||
nsIEditor::eNone);
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
brElement =
|
||||
wsObj.InsertBreak(aSelection, pointToBreak.AsRaw(), nsIEditor::eNone);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
node = brNode->GetParentNode();
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
|
||||
if (bAfterBlock && bBeforeBlock) {
|
||||
// We just placed a br between block boundaries. This is the one case
|
||||
|
||||
// If the <br> element has already been removed from the DOM tree by a
|
||||
// mutation observer, don't continue handling this.
|
||||
if (NS_WARN_IF(!brElement->GetParentNode())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (brElementIsAfterBlock && brElementIsBeforeBlock) {
|
||||
// We just placed a <br> between block boundaries. This is the one case
|
||||
// where we want the selection to be before the br we just placed, as the
|
||||
// br will be on a new line, rather than at end of prior line.
|
||||
// XXX brElementIsAfterBlock and brElementIsBeforeBlock were set before
|
||||
// modifying the DOM tree. So, now, the <br> element may not be
|
||||
// between blocks.
|
||||
aSelection.SetInterlinePosition(true);
|
||||
EditorRawDOMPoint point(brNode);
|
||||
nsresult rv = aSelection.Collapse(point.AsRaw());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
int32_t offset = node->IndexOf(brNode);
|
||||
WSRunObject wsObj(htmlEditor, node, offset + 1);
|
||||
nsCOMPtr<nsINode> secondBR;
|
||||
int32_t visOffset = 0;
|
||||
WSType wsType;
|
||||
wsObj.NextVisibleNode(node, offset + 1, address_of(secondBR),
|
||||
&visOffset, &wsType);
|
||||
if (wsType == WSType::br) {
|
||||
// The next thing after the break we inserted is another break. Move the
|
||||
// second break to be the first break's sibling. This will prevent them
|
||||
// from being in different inline nodes, which would break
|
||||
// SetInterlinePosition(). It will also assure that if the user clicks
|
||||
// away and then clicks back on their new blank line, they will still get
|
||||
// the style from the line above.
|
||||
nsCOMPtr<nsINode> brParent = secondBR->GetParentNode();
|
||||
int32_t brOffset = brParent ? brParent->IndexOf(secondBR) : -1;
|
||||
if (brParent != node || brOffset != offset + 1) {
|
||||
nsresult rv =
|
||||
htmlEditor->MoveNode(secondBR->AsContent(), node, offset + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
EditorRawDOMPoint point(brElement);
|
||||
ErrorResult error;
|
||||
aSelection.Collapse(point, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EditorDOMPoint afterBRElement(brElement);
|
||||
DebugOnly<bool> advanced = afterBRElement.AdvanceOffset();
|
||||
NS_WARNING_ASSERTION(advanced,
|
||||
"Failed to advance offset after the new <br> element");
|
||||
WSRunObject wsObj(htmlEditor, afterBRElement.GetContainer(),
|
||||
afterBRElement.Offset());
|
||||
nsCOMPtr<nsINode> maybeSecondBRNode;
|
||||
int32_t visOffset = 0;
|
||||
WSType wsType;
|
||||
wsObj.NextVisibleNode(afterBRElement.GetContainer(), afterBRElement.Offset(),
|
||||
address_of(maybeSecondBRNode), &visOffset, &wsType);
|
||||
if (wsType == WSType::br) {
|
||||
// The next thing after the break we inserted is another break. Move the
|
||||
// second break to be the first break's sibling. This will prevent them
|
||||
// from being in different inline nodes, which would break
|
||||
// SetInterlinePosition(). It will also assure that if the user clicks
|
||||
// away and then clicks back on their new blank line, they will still get
|
||||
// the style from the line above.
|
||||
EditorDOMPoint atSecondBRElement(maybeSecondBRNode);
|
||||
if (brElement->GetNextSibling() != maybeSecondBRNode) {
|
||||
nsresult rv =
|
||||
htmlEditor->MoveNode(maybeSecondBRNode->AsContent(),
|
||||
afterBRElement.GetContainer(),
|
||||
afterBRElement.Offset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
// SetInterlinePosition(true) means we want the caret to stick to the
|
||||
// content on the "right". We want the caret to stick to whatever is past
|
||||
// the break. This is because the break is on the same line we were on,
|
||||
// but the next content will be on the following line.
|
||||
}
|
||||
|
||||
// An exception to this is if the break has a next sibling that is a block
|
||||
// node. Then we stick to the left to avoid an uber caret.
|
||||
nsCOMPtr<nsIContent> siblingNode = brNode->GetNextSibling();
|
||||
if (siblingNode && IsBlockNode(*siblingNode)) {
|
||||
aSelection.SetInterlinePosition(false);
|
||||
} else {
|
||||
aSelection.SetInterlinePosition(true);
|
||||
}
|
||||
nsresult rv = aSelection.Collapse(node, offset + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// SetInterlinePosition(true) means we want the caret to stick to the
|
||||
// content on the "right". We want the caret to stick to whatever is past
|
||||
// the break. This is because the break is on the same line we were on,
|
||||
// but the next content will be on the following line.
|
||||
|
||||
// An exception to this is if the break has a next sibling that is a block
|
||||
// node. Then we stick to the left to avoid an uber caret.
|
||||
nsIContent* nextSiblingOfBRElement = brElement->GetNextSibling();
|
||||
aSelection.SetInterlinePosition(!(nextSiblingOfBRElement &&
|
||||
IsBlockNode(*nextSiblingOfBRElement)));
|
||||
ErrorResult error;
|
||||
aSelection.Collapse(afterBRElement.AsRaw(), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1951,7 +1983,15 @@ nsresult
|
|||
HTMLEditRules::SplitMailCites(Selection* aSelection,
|
||||
bool* aHandled)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSelection && aHandled, NS_ERROR_NULL_POINTER);
|
||||
if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aHandled)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
nsCOMPtr<nsIContent> leftCite, rightCite;
|
||||
nsCOMPtr<nsINode> selNode;
|
||||
nsCOMPtr<Element> citeNode;
|
||||
|
@ -1970,8 +2010,7 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// mailquote (in either inline or block case).
|
||||
// The latter can confuse a user if they click there and start typing,
|
||||
// because being in the mailquote may affect wrapping behavior, or font color, etc.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
|
||||
WSRunObject wsObj(htmlEditor, selNode, selOffset);
|
||||
nsCOMPtr<nsINode> visNode;
|
||||
int32_t visOffset=0;
|
||||
WSType wsType;
|
||||
|
@ -1981,18 +2020,16 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// ok, we are just before a break. is it inside the mailquote?
|
||||
if (visNode != citeNode && citeNode->Contains(visNode)) {
|
||||
// it is. so lets reset our selection to be just after it.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
selNode = mHTMLEditor->GetNodeLocation(visNode, &selOffset);
|
||||
selNode = EditorBase::GetNodeLocation(visNode, &selOffset);
|
||||
++selOffset;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
NS_ENSURE_STATE(selNode->IsContent());
|
||||
SplitNodeResult splitCiteNodeResult =
|
||||
mHTMLEditor->SplitNodeDeep(*citeNode,
|
||||
EditorRawDOMPoint(selNode, selOffset),
|
||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||
htmlEditor->SplitNodeDeep(*citeNode,
|
||||
EditorRawDOMPoint(selNode, selOffset),
|
||||
SplitAtEdges::eDoNotCreateEmptyContainer);
|
||||
if (NS_WARN_IF(splitCiteNodeResult.Failed())) {
|
||||
return splitCiteNodeResult.Rv();
|
||||
}
|
||||
|
@ -2003,19 +2040,20 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// important, since when serializing the cite to plain text, the span which
|
||||
// caused the visual break is discarded. So the added <br> will guarantee
|
||||
// that the serializer will insert a break where the user saw one.
|
||||
nsIContent* preveiousNodeOfSplitPoint =
|
||||
nsIContent* previousNodeOfSplitPoint =
|
||||
splitCiteNodeResult.GetPreviousNode();
|
||||
if (preveiousNodeOfSplitPoint &&
|
||||
preveiousNodeOfSplitPoint->IsHTMLElement(nsGkAtoms::span) &&
|
||||
preveiousNodeOfSplitPoint->GetPrimaryFrame()->
|
||||
IsFrameOfType(nsIFrame::eBlockFrame)) {
|
||||
if (previousNodeOfSplitPoint &&
|
||||
previousNodeOfSplitPoint->IsHTMLElement(nsGkAtoms::span) &&
|
||||
previousNodeOfSplitPoint->GetPrimaryFrame()->
|
||||
IsFrameOfType(nsIFrame::eBlockFrame)) {
|
||||
nsCOMPtr<nsINode> lastChild =
|
||||
preveiousNodeOfSplitPoint->GetLastChild();
|
||||
previousNodeOfSplitPoint->GetLastChild();
|
||||
if (lastChild && !lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
||||
// We ignore the result here.
|
||||
nsCOMPtr<Element> invisBR =
|
||||
mHTMLEditor->CreateBR(preveiousNodeOfSplitPoint,
|
||||
preveiousNodeOfSplitPoint->Length());
|
||||
EditorRawDOMPoint endOfPreviousNodeOfSplitPoint;
|
||||
endOfPreviousNodeOfSplitPoint.SetToEndOf(previousNodeOfSplitPoint);
|
||||
RefPtr<Element> invisBR =
|
||||
htmlEditor->CreateBR(endOfPreviousNodeOfSplitPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2023,11 +2061,10 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// left cite hasn't been created because the split point was start of the
|
||||
// cite node, <br> should be inserted before the current cite.
|
||||
EditorRawDOMPoint pointToInsertBrNode(splitCiteNodeResult.SplitPoint());
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> brNode =
|
||||
mHTMLEditor->CreateBR(pointToInsertBrNode.GetContainer(),
|
||||
pointToInsertBrNode.Offset());
|
||||
NS_ENSURE_STATE(brNode);
|
||||
RefPtr<Element> brNode = htmlEditor->CreateBR(pointToInsertBrNode);
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Now, offset of pointToInsertBrNode is invalid. Let's clear it.
|
||||
pointToInsertBrNode.Clear();
|
||||
|
||||
|
@ -2048,8 +2085,7 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// just after it. If we don't have another br or block boundary adjacent,
|
||||
// then we will need a 2nd br added to achieve blank line that user expects.
|
||||
if (IsInlineNode(*citeNode)) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
|
||||
WSRunObject wsObj(htmlEditor, selNode, selOffset);
|
||||
nsCOMPtr<nsINode> visNode;
|
||||
int32_t visOffset=0;
|
||||
WSType wsType;
|
||||
|
@ -2057,16 +2093,14 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
&visOffset, &wsType);
|
||||
if (wsType == WSType::normalWS || wsType == WSType::text ||
|
||||
wsType == WSType::special) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
WSRunObject wsObjAfterBR(mHTMLEditor, selNode, selOffset + 1);
|
||||
WSRunObject wsObjAfterBR(htmlEditor, selNode, selOffset + 1);
|
||||
wsObjAfterBR.NextVisibleNode(selNode, selOffset + 1,
|
||||
address_of(visNode), &visOffset, &wsType);
|
||||
if (wsType == WSType::normalWS || wsType == WSType::text ||
|
||||
wsType == WSType::special ||
|
||||
// In case we're at the very end.
|
||||
wsType == WSType::thisBlock) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
brNode = mHTMLEditor->CreateBR(selNode, selOffset);
|
||||
brNode = htmlEditor->CreateBR(EditorRawDOMPoint(selNode, selOffset));
|
||||
NS_ENSURE_STATE(brNode);
|
||||
}
|
||||
}
|
||||
|
@ -2075,14 +2109,12 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
// delete any empty cites
|
||||
bool bEmptyCite = false;
|
||||
if (leftCite) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->IsEmptyNode(leftCite, &bEmptyCite, true, false);
|
||||
rv = htmlEditor->IsEmptyNode(leftCite, &bEmptyCite, true, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (bEmptyCite) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->DeleteNode(leftCite);
|
||||
rv = htmlEditor->DeleteNode(leftCite);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2090,14 +2122,12 @@ HTMLEditRules::SplitMailCites(Selection* aSelection,
|
|||
}
|
||||
|
||||
if (citeNode) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
|
||||
rv = htmlEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (bEmptyCite) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->DeleteNode(citeNode);
|
||||
rv = htmlEditor->DeleteNode(citeNode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2831,36 +2861,41 @@ HTMLEditRules::DeleteNodeIfCollapsedText(nsINode& aNode)
|
|||
nsresult
|
||||
HTMLEditRules::InsertBRIfNeeded(Selection* aSelection)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
|
||||
if (NS_WARN_IF(!aSelection)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// get selection
|
||||
nsCOMPtr<nsINode> node;
|
||||
int32_t offset;
|
||||
nsresult rv =
|
||||
EditorBase::GetStartNodeAndOffset(aSelection,
|
||||
getter_AddRefs(node), &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
EditorRawDOMPoint atStartOfSelection(EditorBase::GetStartPoint(aSelection));
|
||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// inline elements don't need any br
|
||||
if (!IsBlockNode(*node)) {
|
||||
if (!IsBlockNode(*atStartOfSelection.GetContainer())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// examine selection
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
WSRunObject wsObj(mHTMLEditor, node, offset);
|
||||
WSRunObject wsObj(htmlEditor, atStartOfSelection.GetContainer(),
|
||||
atStartOfSelection.Offset());
|
||||
if (((wsObj.mStartReason & WSType::block) ||
|
||||
(wsObj.mStartReason & WSType::br)) &&
|
||||
(wsObj.mEndReason & WSType::block)) {
|
||||
// if we are tucked between block boundaries then insert a br
|
||||
// first check that we are allowed to
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
if (mHTMLEditor->CanContainTag(*node, *nsGkAtoms::br)) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> br =
|
||||
mHTMLEditor->CreateBR(node, offset, nsIEditor::ePrevious);
|
||||
return br ? NS_OK : NS_ERROR_FAILURE;
|
||||
if (htmlEditor->CanContainTag(*atStartOfSelection.GetContainer(),
|
||||
*nsGkAtoms::br)) {
|
||||
RefPtr<Element> br =
|
||||
htmlEditor->CreateBR(atStartOfSelection, nsIEditor::ePrevious);
|
||||
if (NS_WARN_IF(!br)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -3383,33 +3418,42 @@ HTMLEditRules::DidDeleteSelection(Selection* aSelection,
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
// find where we are
|
||||
nsCOMPtr<nsINode> startNode;
|
||||
int32_t startOffset;
|
||||
nsresult rv = EditorBase::GetStartNodeAndOffset(aSelection,
|
||||
getter_AddRefs(startNode),
|
||||
&startOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
||||
EditorDOMPoint atStartOfSelection(EditorBase::GetStartPoint(aSelection));
|
||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// find any enclosing mailcite
|
||||
nsCOMPtr<Element> citeNode = GetTopEnclosingMailCite(*startNode);
|
||||
nsCOMPtr<Element> citeNode =
|
||||
GetTopEnclosingMailCite(*atStartOfSelection.GetContainer());
|
||||
if (citeNode) {
|
||||
bool isEmpty = true, seenBR = false;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
mHTMLEditor->IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false,
|
||||
&seenBR);
|
||||
htmlEditor->IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false,
|
||||
&seenBR);
|
||||
if (isEmpty) {
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsINode> parent = EditorBase::GetNodeLocation(citeNode, &offset);
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
rv = mHTMLEditor->DeleteNode(citeNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (parent && seenBR) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> brNode = mHTMLEditor->CreateBR(parent, offset);
|
||||
NS_ENSURE_STATE(brNode);
|
||||
aSelection->Collapse(parent, offset);
|
||||
EditorDOMPoint atCiteNode(citeNode);
|
||||
{
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(atCiteNode);
|
||||
nsresult rv = htmlEditor->DeleteNode(citeNode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (atCiteNode.IsSet() && seenBR) {
|
||||
RefPtr<Element> brNode = htmlEditor->CreateBR(atCiteNode.AsRaw());
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
IgnoredErrorResult error;
|
||||
aSelection->Collapse(EditorRawDOMPoint(brNode), error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Failed to collapse selection at the new <br> element");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3881,8 +3925,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
|
|||
}
|
||||
EditorRawDOMPoint pointToInsertBrNode(splitNodeResult.SplitPoint());
|
||||
// Put a br at the split point
|
||||
brNode = htmlEditor->CreateBR(pointToInsertBrNode.GetContainer(),
|
||||
pointToInsertBrNode.Offset());
|
||||
brNode = htmlEditor->CreateBR(pointToInsertBrNode);
|
||||
NS_ENSURE_STATE(brNode);
|
||||
// Put selection at the split point
|
||||
EditorRawDOMPoint atBrNode(brNode);
|
||||
|
@ -5076,8 +5119,10 @@ HTMLEditRules::WillAlign(Selection& aSelection,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aHandled = true;
|
||||
// Put in a moz-br so that it won't get deleted
|
||||
rv = CreateMozBR(*div, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> brElement = CreateMozBR(EditorRawDOMPoint(div, 0));
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
EditorRawDOMPoint atStartOfDiv(div, 0);
|
||||
ErrorResult error;
|
||||
aSelection.Collapse(atStartOfDiv, error);
|
||||
|
@ -5292,7 +5337,10 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
|||
if (aBodyNode && IsInlineNode(*aBodyNode)) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
// If we are inside an empty block, delete it. Note: do NOT delete table
|
||||
|
@ -5321,22 +5369,24 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
|||
|
||||
if (HTMLEditUtils::IsListItem(emptyBlock)) {
|
||||
// Are we the first list item in the list?
|
||||
NS_ENSURE_STATE(htmlEditor);
|
||||
if (htmlEditor->IsFirstEditableChild(emptyBlock)) {
|
||||
nsCOMPtr<nsINode> listParent = blockParent->GetParentNode();
|
||||
NS_ENSURE_TRUE(listParent, NS_ERROR_FAILURE);
|
||||
EditorDOMPoint atBlockParent(blockParent);
|
||||
if (NS_WARN_IF(!atBlockParent.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// If we are a sublist, skip the br creation
|
||||
if (!HTMLEditUtils::IsList(listParent)) {
|
||||
int32_t listOffset = listParent->IndexOf(blockParent);
|
||||
|
||||
if (!HTMLEditUtils::IsList(atBlockParent.GetContainer())) {
|
||||
// Create a br before list
|
||||
NS_ENSURE_STATE(htmlEditor);
|
||||
nsCOMPtr<Element> br =
|
||||
htmlEditor->CreateBR(listParent, listOffset);
|
||||
NS_ENSURE_STATE(br);
|
||||
RefPtr<Element> br = htmlEditor->CreateBR(atBlockParent.AsRaw());
|
||||
if (NS_WARN_IF(!br)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Adjust selection to be right before it
|
||||
nsresult rv = aSelection->Collapse(listParent, listOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult error;
|
||||
aSelection->Collapse(EditorRawDOMPoint(br), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
// Else just let selection percolate up. We'll adjust it in
|
||||
// AfterEdit()
|
||||
|
@ -5387,7 +5437,6 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
|||
MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet");
|
||||
}
|
||||
}
|
||||
NS_ENSURE_STATE(htmlEditor);
|
||||
*aHandled = true;
|
||||
nsresult rv = htmlEditor->DeleteNode(emptyBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -6768,8 +6817,10 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
|
|||
rv = htmlEditor->IsEmptyNode(prevItem, &isEmptyNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isEmptyNode) {
|
||||
rv = CreateMozBR(*prevItem, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> brElement = CreateMozBR(EditorRawDOMPoint(prevItem, 0));
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6801,12 +6852,18 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
|
|||
NS_ENSURE_STATE(pNode);
|
||||
|
||||
// Append a <br> to it
|
||||
nsCOMPtr<Element> brNode = htmlEditor->CreateBR(pNode, 0);
|
||||
NS_ENSURE_STATE(brNode);
|
||||
RefPtr<Element> brNode =
|
||||
htmlEditor->CreateBR(EditorRawDOMPoint(pNode, 0));
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set selection to before the break
|
||||
rv = aSelection.Collapse(pNode, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult error;
|
||||
aSelection.Collapse(EditorRawDOMPoint(pNode, 0), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
} else {
|
||||
EditorRawDOMPoint afterSibling(sibling);
|
||||
if (NS_WARN_IF(!afterSibling.AdvanceOffset())) {
|
||||
|
@ -6933,8 +6990,7 @@ HTMLEditRules::ReturnInParagraph(Selection& aSelection,
|
|||
return EditActionResult(NS_OK);
|
||||
}
|
||||
|
||||
brNode = htmlEditor->CreateBR(pointToInsertBR.GetContainer(),
|
||||
pointToInsertBR.Offset());
|
||||
brNode = htmlEditor->CreateBR(pointToInsertBR);
|
||||
if (splitAfterNewBR) {
|
||||
// We split the parent after the br we've just inserted.
|
||||
pointToSplitParentDivOrP.Set(brNode);
|
||||
|
@ -7097,12 +7153,18 @@ HTMLEditRules::ReturnInListItem(Selection& aSelection,
|
|||
NS_ENSURE_STATE(pNode);
|
||||
|
||||
// Append a <br> to it
|
||||
nsCOMPtr<Element> brNode = htmlEditor->CreateBR(pNode, 0);
|
||||
NS_ENSURE_STATE(brNode);
|
||||
RefPtr<Element> brNode =
|
||||
htmlEditor->CreateBR(EditorRawDOMPoint(pNode, 0));
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set selection to before the break
|
||||
rv = aSelection.Collapse(pNode, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult error;
|
||||
aSelection.Collapse(EditorRawDOMPoint(pNode, 0), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -7133,8 +7195,10 @@ HTMLEditRules::ReturnInListItem(Selection& aSelection,
|
|||
rv = htmlEditor->IsEmptyNode(prevItem, &isEmptyNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isEmptyNode) {
|
||||
rv = CreateMozBR(*prevItem, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> brElement = CreateMozBR(EditorRawDOMPoint(prevItem, 0));
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
rv = htmlEditor->IsEmptyNode(&aListItem, &isEmptyNode, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -7857,8 +7921,10 @@ HTMLEditRules::AdjustSpecialBreaks()
|
|||
// still pass the "IsEmptyNode" test, and we want the br's to be after
|
||||
// them. Also, we want the br to be after the selection if the selection
|
||||
// is in this node.
|
||||
nsresult rv = CreateMozBR(*node, (int32_t)node->Length());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
EditorRawDOMPoint endOfNode;
|
||||
endOfNode.SetToEndOf(node);
|
||||
RefPtr<Element> brElement = CreateMozBR(endOfNode);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -8011,7 +8077,14 @@ nsresult
|
|||
HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||
nsIEditor::EDirection aAction)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
|
||||
if (NS_WARN_IF(!aSelection)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
// if the selection isn't collapsed, do nothing.
|
||||
// moose: one thing to do instead is check for the case of
|
||||
|
@ -8027,8 +8100,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
}
|
||||
|
||||
// are we in an editable node?
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
while (!mHTMLEditor->IsEditable(point.GetContainer())) {
|
||||
while (!htmlEditor->IsEditable(point.GetContainer())) {
|
||||
// scan up the tree until we find an editable place to be
|
||||
point.Set(point.GetContainer());
|
||||
if (NS_WARN_IF(!point.IsSet())) {
|
||||
|
@ -8038,23 +8110,21 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
|
||||
// make sure we aren't in an empty block - user will see no cursor. If this
|
||||
// is happening, put a <br> in the block if allowed.
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> theblock = mHTMLEditor->GetBlock(*point.GetContainer());
|
||||
RefPtr<Element> theblock = htmlEditor->GetBlock(*point.GetContainer());
|
||||
|
||||
if (theblock && mHTMLEditor->IsEditable(theblock)) {
|
||||
if (theblock && htmlEditor->IsEditable(theblock)) {
|
||||
bool bIsEmptyNode;
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsresult rv =
|
||||
mHTMLEditor->IsEmptyNode(theblock, &bIsEmptyNode, false, false);
|
||||
htmlEditor->IsEmptyNode(theblock, &bIsEmptyNode, false, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// check if br can go into the destination node
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
if (bIsEmptyNode &&
|
||||
mHTMLEditor->CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> rootNode = mHTMLEditor->GetRoot();
|
||||
NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
|
||||
if (point.GetContainer() == rootNode) {
|
||||
htmlEditor->CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) {
|
||||
Element* rootElement = htmlEditor->GetRoot();
|
||||
if (NS_WARN_IF(!rootElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
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()!
|
||||
|
@ -8062,7 +8132,11 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
}
|
||||
|
||||
// we know we can skip the rest of this routine given the cirumstance
|
||||
return CreateMozBR(*point.GetContainer(), point.Offset());
|
||||
RefPtr<Element> brElement = CreateMozBR(point.AsRaw());
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8076,27 +8150,23 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
// 2) prior node is a br AND
|
||||
// 3) that br is not visible
|
||||
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsIContent> nearNode =
|
||||
mHTMLEditor->GetPreviousEditableHTMLNode(point.AsRaw());
|
||||
htmlEditor->GetPreviousEditableHTMLNode(point.AsRaw());
|
||||
if (nearNode) {
|
||||
// is nearNode also a descendant of same block?
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<Element> block = mHTMLEditor->GetBlock(*point.GetContainer());
|
||||
nsCOMPtr<Element> nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
|
||||
RefPtr<Element> block = htmlEditor->GetBlock(*point.GetContainer());
|
||||
RefPtr<Element> nearBlock = htmlEditor->GetBlockNodeParent(nearNode);
|
||||
if (block && block == nearBlock) {
|
||||
if (nearNode && TextEditUtils::IsBreak(nearNode)) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
if (!mHTMLEditor->IsVisibleBRElement(nearNode)) {
|
||||
if (!htmlEditor->IsVisibleBRElement(nearNode)) {
|
||||
// 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.
|
||||
RefPtr<Element> br;
|
||||
nsresult rv =
|
||||
CreateMozBR(*point.GetContainer(), point.Offset(),
|
||||
getter_AddRefs(br));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
point.Set(br);
|
||||
RefPtr<Element> brElement = CreateMozBR(point.AsRaw());
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
point.Set(brElement);
|
||||
// selection stays *before* moz-br, sticking to it
|
||||
aSelection->SetInterlinePosition(true);
|
||||
ErrorResult error;
|
||||
|
@ -8105,9 +8175,8 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
return error.StealNSResult();
|
||||
}
|
||||
} else {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsCOMPtr<nsIContent> nextNode =
|
||||
mHTMLEditor->GetNextEditableHTMLNodeInBlock(*nearNode);
|
||||
htmlEditor->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.
|
||||
|
@ -8119,8 +8188,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
}
|
||||
|
||||
// we aren't in a textnode: are we adjacent to text or a break or an image?
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nearNode = mHTMLEditor->GetPreviousEditableHTMLNodeInBlock(point.AsRaw());
|
||||
nearNode = htmlEditor->GetPreviousEditableHTMLNodeInBlock(point.AsRaw());
|
||||
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
||||
EditorBase::IsTextNode(nearNode) ||
|
||||
HTMLEditUtils::IsImage(nearNode) ||
|
||||
|
@ -8128,8 +8196,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
|||
// this is a good place for the caret to be
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nearNode = mHTMLEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
|
||||
nearNode = htmlEditor->GetNextEditableHTMLNodeInBlock(point.AsRaw());
|
||||
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
||||
EditorBase::IsTextNode(nearNode) ||
|
||||
nearNode->IsAnyOfHTMLElements(nsGkAtoms::img,
|
||||
|
@ -8345,7 +8412,7 @@ HTMLEditRules::RemoveEmptyNodes()
|
|||
}
|
||||
|
||||
// now delete the empty nodes
|
||||
for (auto& delNode : arrayOfEmptyNodes) {
|
||||
for (OwningNonNull<nsINode>& delNode : arrayOfEmptyNodes) {
|
||||
if (htmlEditor->IsModifiableNode(delNode)) {
|
||||
rv = htmlEditor->DeleteNode(delNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -8354,17 +8421,17 @@ HTMLEditRules::RemoveEmptyNodes()
|
|||
|
||||
// Now delete the empty mailcites. This is a separate step because we want
|
||||
// to pull out any br's and preserve them.
|
||||
for (auto& delNode : arrayOfEmptyCites) {
|
||||
for (OwningNonNull<nsINode>& delNode : arrayOfEmptyCites) {
|
||||
bool bIsEmptyNode;
|
||||
rv = htmlEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!bIsEmptyNode) {
|
||||
// We are deleting a cite that has just a br. We want to delete cite,
|
||||
// but preserve br.
|
||||
nsCOMPtr<nsINode> parent = delNode->GetParentNode();
|
||||
int32_t offset = parent ? parent->IndexOf(delNode) : -1;
|
||||
nsCOMPtr<Element> br = htmlEditor->CreateBR(parent, offset);
|
||||
NS_ENSURE_STATE(br);
|
||||
RefPtr<Element> br = htmlEditor->CreateBR(EditorRawDOMPoint(delNode));
|
||||
if (NS_WARN_IF(!br)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
rv = htmlEditor->DeleteNode(delNode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -8735,8 +8802,12 @@ HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
return aInsertMozBR ? CreateMozBR(aNode, 0) :
|
||||
CreateBR(aNode, 0);
|
||||
RefPtr<Element> brElement =
|
||||
CreateBRInternal(EditorRawDOMPoint(&aNode, 0), aInsertMozBR);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -9036,27 +9107,24 @@ nsresult
|
|||
HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode,
|
||||
bool aStarts)
|
||||
{
|
||||
nsCOMPtr<nsINode> child;
|
||||
if (aStarts) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
child = mHTMLEditor->GetFirstEditableChild(aNode);
|
||||
} else {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
child = mHTMLEditor->GetLastEditableChild(aNode);
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
NS_ENSURE_TRUE(child, NS_OK);
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
nsINode* child = aStarts ? htmlEditor->GetFirstEditableChild(aNode) :
|
||||
htmlEditor->GetLastEditableChild(aNode);
|
||||
if (NS_WARN_IF(!child)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool foundCR = false;
|
||||
if (IsBlockNode(*child) || child->IsHTMLElement(nsGkAtoms::br)) {
|
||||
foundCR = true;
|
||||
} else {
|
||||
nsCOMPtr<nsINode> sibling;
|
||||
if (aStarts) {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
sibling = mHTMLEditor->GetPriorHTMLSibling(&aNode);
|
||||
} else {
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
sibling = mHTMLEditor->GetNextHTMLSibling(&aNode);
|
||||
}
|
||||
nsINode* sibling =
|
||||
aStarts ? htmlEditor->GetPriorHTMLSibling(&aNode) :
|
||||
htmlEditor->GetNextHTMLSibling(&aNode);
|
||||
if (sibling) {
|
||||
if (IsBlockNode(*sibling) || sibling->IsHTMLElement(nsGkAtoms::br)) {
|
||||
foundCR = true;
|
||||
|
@ -9066,12 +9134,13 @@ HTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsINode& aNode,
|
|||
}
|
||||
}
|
||||
if (!foundCR) {
|
||||
int32_t offset = 0;
|
||||
EditorRawDOMPoint pointToInsert;
|
||||
if (!aStarts) {
|
||||
offset = aNode.GetChildCount();
|
||||
pointToInsert.SetToEndOf(&aNode);
|
||||
} else {
|
||||
pointToInsert.Set(&aNode, 0);
|
||||
}
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
RefPtr<Element> brNode = mHTMLEditor->CreateBR(&aNode, offset);
|
||||
RefPtr<Element> brNode = htmlEditor->CreateBR(pointToInsert);
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -158,8 +158,17 @@ protected:
|
|||
nsresult WillLoadHTML(Selection* aSelection, bool* aCancel);
|
||||
nsresult WillInsertBreak(Selection& aSelection, bool* aCancel,
|
||||
bool* aHandled);
|
||||
nsresult StandardBreakImpl(nsINode& aNode, int32_t aOffset,
|
||||
Selection& aSelection);
|
||||
|
||||
/**
|
||||
* InsertBRElement() inserts a <br> element into aInsertToBreak.
|
||||
*
|
||||
* @param aSelection The selection.
|
||||
* @param aInsertToBreak The point where new <br> element will be
|
||||
* inserted before.
|
||||
*/
|
||||
nsresult InsertBRElement(Selection& aSelection,
|
||||
const EditorDOMPoint& aInsertToBreak);
|
||||
|
||||
nsresult DidInsertBreak(Selection* aSelection, nsresult aResult);
|
||||
nsresult SplitMailCites(Selection* aSelection, bool* aHandled);
|
||||
nsresult WillDeleteSelection(Selection* aSelection,
|
||||
|
|
|
@ -3733,8 +3733,10 @@ HTMLEditor::RemoveBlockContainer(nsIContent& aNode)
|
|||
if (sibling && !IsBlockNode(sibling) &&
|
||||
!sibling->IsHTMLElement(nsGkAtoms::br) && !IsBlockNode(child)) {
|
||||
// Insert br node
|
||||
nsCOMPtr<Element> br = CreateBR(&aNode, 0);
|
||||
NS_ENSURE_STATE(br);
|
||||
RefPtr<Element> brElement = CreateBR(EditorRawDOMPoint(&aNode, 0));
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// We need a br at end unless:
|
||||
|
@ -3749,8 +3751,12 @@ HTMLEditor::RemoveBlockContainer(nsIContent& aNode)
|
|||
MOZ_ASSERT(child, "aNode has first editable child but not last?");
|
||||
if (!IsBlockNode(child) && !child->IsHTMLElement(nsGkAtoms::br)) {
|
||||
// Insert br node
|
||||
nsCOMPtr<Element> br = CreateBR(&aNode, aNode.Length());
|
||||
NS_ENSURE_STATE(br);
|
||||
EditorRawDOMPoint endOfNode;
|
||||
endOfNode.SetToEndOf(&aNode);
|
||||
RefPtr<Element> brElement = CreateBR(endOfNode);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -3767,8 +3773,10 @@ HTMLEditor::RemoveBlockContainer(nsIContent& aNode)
|
|||
if (sibling && !IsBlockNode(sibling) &&
|
||||
!sibling->IsHTMLElement(nsGkAtoms::br)) {
|
||||
// Insert br node
|
||||
nsCOMPtr<Element> br = CreateBR(&aNode, 0);
|
||||
NS_ENSURE_STATE(br);
|
||||
RefPtr<Element> brElement = CreateBR(EditorRawDOMPoint(&aNode, 0));
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4469,7 +4477,7 @@ HTMLEditor::CopyLastEditableChildStyles(nsINode* aPreviousBlock,
|
|||
childElement = childElement->GetParentElement();
|
||||
}
|
||||
if (deepestStyle) {
|
||||
RefPtr<Element> retVal = CreateBR(deepestStyle, 0);
|
||||
RefPtr<Element> retVal = CreateBR(EditorRawDOMPoint(deepestStyle, 0));
|
||||
retVal.forget(aOutBrNode);
|
||||
NS_ENSURE_STATE(*aOutBrNode);
|
||||
}
|
||||
|
|
|
@ -1376,7 +1376,13 @@ TextEditRules::CreateTrailingBRIfNeeded()
|
|||
|
||||
if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(mTextEditor);
|
||||
return CreateMozBR(*body, body->Length());
|
||||
EditorRawDOMPoint endOfBody;
|
||||
endOfBody.SetToEndOf(body);
|
||||
RefPtr<Element> brElement = CreateMozBR(endOfBody);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check to see if the trailing BR is a former bogus node - this will have
|
||||
|
@ -1638,33 +1644,37 @@ TextEditRules::FillBufWithPWChars(nsAString* aOutString,
|
|||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
TextEditRules::CreateBRInternal(nsINode& inParent,
|
||||
int32_t inOffset,
|
||||
bool aMozBR,
|
||||
Element** aOutBRElement)
|
||||
already_AddRefed<Element>
|
||||
TextEditRules::CreateBRInternal(const EditorRawDOMPoint& aPointToInsert,
|
||||
bool aCreateMozBR)
|
||||
{
|
||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mTextEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<TextEditor> textEditor = mTextEditor;
|
||||
|
||||
RefPtr<Element> brElem = textEditor->CreateBR(&inParent, inOffset);
|
||||
if (NS_WARN_IF(!brElem)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
RefPtr<Element> brElement = textEditor->CreateBR(aPointToInsert);
|
||||
if (NS_WARN_IF(!brElement)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// give it special moz attr
|
||||
if (aMozBR) {
|
||||
nsresult rv = textEditor->SetAttribute(brElem, nsGkAtoms::type,
|
||||
if (aCreateMozBR) {
|
||||
// XXX Why do we need to set this attribute with transaction?
|
||||
nsresult rv = textEditor->SetAttribute(brElement, nsGkAtoms::type,
|
||||
NS_LITERAL_STRING("_moz"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// XXX Don't we need to remove the new <br> element from the DOM tree
|
||||
// in this case?
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aOutBRElement) {
|
||||
brElem.forget(aOutBRElement);
|
||||
}
|
||||
return NS_OK;
|
||||
return brElement.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -218,33 +218,43 @@ protected:
|
|||
void RemoveIMETextFromPWBuf(uint32_t& aStart, nsAString* aIMEString);
|
||||
|
||||
/**
|
||||
* Create a normal <br> element and insert it to aOffset at aParent.
|
||||
* Create a normal <br> element and insert it to aPointToInsert.
|
||||
*
|
||||
* @param aParent The parent node which will have new <br> element.
|
||||
* @param aOffset The offset in aParent where the new <br> element will
|
||||
* be inserted.
|
||||
* @param aOutBRNode Returns created <br> element.
|
||||
* @param aPointToInsert The point where the new <br> element will be
|
||||
* inserted.
|
||||
* @return Returns created <br> element.
|
||||
*/
|
||||
nsresult CreateBR(nsINode& aParent, int32_t aOffset,
|
||||
Element** aOutBRNode = nullptr)
|
||||
already_AddRefed<Element> CreateBR(const EditorRawDOMPoint& aPointToInsert)
|
||||
{
|
||||
return CreateBRInternal(aParent, aOffset, false, aOutBRNode);
|
||||
return CreateBRInternal(aPointToInsert, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a moz-<br> element and insert it to aOffset at aParent.
|
||||
* Create a moz-<br> element and insert it to aPointToInsert.
|
||||
*
|
||||
* @param aParent The parent node which will have new <br> element.
|
||||
* @param aOffset The offset in aParent where the new <br> element will
|
||||
* be inserted.
|
||||
* @param aOutBRNode Returns created <br> element.
|
||||
* @param aPointToInsert The point where the new moz-<br> element will be
|
||||
* inserted.
|
||||
* @return Returns created moz-<br> element.
|
||||
*/
|
||||
nsresult CreateMozBR(nsINode& aParent, int32_t aOffset,
|
||||
Element** aOutBRNode = nullptr)
|
||||
already_AddRefed<Element> CreateMozBR(const EditorRawDOMPoint& aPointToInsert)
|
||||
{
|
||||
return CreateBRInternal(aParent, aOffset, true, aOutBRNode);
|
||||
return CreateBRInternal(aPointToInsert, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
already_AddRefed<Element>
|
||||
CreateBRInternal(const EditorRawDOMPoint& aPointToInsert,
|
||||
bool aCreateMozBR);
|
||||
|
||||
void UndefineCaretBidiLevel(Selection* aSelection);
|
||||
|
||||
nsresult CheckBidiLevelForDeletion(Selection* aSelection,
|
||||
|
@ -269,23 +279,6 @@ private:
|
|||
// Note that we do not refcount the editor.
|
||||
TextEditor* mTextEditor;
|
||||
|
||||
/**
|
||||
* Create a normal <br> element or a moz-<br> element and insert it to
|
||||
* aOffset at aParent.
|
||||
*
|
||||
* @param aParent The parent node which will have new <br> element.
|
||||
* @param aOffset The offset in aParent where the new <br> element will
|
||||
* be inserted.
|
||||
* @param aMozBR true if the caller wants to create a moz-<br> element.
|
||||
* Otherwise, false.
|
||||
* @param aOutBRNode Returns created <br> element.
|
||||
*/
|
||||
nsresult CreateBRInternal(nsINode& aParent,
|
||||
int32_t aOffset,
|
||||
bool aMozBR,
|
||||
Element** aOutBRNode = nullptr);
|
||||
|
||||
|
||||
protected:
|
||||
// A buffer we use to store the real value of password editors.
|
||||
nsString mPasswordText;
|
||||
|
|
|
@ -417,8 +417,7 @@ TextEditor::TypedText(const nsAString& aString, ETypingAction aAction)
|
|||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
TextEditor::CreateBR(nsINode* aNode,
|
||||
int32_t aOffset,
|
||||
TextEditor::CreateBR(const EditorRawDOMPoint& aPointToInsert,
|
||||
EDirection aSelect /* = eNone */)
|
||||
{
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
|
@ -426,7 +425,7 @@ TextEditor::CreateBR(nsINode* aNode,
|
|||
return nullptr;
|
||||
}
|
||||
// We assume everything is fine if newBRElement is not null.
|
||||
return CreateBRImpl(*selection, EditorRawDOMPoint(aNode, aOffset), aSelect);
|
||||
return CreateBRImpl(*selection, aPointToInsert, aSelect);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
|
|
|
@ -188,20 +188,19 @@ protected:
|
|||
const nsACString& aCharset);
|
||||
|
||||
/**
|
||||
* CreateBR() creates new <br> element and inserts it before the point,
|
||||
* aNode - aOffset, and collapse selection if it's necessary.
|
||||
* CreateBR() creates new <br> element and inserts it before aPointToInsert,
|
||||
* and collapse selection if it's necessary.
|
||||
*
|
||||
* @param aNode The container node to insert new <br> element.
|
||||
* @param aOffset The offset in aNode to insert new <br> element.
|
||||
* @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.
|
||||
* @param aPointToInsert The point to insert new <br> element.
|
||||
* @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.
|
||||
*/
|
||||
already_AddRefed<Element> CreateBR(nsINode* aNode, int32_t aOffset,
|
||||
already_AddRefed<Element> CreateBR(const EditorRawDOMPoint& aPointToInsert,
|
||||
EDirection aSelect = eNone);
|
||||
|
||||
/**
|
||||
|
|
|
@ -1754,6 +1754,11 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
|
||||
|
||||
// first check for trailing nbsp
|
||||
WSPoint thePoint = GetPreviousCharPoint(aRun->EndPoint());
|
||||
if (thePoint.mTextNode && thePoint.mChar == nbsp) {
|
||||
|
@ -1800,9 +1805,10 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
|
|||
// beginning of soft wrapped lines, and lets the user see 2 spaces when
|
||||
// they type 2 spaces.
|
||||
|
||||
nsCOMPtr<Element> brNode =
|
||||
mHTMLEditor->CreateBR(aRun->mEndNode, aRun->mEndOffset);
|
||||
NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE);
|
||||
RefPtr<Element> brNode = htmlEditor->CreateBR(aRun->EndPoint());
|
||||
if (NS_WARN_IF(!brNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Refresh thePoint, prevPoint
|
||||
thePoint = GetPreviousCharPoint(aRun->EndPoint());
|
||||
|
@ -1812,11 +1818,11 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
|
|||
}
|
||||
if (leftCheck && rightCheck) {
|
||||
// Now replace nbsp with space. First, insert a space
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(htmlEditor);
|
||||
nsAutoString spaceStr(char16_t(32));
|
||||
nsresult rv =
|
||||
mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, *thePoint.mTextNode,
|
||||
thePoint.mOffset, true);
|
||||
htmlEditor->InsertTextIntoTextNodeImpl(spaceStr, *thePoint.mTextNode,
|
||||
thePoint.mOffset, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Finally, delete that nbsp
|
||||
|
@ -1851,10 +1857,10 @@ WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
|
|||
}
|
||||
|
||||
// Finally, insert that nbsp before the ASCII ws run
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(htmlEditor);
|
||||
nsAutoString nbspStr(nbsp);
|
||||
rv = mHTMLEditor->InsertTextIntoTextNodeImpl(nbspStr, *startNode,
|
||||
startOffset, true);
|
||||
rv = htmlEditor->InsertTextIntoTextNodeImpl(nbspStr, *startNode,
|
||||
startOffset, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ impl BlobImageRenderer for Moz2dImageRenderer {
|
|||
let buf_size = (descriptor.width
|
||||
* descriptor.height
|
||||
* descriptor.format.bytes_per_pixel()) as usize;
|
||||
let mut output = vec![255u8; buf_size];
|
||||
let mut output = vec![0u8; buf_size];
|
||||
|
||||
let result = unsafe {
|
||||
if wr_moz2d_render_cb(
|
||||
|
|
|
@ -4330,6 +4330,7 @@ public:
|
|||
nsDisplayEventReceiver(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame) {
|
||||
MOZ_COUNT_CTOR(nsDisplayEventReceiver);
|
||||
MOZ_ASSERT(aBuilder->IsForEventDelivery());
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayEventReceiver() {
|
||||
|
|
|
@ -371,7 +371,7 @@ nsSplitterFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
nsBoxFrame::BuildDisplayList(aBuilder, aLists);
|
||||
|
||||
// if the mouse is captured always return us as the frame.
|
||||
if (mInner->mDragging)
|
||||
if (mInner->mDragging && aBuilder->IsForEventDelivery())
|
||||
{
|
||||
// XXX It's probably better not to check visibility here, right?
|
||||
aLists.Outlines()->AppendNewToTop(new (aBuilder)
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.os.HandlerThread;
|
|||
import android.util.Log;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
|
@ -28,6 +29,7 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedT
|
|||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
||||
|
@ -560,8 +562,19 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
|
|||
mRenderers[0] = mVRenderer;
|
||||
mRenderers[1] = mARenderer;
|
||||
|
||||
// Use default values for constructing DefaultLoadControl except maxBufferMs.
|
||||
// See Bug 1424168.
|
||||
int maxBufferMs = Math.max(DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
|
||||
DefaultLoadControl.DEFAULT_MAX_BUFFER_MS / 2);
|
||||
DefaultLoadControl dlc =
|
||||
new DefaultLoadControl(
|
||||
new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
|
||||
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
|
||||
maxBufferMs, /*this value can eliminate the memory usage immensely by experiment*/
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
|
||||
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
|
||||
// Create ExoPlayer instance with specific components.
|
||||
mPlayer = ExoPlayerFactory.newInstance(mRenderers, mTrackSelector);
|
||||
mPlayer = ExoPlayerFactory.newInstance(mRenderers, mTrackSelector, dlc);
|
||||
mPlayer.addListener(this);
|
||||
|
||||
Uri uri = Uri.parse(url);
|
||||
|
|
|
@ -2160,13 +2160,15 @@ nsHttpConnectionMgr::GetSpdyActiveConn(nsConnectionEntry *ent)
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
||||
nsHttpConnectionMgr::AbortAndCloseAllConnections(int32_t, ARefBase *)
|
||||
{
|
||||
if (!OnSocketThread()) {
|
||||
Unused << PostEvent(&nsHttpConnectionMgr::AbortAndCloseAllConnections);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
|
||||
|
||||
gHttpHandler->StopRequestTokenBucket();
|
||||
|
||||
LOG(("nsHttpConnectionMgr::AbortAndCloseAllConnections\n"));
|
||||
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
|
||||
RefPtr<nsConnectionEntry> ent = iter.Data();
|
||||
|
||||
|
@ -2224,6 +2226,23 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
|||
iter.Remove();
|
||||
}
|
||||
|
||||
mActiveTransactions[false].Clear();
|
||||
mActiveTransactions[true].Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
|
||||
|
||||
gHttpHandler->StopRequestTokenBucket();
|
||||
AbortAndCloseAllConnections(0, nullptr);
|
||||
|
||||
// If all idle connections are removed we can stop pruning dead
|
||||
// connections.
|
||||
ConditionallyStopPruneDeadConnectionsTimer();
|
||||
|
||||
if (mTimeoutTick) {
|
||||
mTimeoutTick->Cancel();
|
||||
mTimeoutTick = nullptr;
|
||||
|
@ -2238,8 +2257,6 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
|||
mTrafficTimer = nullptr;
|
||||
}
|
||||
DestroyThrottleTicker();
|
||||
mActiveTransactions[false].Clear();
|
||||
mActiveTransactions[true].Clear();
|
||||
|
||||
mCoalescingHash.Clear();
|
||||
|
||||
|
|
|
@ -95,6 +95,9 @@ public:
|
|||
// given time.
|
||||
void PruneDeadConnectionsAfter(uint32_t time);
|
||||
|
||||
// this cancels all outstanding transactions but does not shut down the mgr
|
||||
void AbortAndCloseAllConnections(int32_t, ARefBase *);
|
||||
|
||||
// Stops timer scheduled for next pruning of dead connections if
|
||||
// there are no more idle connections or active spdy ones
|
||||
void ConditionallyStopPruneDeadConnectionsTimer();
|
||||
|
|
|
@ -545,6 +545,7 @@ nsHttpHandler::Init()
|
|||
obsService->AddObserver(this, "net:prune-dead-connections", true);
|
||||
// Sent by the TorButton add-on in the Tor Browser
|
||||
obsService->AddObserver(this, "net:prune-all-connections", true);
|
||||
obsService->AddObserver(this, "net:cancel-all-connections", true);
|
||||
obsService->AddObserver(this, "last-pb-context-exited", true);
|
||||
obsService->AddObserver(this, "browser:purge-session-history", true);
|
||||
obsService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
|
||||
|
@ -2277,6 +2278,10 @@ nsHttpHandler::Observe(nsISupports *subject,
|
|||
} else if (!strcmp(topic, "net:clear-active-logins")) {
|
||||
Unused << mAuthCache.ClearAll();
|
||||
Unused << mPrivateAuthCache.ClearAll();
|
||||
} else if (!strcmp(topic, "net:cancel-all-connections")) {
|
||||
if (mConnMgr) {
|
||||
mConnMgr->AbortAndCloseAllConnections(0, nullptr);
|
||||
}
|
||||
} else if (!strcmp(topic, "net:prune-dead-connections")) {
|
||||
if (mConnMgr) {
|
||||
rv = mConnMgr->PruneDeadConnections();
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
// Test bug 1411316.
|
||||
//
|
||||
// Summary:
|
||||
// The purpose of this test is to test whether the HttpConnectionMgr really
|
||||
// cancel and close all connecitons when get "net:cancel-all-connections".
|
||||
//
|
||||
// Test step:
|
||||
// 1. Create 6 http requests. Server would not process responses and just put
|
||||
// all requests in its queue.
|
||||
// 2. Once server receive all 6 requests, call notifyObservers with the
|
||||
// topic "net:cancel-all-connections".
|
||||
// 3. We expect that all 6 active connections should be closed with the status
|
||||
// NS_ERROR_ABORT.
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var server = new HttpServer();
|
||||
server.start(-1);
|
||||
var baseURL = "http://localhost:" + server.identity.primaryPort + "/";
|
||||
var maxConnections = 0;
|
||||
var debug = false;
|
||||
var requestId = 0;
|
||||
|
||||
function log(msg) {
|
||||
if (!debug) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
dump("TEST INFO | " + msg + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
function make_channel(url) {
|
||||
var request = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
|
||||
request.QueryInterface(Ci.nsIHttpChannel);
|
||||
return request;
|
||||
}
|
||||
|
||||
function serverStopListener() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
function createHttpRequest(status) {
|
||||
let uri = baseURL;
|
||||
var chan = make_channel(uri);
|
||||
var listner = new HttpResponseListener(++requestId, status);
|
||||
chan.setRequestHeader("X-ID", requestId, false);
|
||||
chan.setRequestHeader("Cache-control", "no-store", false);
|
||||
chan.asyncOpen2(listner);
|
||||
log("Create http request id=" + requestId);
|
||||
}
|
||||
|
||||
function setupHttpRequests(status) {
|
||||
log("setupHttpRequests");
|
||||
for (var i = 0; i < maxConnections ; i++) {
|
||||
createHttpRequest(status);
|
||||
do_test_pending();
|
||||
}
|
||||
}
|
||||
|
||||
function HttpResponseListener(id, onStopRequestStatus)
|
||||
{
|
||||
this.id = id
|
||||
this.onStopRequestStatus = onStopRequestStatus;
|
||||
};
|
||||
|
||||
HttpResponseListener.prototype =
|
||||
{
|
||||
onStartRequest: function (request, ctx) {
|
||||
},
|
||||
|
||||
onDataAvailable: function (request, ctx, stream, off, cnt) {
|
||||
},
|
||||
|
||||
onStopRequest: function (request, ctx, status) {
|
||||
log("STOP id=" + this.id + " status=" + status);
|
||||
do_check_true(this.onStopRequestStatus == status);
|
||||
do_test_finished();
|
||||
}
|
||||
};
|
||||
|
||||
var responseQueue = new Array();
|
||||
function setup_http_server()
|
||||
{
|
||||
log("setup_http_server");
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
maxConnections = prefs.getIntPref("network.http.max-persistent-connections-per-server");
|
||||
|
||||
var allDummyHttpRequestReceived = false;
|
||||
// Start server; will be stopped at test cleanup time.
|
||||
server.registerPathHandler('/', function(metadata, response)
|
||||
{
|
||||
var id = metadata.getHeader("X-ID");
|
||||
log("Server recived the response id=" + id);
|
||||
|
||||
response.processAsync();
|
||||
response.setHeader("X-ID", id);
|
||||
responseQueue.push(response);
|
||||
|
||||
if (responseQueue.length == maxConnections) {
|
||||
log("received all http requets");
|
||||
Services.obs.notifyObservers(null, "net:cancel-all-connections");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
do_register_cleanup(function() {
|
||||
server.stop(serverStopListener);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
setup_http_server();
|
||||
setupHttpRequests(Components.results.NS_ERROR_ABORT);
|
||||
}
|
|
@ -409,3 +409,4 @@ skip-if = os == "android"
|
|||
[test_tls_flags_separate_connections.js]
|
||||
[test_tls_flags.js]
|
||||
[test_uri_mutator.js]
|
||||
[test_bug1411316_http1.js]
|
||||
|
|
|
@ -190,7 +190,7 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
self._installed_files = '$(MOZ_OBJ_ROOT)/<installed-files>'
|
||||
|
||||
def _get_backend_file(self, relobjdir):
|
||||
objdir = mozpath.join(self.environment.topobjdir, relobjdir)
|
||||
objdir = mozpath.normpath(mozpath.join(self.environment.topobjdir, relobjdir))
|
||||
if objdir not in self._backend_files:
|
||||
self._backend_files[objdir] = \
|
||||
BackendTupfile(objdir, self.environment,
|
||||
|
@ -331,6 +331,8 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
if obj.script and obj.method and obj.relobjdir not in skip_directories:
|
||||
backend_file.export_shell()
|
||||
cmd = self._py_action('file_generate')
|
||||
if obj.localized:
|
||||
cmd.append('--locale=en-US')
|
||||
cmd.extend([
|
||||
obj.script,
|
||||
obj.method,
|
||||
|
@ -383,9 +385,9 @@ class TupOnly(CommonBackend, PartialBackend):
|
|||
return
|
||||
|
||||
for path, files in obj.files.walk():
|
||||
backend_file = self._get_backend_file(mozpath.join(target, path))
|
||||
for f in files:
|
||||
if not isinstance(f, ObjDirPath):
|
||||
backend_file = self._get_backend_file(mozpath.join(target, path))
|
||||
if '*' in f:
|
||||
if f.startswith('/') or isinstance(f, AbsolutePath):
|
||||
basepath, wild = os.path.split(f.full_path)
|
||||
|
|
|
@ -71,7 +71,7 @@ def generate_placeholder(testcase):
|
|||
return [timings]
|
||||
|
||||
|
||||
def run_gecko_test(testcase, url, timeout, is_async):
|
||||
def run_gecko_test(testcase, url, date, timeout, is_async):
|
||||
with create_gecko_session() as driver:
|
||||
driver.set_page_load_timeout(timeout)
|
||||
try:
|
||||
|
|
|
@ -17,7 +17,7 @@ from statistics import median, StatisticsError
|
|||
from urllib.parse import urlsplit, urlunsplit, urljoin
|
||||
|
||||
|
||||
DATE = datetime.now().strftime("%Y%m%d")
|
||||
DATE = datetime.now().strftime("%Y-%m-%d")
|
||||
MACHINE = platform.machine()
|
||||
SYSTEM = platform.system()
|
||||
|
||||
|
@ -66,11 +66,11 @@ def execute_test(url, command, timeout):
|
|||
return ""
|
||||
|
||||
|
||||
def run_servo_test(testcase, url, timeout, is_async):
|
||||
def run_servo_test(testcase, url, date, timeout, is_async):
|
||||
if is_async:
|
||||
print("Servo does not support async test!")
|
||||
# Return a placeholder
|
||||
return parse_log("", testcase, url)
|
||||
return parse_log("", testcase, url, date)
|
||||
|
||||
ua_script_path = "{}/user-agent-js".format(os.getcwd())
|
||||
command = [
|
||||
|
@ -92,10 +92,10 @@ def run_servo_test(testcase, url, timeout, is_async):
|
|||
))
|
||||
except subprocess.TimeoutExpired:
|
||||
print("Test FAILED due to timeout: {}".format(testcase))
|
||||
return parse_log(log, testcase, url)
|
||||
return parse_log(log, testcase, url, date)
|
||||
|
||||
|
||||
def parse_log(log, testcase, url):
|
||||
def parse_log(log, testcase, url, date):
|
||||
blocks = []
|
||||
block = []
|
||||
copy = False
|
||||
|
@ -149,7 +149,7 @@ def parse_log(log, testcase, url):
|
|||
return {
|
||||
"system": SYSTEM,
|
||||
"machine": MACHINE,
|
||||
"date": DATE,
|
||||
"date": date,
|
||||
"testcase": testcase,
|
||||
"title": "",
|
||||
"navigationStart": 0,
|
||||
|
@ -177,15 +177,15 @@ def parse_log(log, testcase, url):
|
|||
|
||||
# Set the testcase field to contain the original testcase name,
|
||||
# rather than the url.
|
||||
def set_testcase(timing, testcase=None):
|
||||
def set_testcase(timing, testcase=None, date=None):
|
||||
timing['testcase'] = testcase
|
||||
timing['system'] = SYSTEM
|
||||
timing['machine'] = MACHINE
|
||||
timing['date'] = DATE
|
||||
timing['date'] = date
|
||||
return timing
|
||||
|
||||
valid_timing_for_case = partial(valid_timing, url=url)
|
||||
set_testcase_for_case = partial(set_testcase, testcase=testcase)
|
||||
set_testcase_for_case = partial(set_testcase, testcase=testcase, date=date)
|
||||
timings = list(map(set_testcase_for_case, filter(valid_timing_for_case, map(parse_block, blocks))))
|
||||
|
||||
if len(timings) == 0:
|
||||
|
@ -329,6 +329,10 @@ def main():
|
|||
default=300, # 5 min
|
||||
help=("kill the test if not finished in time (sec)."
|
||||
" Default: 5 min"))
|
||||
parser.add_argument("--date",
|
||||
type=str,
|
||||
default=None, # 5 min
|
||||
help=("the date to use in the CSV file."))
|
||||
parser.add_argument("--engine",
|
||||
type=str,
|
||||
default='servo',
|
||||
|
@ -340,6 +344,7 @@ def main():
|
|||
elif args.engine == 'gecko':
|
||||
import gecko_driver # Load this only when we need gecko test
|
||||
run_test = gecko_driver.run_gecko_test
|
||||
date = args.date or DATE
|
||||
try:
|
||||
# Assume the server is up and running
|
||||
testcases = load_manifest(args.tp5_manifest)
|
||||
|
@ -352,7 +357,7 @@ def main():
|
|||
url))
|
||||
# results will be a mixure of timings dict and testcase strings
|
||||
# testcase string indicates a failed test
|
||||
results += run_test(testcase, url, args.timeout, is_async)
|
||||
results += run_test(testcase, url, date, args.timeout, is_async)
|
||||
print("Finished")
|
||||
# TODO: Record and analyze other performance.timing properties
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ set -o pipefail
|
|||
# https://groups.google.com/forum/#!topic/mozilla.dev.servo/JlAZoRgcnpA
|
||||
port="8123"
|
||||
base="http://localhost:${port}"
|
||||
date="$(date +%Y-%m-%d)"
|
||||
|
||||
while (( "${#}" ))
|
||||
do
|
||||
|
@ -33,6 +34,10 @@ case "${1}" in
|
|||
base="${2}"
|
||||
shift
|
||||
;;
|
||||
--date)
|
||||
date="${2}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option ${1}."
|
||||
exit
|
||||
|
@ -56,11 +61,12 @@ trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
|
|||
# MANIFEST="page_load_test/tp5n/20160509.manifest"
|
||||
MANIFEST="page_load_test/test.manifest" # A manifest that excludes
|
||||
# timeout test cases
|
||||
PERF_KEY="perf-$(uname -s)-$(uname -m)-$(date +%s).csv"
|
||||
PERF_KEY="perf-$(uname -s)-$(uname -m)-${date}.csv"
|
||||
PERF_FILE="output/${PERF_KEY}"
|
||||
|
||||
echo "Running tests"
|
||||
python3 runner.py ${engine} --runs 4 --timeout "${timeout}" --base "${base}" \
|
||||
python3 runner.py ${engine} --runs 4 --timeout "${timeout}" \
|
||||
--base "${base}" --date "${date}" \
|
||||
"${MANIFEST}" "${PERF_FILE}"
|
||||
|
||||
if [[ "${submit:-}" ]];
|
||||
|
|
|
@ -171,9 +171,11 @@ class MachCommands(CommandBase):
|
|||
category='testing')
|
||||
@CommandArgument('--base', default=None,
|
||||
help="the base URL for testcases")
|
||||
@CommandArgument('--date', default=None,
|
||||
help="the datestamp for the data")
|
||||
@CommandArgument('--submit', '-a', default=False, action="store_true",
|
||||
help="submit the data to perfherder")
|
||||
def test_perf(self, base=None, submit=False):
|
||||
def test_perf(self, base=None, date=None, submit=False):
|
||||
self.set_software_rendering_env(True)
|
||||
|
||||
self.ensure_bootstrapped()
|
||||
|
@ -181,6 +183,8 @@ class MachCommands(CommandBase):
|
|||
cmd = ["bash", "test_perf.sh"]
|
||||
if base:
|
||||
cmd += ["--base", base]
|
||||
if date:
|
||||
cmd += ["--date", date]
|
||||
if submit:
|
||||
cmd += ["--submit"]
|
||||
return call(cmd,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
using namespace mozilla;
|
||||
|
||||
// Yikes! Casting a char to unichar can fill with ones!
|
||||
#define CHAR_TO_UNICHAR(c) ((char16_t)(const unsigned char)c)
|
||||
#define CHAR_TO_UNICHAR(c) ((char16_t)(unsigned char)c)
|
||||
|
||||
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID);
|
||||
|
|
|
@ -1015,7 +1015,7 @@ PendingLookup::GetSpecHash(nsACString& aSpec, nsACString& hexEncodedHash)
|
|||
static const char* const hex = "0123456789ABCDEF";
|
||||
hexEncodedHash.SetCapacity(2 * binaryHash.Length());
|
||||
for (size_t i = 0; i < binaryHash.Length(); ++i) {
|
||||
auto c = static_cast<const unsigned char>(binaryHash[i]);
|
||||
auto c = static_cast<unsigned char>(binaryHash[i]);
|
||||
hexEncodedHash.Append(hex[(c >> 4) & 0x0F]);
|
||||
hexEncodedHash.Append(hex[c & 0x0F]);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ struct SafebrowsingHash
|
|||
|
||||
aStr.SetCapacity(2 * len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
const char c = static_cast<const char>(buf[i]);
|
||||
const char c = static_cast<char>(buf[i]);
|
||||
aStr.Append(lut[(c >> 4) & 0x0F]);
|
||||
aStr.Append(lut[c & 15]);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ void CStringToHexString(const nsACString& aIn, nsACString& aOut)
|
|||
|
||||
aOut.SetCapacity(2 * len);
|
||||
for (size_t i = 0; i < aIn.Length(); ++i) {
|
||||
const char c = static_cast<const char>(aIn[i]);
|
||||
const char c = static_cast<char>(aIn[i]);
|
||||
aOut.Append(lut[(c >> 4) & 0x0F]);
|
||||
aOut.Append(lut[c & 15]);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_silentAudioTrack.html";
|
||||
|
||||
async function check_video_decoding_state(isSuspended) {
|
||||
async function check_video_decoding_state(args) {
|
||||
let video = content.document.getElementById("autoplay");
|
||||
if (!video) {
|
||||
ok(false, "Can't get the video element!");
|
||||
}
|
||||
|
||||
let isSuspended = args.suspend;
|
||||
let reload = args.reload;
|
||||
|
||||
if (reload) {
|
||||
// It is too late to register event handlers when playback is half
|
||||
// way done. Let's start playback from the beginning so we won't
|
||||
// miss any events.
|
||||
video.load();
|
||||
video.play();
|
||||
}
|
||||
|
||||
let state = isSuspended ? "suspended" : "resumed";
|
||||
let event = isSuspended ? "mozentervideosuspend" : "mozexitvideosuspend";
|
||||
return new Promise(resolve => {
|
||||
|
@ -46,13 +57,16 @@ function check_should_not_send_unselected_tab_hover_msg(browser) {
|
|||
});
|
||||
}
|
||||
|
||||
function get_video_decoding_suspend_promise(browser) {
|
||||
return ContentTask.spawn(browser, true /* suspend */,
|
||||
function get_video_decoding_suspend_promise(browser, reload) {
|
||||
let suspend = true;
|
||||
return ContentTask.spawn(browser, { suspend, reload },
|
||||
check_video_decoding_state);
|
||||
}
|
||||
|
||||
function get_video_decoding_resume_promise(browser) {
|
||||
return ContentTask.spawn(browser, false /* resume */,
|
||||
let suspend = false;
|
||||
let reload = false;
|
||||
return ContentTask.spawn(browser, { suspend, reload },
|
||||
check_video_decoding_state);
|
||||
}
|
||||
|
||||
|
@ -97,7 +111,7 @@ add_task(async function resume_and_suspend_background_video_decoding() {
|
|||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
info("- should suspend background video decoding -");
|
||||
await get_video_decoding_suspend_promise(browser);
|
||||
await get_video_decoding_suspend_promise(browser, true);
|
||||
await check_should_send_unselected_tab_hover_msg(browser);
|
||||
|
||||
info("- when cursor is hovering over the tab, resuming the video decoding -");
|
||||
|
|
|
@ -251,7 +251,7 @@
|
|||
</toolbarbutton>
|
||||
<textbox id="header-search" type="search" searchbutton="true"
|
||||
searchbuttonlabel="&search.buttonlabel;"
|
||||
placeholder="&search.placeholder2;"/>
|
||||
placeholder="&search.placeholder2;" maxlength="100"/>
|
||||
</hbox>
|
||||
|
||||
<deck id="headered-views-content" flex="1" selectedIndex="0">
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/intl/LocaleService.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
|
||||
#include "nsAppRunner.h"
|
||||
#include "mozilla/XREAppData.h"
|
||||
|
@ -4516,6 +4517,16 @@ XREMain::XRE_mainRun()
|
|||
}
|
||||
}
|
||||
|
||||
if (NS_IsNativeUTF8()) {
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
nsAutoCString path;
|
||||
rv = mDirProvider.GetProfileStartupDir(getter_AddRefs(profileDir));
|
||||
if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(profileDir->GetNativePath(path)) && !IsUTF8(path)) {
|
||||
PR_fprintf(PR_STDERR, "Error: The profile path is not valid UTF-8. Unable to continue.\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize user preferences before notifying startup observers so they're
|
||||
// ready in time for early consumers, such as the component loader.
|
||||
mDirProvider.InitializeUserPrefs();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
let {Constructor: CC, classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
function get_test_program(prog) {
|
||||
var progPath = do_get_cwd();
|
||||
progPath.append(prog);
|
||||
|
@ -8,6 +10,8 @@ function get_test_program(prog) {
|
|||
function set_process_running_environment() {
|
||||
var envSvc = Components.classes["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
// Importing Services here messes up appInfo for some of the tests.
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties);
|
||||
var greBinDir = dirSvc.get("GreBinD", Components.interfaces.nsIFile);
|
||||
|
@ -16,4 +20,3 @@ function set_process_running_environment() {
|
|||
envSvc.set("LD_LIBRARY_PATH", greBinDir.path);
|
||||
// XXX: handle windows
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var dataFile = do_get_file("data/bug121341.properties");
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: ios.newFileURI(dataFile, null, null),
|
||||
uri: Services.io.newFileURI(dataFile, null, null),
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
var inp = channel.open2();
|
||||
|
@ -55,7 +51,7 @@ function run_test() {
|
|||
dataFile = do_get_file("data/bug121341-2.properties");
|
||||
|
||||
var channel2 = NetUtil.newChannel({
|
||||
uri: ios.newFileURI(dataFile, null, null),
|
||||
uri: Services.io.newFileURI(dataFile, null, null),
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
inp = channel2.open2();
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
// 5 seconds.
|
||||
const kExpectedDelay1 = 5;
|
||||
// 1 second.
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
var f =
|
||||
Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
|
||||
var f = Services.dirsvc.get("CurProcD", Ci.nsIFile);
|
||||
|
||||
var terminated = false;
|
||||
for (var i = 0; i < 100; i++) {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var nameArray = [
|
||||
"ascii", // ASCII
|
||||
|
@ -12,9 +11,7 @@ var nameArray = [
|
|||
];
|
||||
|
||||
function getTempDir() {
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
return dirService.get("TmpD", Ci.nsIFile);
|
||||
return Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
}
|
||||
|
||||
function create_file(fileName) {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var addedTopic = "xpcom-category-entry-added";
|
||||
var removedTopic = "xpcom-category-entry-removed";
|
||||
|
@ -23,9 +22,8 @@ var observer = {
|
|||
if (topic == "timer-callback") {
|
||||
do_check_eq(result, expected);
|
||||
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
observerService.removeObserver(this, addedTopic);
|
||||
observerService.removeObserver(this, removedTopic);
|
||||
Services.obs.removeObserver(this, addedTopic);
|
||||
Services.obs.removeObserver(this, removedTopic);
|
||||
|
||||
do_test_finished();
|
||||
|
||||
|
@ -45,9 +43,8 @@ var observer = {
|
|||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
observerService.addObserver(observer, addedTopic);
|
||||
observerService.addObserver(observer, removedTopic);
|
||||
Services.obs.addObserver(observer, addedTopic);
|
||||
Services.obs.addObserver(observer, removedTopic);
|
||||
|
||||
var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
|
||||
categoryManager.addCategoryEntry(testCategory, testEntry, testValue, false, true);
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
/* global __LOCATION__ */
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/* global registerAppManifest */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
function info(s) {
|
||||
dump("TEST-INFO | test_bug656331.js | " + s + "\n");
|
||||
}
|
||||
|
@ -22,9 +20,7 @@ const kConsoleListener = {
|
|||
};
|
||||
|
||||
function run_test() {
|
||||
let cs = Components.classes["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService);
|
||||
cs.registerListener(kConsoleListener);
|
||||
Services.console.registerListener(kConsoleListener);
|
||||
|
||||
let manifest = do_get_file("components/bug656331.manifest");
|
||||
registerAppManifest(manifest);
|
||||
|
@ -32,10 +28,9 @@ function run_test() {
|
|||
do_check_false("{f18fb09b-28b4-4435-bc5b-8027f18df743}" in Components.classesByID);
|
||||
|
||||
do_test_pending();
|
||||
Components.classes["@mozilla.org/thread-manager;1"].
|
||||
getService(Ci.nsIThreadManager).dispatchToMainThread(function() {
|
||||
cs.unregisterListener(kConsoleListener);
|
||||
do_check_true(gFound);
|
||||
do_test_finished();
|
||||
});
|
||||
Services.tm.dispatchToMainThread(function() {
|
||||
Services.console.unregisterListener(kConsoleListener);
|
||||
do_check_true(gFound);
|
||||
do_test_finished();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const manifest = do_get_file("bug725015.manifest");
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// expected byte sizes within SpiderMonkey's jit-tests, we just want to make
|
||||
// sure that Gecko is providing SpiderMonkey with the callback it needs.
|
||||
|
||||
var Cu = Components.utils;
|
||||
const { byteSize } = Cu.getJSTestingFunctions();
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -3,17 +3,14 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
// Generate a leaf name that is 255 characters long.
|
||||
var longLeafName = new Array(256).join("T");
|
||||
|
||||
// Generate the path for a file located in a directory with a long name.
|
||||
var tempFile = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
|
||||
var tempFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tempFile.append(longLeafName);
|
||||
tempFile.append("test.txt");
|
||||
|
||||
|
|
|
@ -4,20 +4,17 @@
|
|||
* 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/. */
|
||||
|
||||
var Cr = Components.results;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
var CC = Components.Constructor;
|
||||
var LocalFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
test_normalized_vs_non_normalized();
|
||||
}
|
||||
|
||||
function test_normalized_vs_non_normalized() {
|
||||
// get a directory that exists on all platforms
|
||||
var dirProvider = Components.classes["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var tmp1 = dirProvider.get("TmpD", Ci.nsIFile);
|
||||
var tmp1 = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
var exists = tmp1.exists();
|
||||
do_check_true(exists);
|
||||
if (!exists)
|
||||
|
|
|
@ -3,14 +3,11 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
// Create the base directory.
|
||||
let base = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties)
|
||||
.get("TmpD", Ci.nsIFile);
|
||||
let base = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
base.append("renameTesting");
|
||||
if (base.exists()) {
|
||||
base.remove(true);
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
const NS_OS_TEMP_DIR = "TmpD";
|
||||
|
||||
const CWD = do_get_cwd();
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var hiddenUnixFile;
|
||||
function createUNIXHiddenFile() {
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var tmpDir = dirSvc.get(NS_OS_TEMP_DIR, Ci.nsIFile);
|
||||
var tmpDir = Services.dirsvc.get(NS_OS_TEMP_DIR, Ci.nsIFile);
|
||||
hiddenUnixFile = tmpDir.clone();
|
||||
hiddenUnixFile.append(".foo");
|
||||
// we don't care if this already exists because we don't care
|
||||
|
@ -25,4 +24,3 @@ function run_test() {
|
|||
do_check_true(createUNIXHiddenFile());
|
||||
do_check_true(hiddenUnixFile.isHidden());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const CWD = do_get_cwd();
|
||||
function checkOS(os) {
|
||||
|
@ -13,8 +12,7 @@ const isWin = checkOS("Win");
|
|||
function run_test() {
|
||||
var envVar = isWin ? "USERPROFILE" : "HOME";
|
||||
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var homeDir = dirSvc.get("Home", Ci.nsIFile);
|
||||
var homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
|
||||
|
||||
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
var expected = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cr = Components.results;
|
||||
|
||||
var testnum = 0;
|
||||
var factory;
|
||||
|
||||
|
@ -129,6 +125,8 @@ var testdata = [
|
|||
testdata.push( { filename: "data/iniparser16-utf8BOM.ini",
|
||||
reference: testdata[15].reference } );
|
||||
|
||||
// Intentional test for appInfo that can't be preloaded.
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
let os = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime).OS;
|
||||
if ("WINNT" === os) {
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
const util = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cr = Components.results;
|
||||
var CC = Components.Constructor;
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
const MAX_TIME_DIFFERENCE = 2500;
|
||||
const MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const kCID = Components.ID("{1f9f7181-e6c5-4f4c-8f71-08005cec8468}");
|
||||
|
@ -80,4 +75,3 @@ function run_test() {
|
|||
}
|
||||
strictEqual(xpcomObject.method3, undefined);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var Cc = Components.classes;
|
||||
var CC = Components.Constructor;
|
||||
|
||||
var MutableArray = CC("@mozilla.org/array;1", "nsIMutableArray");
|
||||
var SupportsString = CC("@mozilla.org/supports-string;1", "nsISupportsString");
|
||||
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var CC = Components.Constructor;
|
||||
|
||||
var Pipe = CC("@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var CC = Components.Constructor;
|
||||
var Cc = Components.classes;
|
||||
|
||||
// The string we use as data.
|
||||
const data = "0123456789";
|
||||
// Number of streams in the multiplex stream.
|
||||
|
@ -160,4 +155,3 @@ function run_test() {
|
|||
test_multiplex_streams();
|
||||
test_multiplex_bug797871();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
|
||||
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "unusedVariable" }] */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
function run_test() {
|
||||
test1();
|
||||
test2();
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
var CC = Components.Constructor;
|
||||
|
||||
var Pipe = CC("@mozilla.org/pipe;1",
|
||||
"nsIPipe",
|
||||
"init");
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
function run_test() {
|
||||
var s = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Versions to test listed in ascending order, none can be equal
|
||||
var comparisons = [
|
||||
"0.9",
|
||||
|
@ -29,12 +31,9 @@ var equality = [
|
|||
];
|
||||
|
||||
function run_test() {
|
||||
var vc = Components.classes["@mozilla.org/xpcom/version-comparator;1"]
|
||||
.getService(Components.interfaces.nsIVersionComparator);
|
||||
|
||||
for (var i = 0; i < comparisons.length; i++) {
|
||||
for (var j = 0; j < comparisons.length; j++) {
|
||||
var result = vc.compare(comparisons[i], comparisons[j]);
|
||||
var result = Services.vc.compare(comparisons[i], comparisons[j]);
|
||||
if (i == j) {
|
||||
if (result != 0)
|
||||
do_throw(comparisons[i] + " should be the same as itself");
|
||||
|
@ -49,7 +48,7 @@ function run_test() {
|
|||
|
||||
for (i = 0; i < equality.length; i++) {
|
||||
for (j = 0; j < equality.length; j++) {
|
||||
if (vc.compare(equality[i], equality[j]) != 0)
|
||||
if (Services.vc.compare(equality[i], equality[j]) != 0)
|
||||
do_throw(equality[i] + " should equal " + equality[j]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let executableFile = Services.dirsvc.get("CurProcD", Ci.nsIFile);
|
||||
|
|
|
@ -5,12 +5,6 @@
|
|||
* 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/. */
|
||||
|
||||
const Cr = Components.results;
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const nsIWindowsRegKey = Ci.nsIWindowsRegKey;
|
||||
let regKeyComponent = Cc["@mozilla.org/windows-registry-key;1"];
|
||||
|
||||
|
|
|
@ -5,12 +5,6 @@
|
|||
* 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/. */
|
||||
|
||||
var Cr = Components.results;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cu = Components.utils;
|
||||
var CC = Components.Constructor;
|
||||
|
||||
const LocalFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
|
Загрузка…
Ссылка в новой задаче