mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
fffeb135bb
- Bug 1040668 part 2 - Parse and compute text emphasis properties. r=dbaron (0fb79d4709) - Bug 1040668 part 3 - Add helper function gfxTextRun::GetAdvanceForGlyph. r=jfkthame (f1cf02f5ff) - Bug 1216427 - Tests for backspacing over a character with variation selector, and over Regional Indicator flag symbols. r=emk (18957bfe77) - Bug 1216427 - part 1 - Ensure a character+VS sequence or a ligated Regional-Indicator flag symbol is deleted as a single unit when backspacing. r=emk (2776ff8f4a) - Bug 1216427 - part 2 - Ensure mouse selection does not split up a Regional Indicator flag symbol. r=emk (58eb82e6a1) - Bug 1040668 part 4 - Add helper function for ensuring a glyph is a complex glyph. r=jfkthame (ba17f7d0c4) - Bug 1040668 part 5 - Avoid unnecessary allocation inside EnsureComplexGlyph helper function. r=jfkthame (4968a7c68e) - Bug 1040668 part 6 - Add some specifier on gfxTextRun and gfxShapedWord so that compilers are able to reason out certain optimizations. r=jfkthame (69ca3eb959) - Bug 1040668 part 7 - Add NO_EMPHASIS_MARK flag in CompressedGlyph. r=jfkthame (34e9d8a6a6) - Bug 1227001 part 1 - Remove SetupBreakSinksFlags from BuildTextRunsScanner. r=jfkthame (520b1ba111) - Bug 1227001 part 2 - Remove no longer used mExistingTextRun from BreaSink. r=jfkthame (201782a78c) - Bug 1227001 part 3 - Remove no longer used mChangedBreaks from BreakSink. r=jfkthame (e754e2b13f) - Bug 1040668 part 8 - Setup text emphasis for text run. r=jfkthame (376377180e) - Bug 1040668 part 9 - Compute overflow from text-shadow after text decorations. r=dbaron (05c9bd08c2) - Bug 1040668 part 10 - Implement emphasis mark rendering. r=jfkthame (4d270afca8) - Bug 1040668 part 11 - Move line leadings adjusting code into a separate function in nsLineLayout. r=dholbert (fd4dd20ca5) - Bug 1040668 part 12 - Add line leadings for emphasis marks if necessary. r=dholbert (138add5ff7) - Bug 1040668 part 13 - Move first part of nsStyleFont::GetLanguage to nsPresContext::GetContentLanguage. r=dbaron (1e872d2a58) - Bug 1040668 part 14 - Add helper function nsStyleUtil::MatchesLanguagePrefix for doing simple language matching. r=dbaron (9322a02369) - Bug 1040668 part 15 - Make the default value of text-emphasis-position aware of the language. r=dbaron (6587c628da) - Bug 1040668 part 16 - Add reftests for text-emphasis. r=dbaron (9940d65182) - Bug 1040668 followup - Use monospace for text-emphasis reftests. rs=dbaron on a CLOSED TREE (fb7598c3ea) - Bug 1040668 followup 2 - Disable failing reftests of text-emphasis on Windows XP. (7c3f24ac22) - Bug 1040668 followup 3 - Wrap lang attribute mapping code in NS_STYLE_INHERIT_BIT test. r=dbaron (640e3b7b8f) - Bug 1219145 - nsRefreshDriver::IsJankCritical(). r=hiro To refine its alerts, Performance Stats API needs to be able to know whether a long-running operation is actually causing user-visible jank in the current process. This patch introduces a trivial API that lets clients ask the refresh driver whether any kind of animation is ongoing. (7c0868d7c4) - more missing XP theme stuff (637af0c6a0) - Bug 1210261. Tick root refresh driver last. r=mattwoodrow (dae1a325fa) - Bug 1221674 Part 2: Correct for negative content delay values. r=avih (9b9811c41c) - Bug 1211334 - Check if presshell is still available after dispatching transition events; r=mats (8a044a462c) - Bug 1211599 - Only allow whitelisted histograms to have > 100 buckets. r=nfroyd (d467e84130) - Bug 1219733 - Allow a 'bug_numbers' field in Histograms.json entries. r=vladan (8e63a713ec) - Bug 1222044 - Only allow lists of alert_emails r=vladan (1d5fcb009d) - Bug 1168263 - Add a flags parameter to GetResultingTransformMatrix instead of using bools. r=roc (ec5224f9af) - Bug 1168263 - Remove TransformRectOut since it's unused. r=roc (d20a79ae0e) - Bug 1215406 - Part 1: Remove NS_STYLE_ANIMATION_DIRECTION_XXX and NS_STYLE_ANIMATION_FILL_MODE_XXX. r=heycam (4bd7f8116b) - Bug 1215406 - Part 2: Change the types of direction and fillmode in StyleAnimation. r=heycam (e06323c81b) - Bug 1215406 - Part 3: Change the types of direction and fillmode in AnimationTiming. r=heycam (e5454d3ea5) - Bug 1215406 - Part 4: Add KeyframeEffectOptions. r=smaug Add KeyframeEffectOptions in KeyframeEffect.webidl (0ce3372fd1) - Bug 1215406 - Part 5: Implement KeyframeEffectOptions in KeyframeEffectReadOnly constructor. r=birtles (a472e9ac5f) - tch 2 - Use an enum class for NS_STYLE_BOX_SIZING_*. r=heycam (4897b7b8ff) - Bug 1218195, mark MutationObserver as observing in all the nested DOM mutations, r=bz (48a4aa8a91) - Bug 1172870 - Part 3 - Fix openWindow mochitest to work on e10s (574cc6fa4d) - Bug 1223265 - Fix -Wunreachable-code and -Wimplicit-fallthrough warnings in dom/bindings and dom/ipc. r=khuey (9eab632140) - Bug 1189195 - Fix PContentPermissionRequest shutdown () r=fabrice (6bc1a681f5) - Bug 1210508 - Handle null OriginAttributes from JS-implemented nsILoadContext. r=me (2f71edb9d7) - Bug 1224596 part 1. Add a version of WorkerMainThreadRunnable::Dispatch that takes an ErrorResult to report failure to dispatch on. r=khuey (e60a0fb115) - Bug 1224596 part 2. Switch Navigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d9298a4763) - Bug 1224596 part 3. Make some WebSocket(Impl) methods whose return value is totally ignored void. r=khuey (1d04b52d44) - Bug 1224596 part 4. Switch WebSocket to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (aa06e6417b) - Bug 1224596 part 5. Switch nsPerformance to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (0303b7de09) - Bug 1224596 part 6. Switch BroadcastChannel to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (feacc21f63) - Bug 1224636. Fix some code in ImageBitmap that rejects a promise with an ErrorResult, then keeps trying to use that ErrorResult. r=kaku (89b769fe07) - Bug 1224596 part 7. Switch ImageBitmap to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (e21b0a4a0a) - Bug 1183954, Don't leak nsStructuredCloneContainer (use of 'auto' is error prone), r=leak (1a9b30f2ca) - Bug 1114554 - Patch 9 - Fixed crash in b2g-desktop tests. r=nsm (6b12c6d121) - Bug 1189090 - Rework the nsISupports implementation in the ScopeCheckingGetCallback and its subclasses; r=nsm (6bea544597) - Bug 1187018 - Ensure feature is nulled out if it does not get added. r=khuey (9d7439498a) - Bug 1224596 part 8. Switch Notification to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (03f0f6877f) - Bug 1196079 - Always try to release Notification via normal WorkerRunnable first. r=wchen (c093253d6f) - Bug 1203324 - disable notifications on serviceworkers. r=ehsan,wchen (aa39310dc1) - Bug 1199901 - GetOrigin() fails cleanly instead of asserting principal. r=wchen (148c634a4f) - Bug 1199901 - Clear mObserver when WorkerNotificationObserver is destroyed. r=wchen (6d5cd99183) - Bug 1199901 - Bustage fix due to rebase. a=bustage (344bd62af5) - Bug 1225470 Report a message to the console when a service worker waitUntil() is rejected. r=baku (610da2eec6) - Bug 1217909 P1 Report service worker exceptions to controlled documents. r=catalinb (f8bd4677d5) - Bug 1216566 - Fix a bug in nsIServiceWorkerManager.getAllRegistrations;r=catalinb (ed3e14ab43) - Bug 1219205 - ServiceWorkerInfo should be an XPCOM object;r=catalinb (677a6f1ffd) - Bug 1217909 P2 Track registering documents as weak reference so SWM can report errors to them. r=catalinb (4233dc3edc) - Bug 1217909 P3 Refactor service worker register()/update() to reject only with SecurityErr or TypeErr. r=catalinb (c6891a7fae) - Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its scriptSpec property changes;r=amarchesini (5772bb5914) - Bug 1207727 - Add WPT tests for service worker update algorithm. r=bkelly (a4812571a1) - Bug 1217367 - Service workers update algorithm optimization. r=bkelly (e377debad1) - Bug 1226479. Change ErrorResult::ThrowTypeError/ThrowRangeError to take string references, not pointers. r=mccr8 (0804899666) - Bug 1224659 - Worker DataStore code should not use ErrorResult cross threads, r=bz (aef03b0fdd) - Bug 1224596 part 9. Switch DataStore to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (1eb1c427f2) - Bug 1224596 part 10. Switch DataStoreCursor to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (114af8021b) - Bug 1224596 part 11. Switch WorkerNavigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (b2347a0c49) - Bug 1224596 part 12. Switch ServiceWorkerRegistration to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d1ff076836) - Bug 1224596 part 13. Switch gfxUtils to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (a523997588) - Bug 1224007 part 1. Rename ThrowMethodFailed to MaybeSetPendingException and make it an ErrorResult instance method. r=peterv (bdf0891f54) - Bug 1224007 part 2. Make the various ErrorResult::Report* methods private, so consumers all go through MaybeSetPendingException and rename them to more clearly indicate what they're actually doing. r=peterv (48f483c153) - Bug 1203151 - Allow disabling of screen wakelocks for video elements. r=baku (6bd9ff6916) - Bug 1224007 part 4. Fix some cases in which ErrorResult instances are destroyed without doing anything useful with exceptions on them. r=peterv (e328785e5d) - Bug 1224007 part 5. Get rid of ErrorResult::StealJSException. r=peterv (db19cfb31e) - Bug 1224007 part 3. Push down WouldReportJSException into MaybeSetPendingException, since anyone calling the latter will propagate the JS exception as needed. r=peterv (1d3b7b415d) - Bug 1224007 part 6. Change MaybeSetPendingException to set the ErrorResult state to "not failed", just like SuppressException and StealNSResult already do, and assert in the destructor that the ErrorResult is not Failed(). (a028838e8d) - Bug 1213815 - Update URLSearchParams and URLUtils in webidl files, r=bz (28fb8f7de5) - Bug 1213815 - dom/webidl/HTMLHyperlinkElementUtils and URL don't need to throw exceptions as we did before, r=bz (b13dc3bcb9) - Bug 1224596 part 14. Switch URL to using the new WorkerMainThreadRunnable::Dispatch signature. r=baku (232677e50e) - fix updating the backport (9e958da5ca) - Bug 1224596 part 16. Switch Fetch to using the new WorkerMainThreadRunnable::Dispatch signature. r=bkelly (939e338f22) - Bug 1224596 part 17. Remove the old WorkerMainThreadRunnable::Dispatch signature. r=khuey (5a70429ec8) - Bug 1143575. Don't report negative frame delays. r=cpearce (7d8bc0f753) - Bug 1187371 - Get rid of dom.broadcastChannel.enabled pref, r=bz (9335b7ae90) - Bug 1196514 - remove dom.messagechannel.enabled pref, r=smaug (31e06119b4) - Bug 1166356 - Properly detect double-caching in nsXULPrototypeCache; r=ehsan (29df9ffb2d) - Bug 1168916 - Get rid of redundant pref callback in nsXULPrototypeCache; r=janv (9f37fff405) - Bug 1139099: Dispatch DOMDocElementInserted to match the document-element-inserted observer notification. r=mrbkap (6565e4b924) - Bug 1187068 - Tell the cycle collector about nsContentSink::mCSSLoader. r=heycam (4ae23eb26c) - Bug 1172189 - Fix overflow in nsXULContentSink.cpp. r=ehsan (cc6330f5de) - Bug 1126010 - XULContentSinkImpl::mParser should be an nsRefPtr. r=smaug (d6bb567692) - Bug 1147946, part 7 - Remove trailing whitespace from nsXULContentSink.cpp. r=baku (cdcadbfeeb) - Bug 1147946, part 1 - Tuck elses in nsXULContentSink.cpp. r=baku (26fd806676) - Bug 1147946, part 2 - Move body of check inside prior if in XULContentSinkImpl::OpenScript(). r=baku (b509455bdb) - Bug 1147946, part 3 - Eliminate unused case for non-JS scripting languages in XULContentSinkImpl::OpenScript(). r=baku (4136933cc2) - Bug 1147946, part 4 - Use an early return in XULContentSinkImpl::OpenScript(). r=baku (c3e293474b) - Bug 1147946, part 5 - Don't use the generic nsIProgrammingLanguage enum in XULContentSinkImpl::OpenScript(). r=baku (89a124e23f) - Bug 1147946, part 6 - Remove some useless null checks on infallible new in XULContentSinkImpl. r=baku (1ac57e8c3a) - Bug 1221351 P1 ServiceWorkerContainer and ServiceWorkerRegistration should not crash for null window owner. r=catalinb (1a72748632) - Bug 1212867 - Node.isEqualNode() should ignore internal subsets; r=bzBug (99b166ffee) - Bug 492933 - getElementsByTagName should match on localName not tagName, r=smaug (d0c6ceabf1) - Bug 912470 part 1 - Implement Encoding Standard-compliant big5 decoder. r=emk. (c680b0ae9b) - Bug 1170932: Test handling of unmapped characters in unicode-to-codepage encoders (ca36bcbd35) - fix style (95a90bfe3a) - Bug 1170794 - patch 2 - Improve the length check of the input in nsUnicode*::GetMaxLength, r=dveditz (aa864d656f) - Bug 1170794 followup: Add 'override' annotations to Convert() & Reset() methods in intl/uconv. rs=ehsan (bb3e6e492e) - Bug 1176462 - Remove nsTableDecoderSupport. r=smontagu (f4a86c44b3) - Bug 1169248 - Fix GBK/GB18030 encoders. r=smontagu (ed946e1ee1) - Bug 1155539 - Remove obsolete encoding decoder telemetry probes. r=emk. (44e15bfb40) - Bug 912470 part 2 - Implement Encoding Standard-compliant big5 encoder. r=emk. (5cca2dc4a0) - Bug 912470 addendum - Pass override static analysis. r=emk. (c163bffeb4) - Bug 1170932: Improve error handling for the gbk encoder, r=emk (30e95b34a5) - Bug 1202366 - Implement the encoder error mode "HTML" for nsFormSubmission without nsISaveAsCharset. r=NOT_emk. (ebc8b542dd) - update manifest (6cc19172cc) - Bug 1197309 - remove PR_snprintf calls in intl/; r=froydnj (79fcdfa845) - Bug 1214619 - Remove nsISaveAsCharset as much as possible without breaking extensions in popular use. r=emk. (89b71b3d87) - Bug 1214857. Store the document-is-HTML state directly in nsContentList instead of refetching from the node being matched. r=smaug (4c4fbf469e) - Bug 1221351 P2 Add a web-platform-test to check for crash when calling .register() on closed window. r=catalinb (eeb30c1bba) - Bug 1221351 P3 Fix test name in register-closed-window.https.html. a=testonly (5bfa840044) - Bug 1224436: Remove enumerator usage in ServiceWorkerManager.cpp. r=njn (b8cb094d3c) - Bug 1223716. Make HTMLCollection check for the element being HTML before checking for its name inside its named getter. r=bkelly (977e0bff5a) - Bug 1180737 - Add update-test.py and update test to latest version. r=bkelly. (59faa36d5c) - Bug 1217909 P4 Extend wpt tests to verify update() promise values for different script failures. r=catalinb (a2f7352a3a) - Bug 1217909 P5 Add wpt test case for fetch event handlers that throw. r=catalinb (56a77f611c) - Bug 1217909 P6 Fix wpt registration.https.html to expect TypeError for script evaluation errors. r=catalinb (3de8a45688) - Bug 1217909 P7 Fix mochitest to expect TypeError when serviceWorker.register() rejects. r=catalinb (6e8841c41e) - Bug 1217909 P8 Track navigation interceptions per scope in ServiceWorkerManager. r=catalinb (6705ba8337) - Bug 1217909 P9 Report exceptions to windows performing an intercepted navigation. r=catalinb (52f9fece14) - Bug 1217909 P10 Remove stale nsTArray when the last registering document for a scope is removed. r=catalinb (b739bcc3b2) - Bug 1217909 P11 Only report errors to documents that are active and not in the bfcache. r=catalinb (5ffd633af2) - Bug 1223378 Tighten service worker register() principal checks. r=baku (478785f2cc) - Bug 1189685 - Part 1: Ensure that the state of all ServiceWorker instances is up to date when dispatching statechange events; r=bkelly (2bd9b78c58) - Bug 1189685 - Part 2: Make synced-state.https.html pass; r=bkelly (029f942d8c) - Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its worker properties change;r=amarchesini (8243a3debc) - Bug 1186856 ServiceWorker .register() should always stop current registration from uninstalling. r=jdm (ec7d6e0e7c) - Bug 1224941 Don't crash during ServiceWorker life cycle event dispatch if window is gone. r=baku (a3f45af3e4) - Bug 1180754 - Get serviceworkerobject-scripturl test passing. r=bkelly (c7979bef47) - Bug 1201498 - Service worker update should compare scriptURL to worker URL without fragment, r=bkelly (914f630528) - Bug 594505 - Remove obsolete comment since this bug has now been fixed. r=me DONTBUILD (44f3a15b91) - Bug 1221840. Support repeating images in 1 axis. r=seth (449ea3e97e) - const-var (5433688051) - Bug 1574573 - Disambiguate a use of Handle in XPCShellEnvironment.cpp r=Ehsan (15b44177d1) - clean up warnings (6e64313d0c)
1638 lines
48 KiB
C++
1638 lines
48 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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/. */
|
|
|
|
/*
|
|
* Base class for the XML and HTML content sinks, which construct a
|
|
* DOM based on information from the parser.
|
|
*/
|
|
|
|
#include "nsContentSink.h"
|
|
#include "nsScriptLoader.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "mozilla/css/Loader.h"
|
|
#include "nsStyleLinkElement.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsILoadContext.h"
|
|
#include "nsCPrefetchService.h"
|
|
#include "nsIURI.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsIMIMEHeaderParam.h"
|
|
#include "nsIProtocolHandler.h"
|
|
#include "nsIHttpChannel.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsViewManager.h"
|
|
#include "nsIAtom.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsIOfflineCacheUpdate.h"
|
|
#include "nsIApplicationCache.h"
|
|
#include "nsIApplicationCacheContainer.h"
|
|
#include "nsIApplicationCacheChannel.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
#include "nsICookieService.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsNodeInfoManager.h"
|
|
#include "nsIAppShell.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "mozAutoDocUpdate.h"
|
|
#include "nsIWebNavigation.h"
|
|
#include "nsGenericHTMLElement.h"
|
|
#include "nsHTMLDNSPrefetch.h"
|
|
#include "nsIObserverService.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "nsParserConstants.h"
|
|
#include "nsSandboxFlags.h"
|
|
|
|
static PRLogModuleInfo*
|
|
GetSriLog()
|
|
{
|
|
static PRLogModuleInfo *gSriPRLog;
|
|
if (!gSriPRLog) {
|
|
gSriPRLog = PR_NewLogModule("SRI");
|
|
}
|
|
return gSriPRLog;
|
|
}
|
|
|
|
using namespace mozilla;
|
|
|
|
PRLogModuleInfo* gContentSinkLogModuleInfo;
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
|
|
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
|
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
|
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
|
|
if (tmp->mDocument) {
|
|
tmp->mDocument->RemoveObserver(tmp);
|
|
}
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptLoader)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
nsContentSink::nsContentSink()
|
|
{
|
|
// We have a zeroing operator new
|
|
NS_ASSERTION(!mLayoutStarted, "What?");
|
|
NS_ASSERTION(!mDynamicLowerValue, "What?");
|
|
NS_ASSERTION(!mParsing, "What?");
|
|
NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
|
|
NS_ASSERTION(mDeflectedCount == 0, "What?");
|
|
NS_ASSERTION(!mDroppedTimer, "What?");
|
|
NS_ASSERTION(mInMonolithicContainer == 0, "What?");
|
|
NS_ASSERTION(mInNotification == 0, "What?");
|
|
NS_ASSERTION(!mDeferredLayoutStart, "What?");
|
|
|
|
#ifdef DEBUG
|
|
if (!gContentSinkLogModuleInfo) {
|
|
gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
nsContentSink::~nsContentSink()
|
|
{
|
|
if (mDocument) {
|
|
// Remove ourselves just to be safe, though we really should have
|
|
// been removed in DidBuildModel if everything worked right.
|
|
mDocument->RemoveObserver(this);
|
|
}
|
|
}
|
|
|
|
bool nsContentSink::sNotifyOnTimer;
|
|
int32_t nsContentSink::sBackoffCount;
|
|
int32_t nsContentSink::sNotificationInterval;
|
|
int32_t nsContentSink::sInteractiveDeflectCount;
|
|
int32_t nsContentSink::sPerfDeflectCount;
|
|
int32_t nsContentSink::sPendingEventMode;
|
|
int32_t nsContentSink::sEventProbeRate;
|
|
int32_t nsContentSink::sInteractiveParseTime;
|
|
int32_t nsContentSink::sPerfParseTime;
|
|
int32_t nsContentSink::sInteractiveTime;
|
|
int32_t nsContentSink::sInitialPerfTime;
|
|
int32_t nsContentSink::sEnablePerfMode;
|
|
|
|
void
|
|
nsContentSink::InitializeStatics()
|
|
{
|
|
Preferences::AddBoolVarCache(&sNotifyOnTimer,
|
|
"content.notify.ontimer", true);
|
|
// -1 means never.
|
|
Preferences::AddIntVarCache(&sBackoffCount,
|
|
"content.notify.backoffcount", -1);
|
|
// The gNotificationInterval has a dramatic effect on how long it
|
|
// takes to initially display content for slow connections.
|
|
// The current value provides good
|
|
// incremental display of content without causing an increase
|
|
// in page load time. If this value is set below 1/10 of second
|
|
// it starts to impact page load performance.
|
|
// see bugzilla bug 72138 for more info.
|
|
Preferences::AddIntVarCache(&sNotificationInterval,
|
|
"content.notify.interval", 120000);
|
|
Preferences::AddIntVarCache(&sInteractiveDeflectCount,
|
|
"content.sink.interactive_deflect_count", 0);
|
|
Preferences::AddIntVarCache(&sPerfDeflectCount,
|
|
"content.sink.perf_deflect_count", 200);
|
|
Preferences::AddIntVarCache(&sPendingEventMode,
|
|
"content.sink.pending_event_mode", 1);
|
|
Preferences::AddIntVarCache(&sEventProbeRate,
|
|
"content.sink.event_probe_rate", 1);
|
|
Preferences::AddIntVarCache(&sInteractiveParseTime,
|
|
"content.sink.interactive_parse_time", 3000);
|
|
Preferences::AddIntVarCache(&sPerfParseTime,
|
|
"content.sink.perf_parse_time", 360000);
|
|
Preferences::AddIntVarCache(&sInteractiveTime,
|
|
"content.sink.interactive_time", 750000);
|
|
Preferences::AddIntVarCache(&sInitialPerfTime,
|
|
"content.sink.initial_perf_time", 2000000);
|
|
Preferences::AddIntVarCache(&sEnablePerfMode,
|
|
"content.sink.enable_perf_mode", 0);
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::Init(nsIDocument* aDoc,
|
|
nsIURI* aURI,
|
|
nsISupports* aContainer,
|
|
nsIChannel* aChannel)
|
|
{
|
|
NS_PRECONDITION(aDoc, "null ptr");
|
|
NS_PRECONDITION(aURI, "null ptr");
|
|
|
|
if (!aDoc || !aURI) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
mDocument = aDoc;
|
|
|
|
mDocumentURI = aURI;
|
|
mDocShell = do_QueryInterface(aContainer);
|
|
mScriptLoader = mDocument->ScriptLoader();
|
|
|
|
if (!mRunsToCompletion) {
|
|
if (mDocShell) {
|
|
uint32_t loadType = 0;
|
|
mDocShell->GetLoadType(&loadType);
|
|
mDocument->SetChangeScrollPosWhenScrollingToRef(
|
|
(loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
|
|
}
|
|
|
|
ProcessHTTPHeaders(aChannel);
|
|
}
|
|
|
|
mCSSLoader = aDoc->CSSLoader();
|
|
|
|
mNodeInfoManager = aDoc->NodeInfoManager();
|
|
|
|
mBackoffCount = sBackoffCount;
|
|
|
|
if (sEnablePerfMode != 0) {
|
|
mDynamicLowerValue = sEnablePerfMode == 1;
|
|
FavorPerformanceHint(!mDynamicLowerValue, 0);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsContentSink::StyleSheetLoaded(CSSStyleSheet* aSheet,
|
|
bool aWasAlternate,
|
|
nsresult aStatus)
|
|
{
|
|
NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
|
|
if (!aWasAlternate) {
|
|
NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
|
|
--mPendingSheetCount;
|
|
|
|
if (mPendingSheetCount == 0 &&
|
|
(mDeferredLayoutStart || mDeferredFlushTags)) {
|
|
if (mDeferredFlushTags) {
|
|
FlushTags();
|
|
}
|
|
if (mDeferredLayoutStart) {
|
|
// We might not have really started layout, since this sheet was still
|
|
// loading. Do it now. Probably doesn't matter whether we do this
|
|
// before or after we unblock scripts, but before feels saner. Note
|
|
// that if mDeferredLayoutStart is true, that means any subclass
|
|
// StartLayout() stuff that needs to happen has already happened, so we
|
|
// don't need to worry about it.
|
|
StartLayout(false);
|
|
}
|
|
|
|
// Go ahead and try to scroll to our ref if we have one
|
|
ScrollToRef();
|
|
}
|
|
|
|
mScriptLoader->RemoveExecuteBlocker();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
|
|
{
|
|
nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
|
|
|
|
if (!httpchannel) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Note that the only header we care about is the "link" header, since we
|
|
// have all the infrastructure for kicking off stylesheet loads.
|
|
|
|
nsAutoCString linkHeader;
|
|
|
|
nsresult rv = httpchannel->GetResponseHeader(NS_LITERAL_CSTRING("link"),
|
|
linkHeader);
|
|
if (NS_SUCCEEDED(rv) && !linkHeader.IsEmpty()) {
|
|
mDocument->SetHeaderData(nsGkAtoms::link,
|
|
NS_ConvertASCIItoUTF16(linkHeader));
|
|
|
|
NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
|
|
"Already dispatched an event?");
|
|
|
|
mProcessLinkHeaderEvent =
|
|
NS_NewNonOwningRunnableMethod(this,
|
|
&nsContentSink::DoProcessLinkHeader);
|
|
rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get());
|
|
if (NS_FAILED(rv)) {
|
|
mProcessLinkHeaderEvent.Forget();
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
|
|
nsIContent* aContent)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
// necko doesn't process headers coming in from the parser
|
|
|
|
mDocument->SetHeaderData(aHeader, aValue);
|
|
|
|
if (aHeader == nsGkAtoms::setcookie) {
|
|
// Don't allow setting cookies in cookie-averse documents.
|
|
if (mDocument->IsCookieAverse()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Note: Necko already handles cookies set via the channel. We can't just
|
|
// call SetCookie on the channel because we want to do some security checks
|
|
// here.
|
|
nsCOMPtr<nsICookieService> cookieServ =
|
|
do_GetService(NS_COOKIESERVICE_CONTRACTID, &rv);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
// Get a URI from the document principal
|
|
|
|
// We use the original codebase in case the codebase was changed
|
|
// by SetDomain
|
|
|
|
// Note that a non-codebase principal (eg the system principal) will return
|
|
// a null URI.
|
|
nsCOMPtr<nsIURI> codebaseURI;
|
|
rv = mDocument->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
|
|
NS_ENSURE_TRUE(codebaseURI, rv);
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
if (mParser) {
|
|
mParser->GetChannel(getter_AddRefs(channel));
|
|
}
|
|
|
|
rv = cookieServ->SetCookieString(codebaseURI,
|
|
nullptr,
|
|
NS_ConvertUTF16toUTF8(aValue).get(),
|
|
channel);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
else if (aHeader == nsGkAtoms::msthemecompatible) {
|
|
// Disable theming for the presshell if the value is no.
|
|
// XXXbz don't we want to support this as an HTTP header too?
|
|
nsAutoString value(aValue);
|
|
if (value.LowerCaseEqualsLiteral("no")) {
|
|
nsIPresShell* shell = mDocument->GetShell();
|
|
if (shell) {
|
|
shell->DisableThemeSupport();
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
void
|
|
nsContentSink::DoProcessLinkHeader()
|
|
{
|
|
nsAutoString value;
|
|
mDocument->GetHeaderData(nsGkAtoms::link, value);
|
|
ProcessLinkHeader(value);
|
|
}
|
|
|
|
// check whether the Link header field applies to the context resource
|
|
// see <http://tools.ietf.org/html/rfc5988#section-5.2>
|
|
|
|
bool
|
|
nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
|
|
{
|
|
if (aAnchor.IsEmpty()) {
|
|
// anchor parameter not present or empty -> same document reference
|
|
return true;
|
|
}
|
|
|
|
nsIURI* docUri = mDocument->GetDocumentURI();
|
|
|
|
// the document URI might contain a fragment identifier ("#...')
|
|
// we want to ignore that because it's invisible to the server
|
|
// and just affects the local interpretation in the recipient
|
|
nsCOMPtr<nsIURI> contextUri;
|
|
nsresult rv = docUri->CloneIgnoringRef(getter_AddRefs(contextUri));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
// copying failed
|
|
return false;
|
|
}
|
|
|
|
// resolve anchor against context
|
|
nsCOMPtr<nsIURI> resolvedUri;
|
|
rv = NS_NewURI(getter_AddRefs(resolvedUri), aAnchor,
|
|
nullptr, contextUri);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
// resolving failed
|
|
return false;
|
|
}
|
|
|
|
bool same;
|
|
rv = contextUri->Equals(resolvedUri, &same);
|
|
if (NS_FAILED(rv)) {
|
|
// comparison failed
|
|
return false;
|
|
}
|
|
|
|
return same;
|
|
}
|
|
|
|
// Decode a parameter value using the encoding defined in RFC 5987 (in place)
|
|
//
|
|
// charset "'" [ language ] "'" value-chars
|
|
//
|
|
// returns true when decoding happened successfully (otherwise leaves
|
|
// passed value alone)
|
|
bool
|
|
nsContentSink::Decode5987Format(nsAString& aEncoded) {
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
|
|
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return false;
|
|
|
|
nsAutoCString asciiValue;
|
|
|
|
const char16_t* encstart = aEncoded.BeginReading();
|
|
const char16_t* encend = aEncoded.EndReading();
|
|
|
|
// create a plain ASCII string, aborting if we can't do that
|
|
// converted form is always shorter than input
|
|
while (encstart != encend) {
|
|
if (*encstart > 0 && *encstart < 128) {
|
|
asciiValue.Append((char)*encstart);
|
|
} else {
|
|
return false;
|
|
}
|
|
encstart++;
|
|
}
|
|
|
|
nsAutoString decoded;
|
|
nsAutoCString language;
|
|
|
|
rv = mimehdrpar->DecodeRFC5987Param(asciiValue, language, decoded);
|
|
if (NS_FAILED(rv))
|
|
return false;
|
|
|
|
aEncoded = decoded;
|
|
return true;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::ProcessLinkHeader(const nsAString& aLinkData)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
// keep track where we are within the header field
|
|
bool seenParameters = false;
|
|
|
|
// parse link content and call process style link
|
|
nsAutoString href;
|
|
nsAutoString rel;
|
|
nsAutoString title;
|
|
nsAutoString titleStar;
|
|
nsAutoString type;
|
|
nsAutoString media;
|
|
nsAutoString anchor;
|
|
nsAutoString crossOrigin;
|
|
|
|
crossOrigin.SetIsVoid(true);
|
|
|
|
// copy to work buffer
|
|
nsAutoString stringList(aLinkData);
|
|
|
|
// put an extra null at the end
|
|
stringList.Append(kNullCh);
|
|
|
|
char16_t* start = stringList.BeginWriting();
|
|
char16_t* end = start;
|
|
char16_t* last = start;
|
|
char16_t endCh;
|
|
|
|
while (*start != kNullCh) {
|
|
// skip leading space
|
|
while ((*start != kNullCh) && nsCRT::IsAsciiSpace(*start)) {
|
|
++start;
|
|
}
|
|
|
|
end = start;
|
|
last = end - 1;
|
|
|
|
bool wasQuotedString = false;
|
|
|
|
// look for semicolon or comma
|
|
while (*end != kNullCh && *end != kSemicolon && *end != kComma) {
|
|
char16_t ch = *end;
|
|
|
|
if (ch == kQuote || ch == kLessThan) {
|
|
// quoted string
|
|
|
|
char16_t quote = ch;
|
|
if (quote == kLessThan) {
|
|
quote = kGreaterThan;
|
|
}
|
|
|
|
wasQuotedString = (ch == kQuote);
|
|
|
|
char16_t* closeQuote = (end + 1);
|
|
|
|
// seek closing quote
|
|
while (*closeQuote != kNullCh && quote != *closeQuote) {
|
|
// in quoted-string, "\" is an escape character
|
|
if (wasQuotedString && *closeQuote == kBackSlash && *(closeQuote + 1) != kNullCh) {
|
|
++closeQuote;
|
|
}
|
|
|
|
++closeQuote;
|
|
}
|
|
|
|
if (quote == *closeQuote) {
|
|
// found closer
|
|
|
|
// skip to close quote
|
|
end = closeQuote;
|
|
|
|
last = end - 1;
|
|
|
|
ch = *(end + 1);
|
|
|
|
if (ch != kNullCh && ch != kSemicolon && ch != kComma) {
|
|
// end string here
|
|
*(++end) = kNullCh;
|
|
|
|
ch = *(end + 1);
|
|
|
|
// keep going until semi or comma
|
|
while (ch != kNullCh && ch != kSemicolon && ch != kComma) {
|
|
++end;
|
|
|
|
ch = *(end + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
++end;
|
|
++last;
|
|
}
|
|
|
|
endCh = *end;
|
|
|
|
// end string here
|
|
*end = kNullCh;
|
|
|
|
if (start < end) {
|
|
if ((*start == kLessThan) && (*last == kGreaterThan)) {
|
|
*last = kNullCh;
|
|
|
|
// first instance of <...> wins
|
|
// also, do not allow hrefs after the first param was seen
|
|
if (href.IsEmpty() && !seenParameters) {
|
|
href = (start + 1);
|
|
href.StripWhitespace();
|
|
}
|
|
} else {
|
|
char16_t* equals = start;
|
|
seenParameters = true;
|
|
|
|
while ((*equals != kNullCh) && (*equals != kEqual)) {
|
|
equals++;
|
|
}
|
|
|
|
if (*equals != kNullCh) {
|
|
*equals = kNullCh;
|
|
nsAutoString attr(start);
|
|
attr.StripWhitespace();
|
|
|
|
char16_t* value = ++equals;
|
|
while (nsCRT::IsAsciiSpace(*value)) {
|
|
value++;
|
|
}
|
|
|
|
if ((*value == kQuote) && (*value == *last)) {
|
|
*last = kNullCh;
|
|
value++;
|
|
}
|
|
|
|
if (wasQuotedString) {
|
|
// unescape in-place
|
|
char16_t* unescaped = value;
|
|
char16_t *src = value;
|
|
|
|
while (*src != kNullCh) {
|
|
if (*src == kBackSlash && *(src + 1) != kNullCh) {
|
|
src++;
|
|
}
|
|
*unescaped++ = *src++;
|
|
}
|
|
|
|
*unescaped = kNullCh;
|
|
}
|
|
|
|
if (attr.LowerCaseEqualsLiteral("rel")) {
|
|
if (rel.IsEmpty()) {
|
|
rel = value;
|
|
rel.CompressWhitespace();
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("title")) {
|
|
if (title.IsEmpty()) {
|
|
title = value;
|
|
title.CompressWhitespace();
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("title*")) {
|
|
if (titleStar.IsEmpty() && !wasQuotedString) {
|
|
// RFC 5987 encoding; uses token format only, so skip if we get
|
|
// here with a quoted-string
|
|
nsAutoString tmp;
|
|
tmp = value;
|
|
if (Decode5987Format(tmp)) {
|
|
titleStar = tmp;
|
|
titleStar.CompressWhitespace();
|
|
} else {
|
|
// header value did not parse, throw it away
|
|
titleStar.Truncate();
|
|
}
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("type")) {
|
|
if (type.IsEmpty()) {
|
|
type = value;
|
|
type.StripWhitespace();
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("media")) {
|
|
if (media.IsEmpty()) {
|
|
media = value;
|
|
|
|
// The HTML5 spec is formulated in terms of the CSS3 spec,
|
|
// which specifies that media queries are case insensitive.
|
|
nsContentUtils::ASCIIToLower(media);
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("anchor")) {
|
|
if (anchor.IsEmpty()) {
|
|
anchor = value;
|
|
anchor.StripWhitespace();
|
|
}
|
|
} else if (attr.LowerCaseEqualsLiteral("crossorigin")) {
|
|
if (crossOrigin.IsVoid()) {
|
|
crossOrigin.SetIsVoid(false);
|
|
crossOrigin = value;
|
|
crossOrigin.StripWhitespace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (endCh == kComma) {
|
|
// hit a comma, process what we've got so far
|
|
|
|
href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
|
|
if (!href.IsEmpty() && !rel.IsEmpty()) {
|
|
rv = ProcessLink(anchor, href, rel,
|
|
// prefer RFC 5987 variant over non-I18zed version
|
|
titleStar.IsEmpty() ? title : titleStar,
|
|
type, media, crossOrigin);
|
|
}
|
|
|
|
href.Truncate();
|
|
rel.Truncate();
|
|
title.Truncate();
|
|
type.Truncate();
|
|
media.Truncate();
|
|
anchor.Truncate();
|
|
crossOrigin.SetIsVoid(true);
|
|
|
|
seenParameters = false;
|
|
}
|
|
|
|
start = ++end;
|
|
}
|
|
|
|
href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
|
|
if (!href.IsEmpty() && !rel.IsEmpty()) {
|
|
rv = ProcessLink(anchor, href, rel,
|
|
// prefer RFC 5987 variant over non-I18zed version
|
|
titleStar.IsEmpty() ? title : titleStar,
|
|
type, media, crossOrigin);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
|
const nsSubstring& aRel, const nsSubstring& aTitle,
|
|
const nsSubstring& aType, const nsSubstring& aMedia,
|
|
const nsSubstring& aCrossOrigin)
|
|
{
|
|
uint32_t linkTypes =
|
|
nsStyleLinkElement::ParseLinkTypes(aRel, mDocument->NodePrincipal());
|
|
|
|
// The link relation may apply to a different resource, specified
|
|
// in the anchor parameter. For the link relations supported so far,
|
|
// we simply abort if the link applies to a resource different to the
|
|
// one we've loaded
|
|
if (!LinkContextIsOurDocument(aAnchor)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
|
|
// prefetch href if relation is "next" or "prefetch"
|
|
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
|
|
PrefetchHref(aHref, mDocument, hasPrefetch);
|
|
}
|
|
|
|
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::eDNS_PREFETCH)) {
|
|
PrefetchDNS(aHref);
|
|
}
|
|
|
|
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::ePRECONNECT)) {
|
|
Preconnect(aHref, aCrossOrigin);
|
|
}
|
|
|
|
// is it a stylesheet link?
|
|
if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
bool isAlternate = linkTypes & nsStyleLinkElement::eALTERNATE;
|
|
return ProcessStyleLink(nullptr, aHref, isAlternate, aTitle, aType,
|
|
aMedia);
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::ProcessStyleLink(nsIContent* aElement,
|
|
const nsSubstring& aHref,
|
|
bool aAlternate,
|
|
const nsSubstring& aTitle,
|
|
const nsSubstring& aType,
|
|
const nsSubstring& aMedia)
|
|
{
|
|
if (aAlternate && aTitle.IsEmpty()) {
|
|
// alternates must have title return without error, for now
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoString mimeType;
|
|
nsAutoString params;
|
|
nsContentUtils::SplitMimeType(aType, mimeType, params);
|
|
|
|
// see bug 18817
|
|
if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
|
|
// Unknown stylesheet language
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> url;
|
|
nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
|
|
mDocument->GetDocBaseURI());
|
|
|
|
if (NS_FAILED(rv)) {
|
|
// The URI is bad, move along, don't propagate the error (for now)
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_ASSERTION(!aElement ||
|
|
aElement->NodeType() == nsIDOMNode::PROCESSING_INSTRUCTION_NODE,
|
|
"We only expect processing instructions here");
|
|
|
|
nsAutoString integrity;
|
|
if (aElement) {
|
|
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity, integrity);
|
|
}
|
|
if (!integrity.IsEmpty()) {
|
|
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
|
("nsContentSink::ProcessStyleLink, integrity=%s",
|
|
NS_ConvertUTF16toUTF8(integrity).get()));
|
|
}
|
|
|
|
// If this is a fragment parser, we don't want to observe.
|
|
// We don't support CORS for processing instructions
|
|
bool isAlternate;
|
|
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
|
|
CORS_NONE, mDocument->GetReferrerPolicy(),
|
|
integrity, mRunsToCompletion ? nullptr : this,
|
|
&isAlternate);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!isAlternate && !mRunsToCompletion) {
|
|
++mPendingSheetCount;
|
|
mScriptLoader->AddExecuteBlocker();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsContentSink::ProcessMETATag(nsIContent* aContent)
|
|
{
|
|
NS_ASSERTION(aContent, "missing meta-element");
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
// set any HTTP-EQUIV data into document's header data as well as url
|
|
nsAutoString header;
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
|
|
if (!header.IsEmpty()) {
|
|
// Ignore META REFRESH when document is sandboxed from automatic features.
|
|
nsContentUtils::ASCIIToLower(header);
|
|
if (nsGkAtoms::refresh->Equals(header) &&
|
|
(mDocument->GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoString result;
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
|
if (!result.IsEmpty()) {
|
|
nsCOMPtr<nsIAtom> fieldAtom(do_GetAtom(header));
|
|
rv = ProcessHeaderData(fieldAtom, result, aContent);
|
|
}
|
|
}
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
|
nsGkAtoms::handheldFriendly, eIgnoreCase)) {
|
|
nsAutoString result;
|
|
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
|
if (!result.IsEmpty()) {
|
|
nsContentUtils::ASCIIToLower(result);
|
|
mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
void
|
|
nsContentSink::PrefetchHref(const nsAString &aHref,
|
|
nsINode *aSource,
|
|
bool aExplicit)
|
|
{
|
|
//
|
|
// SECURITY CHECK: disable prefetching from mailnews!
|
|
//
|
|
// walk up the docshell tree to see if any containing
|
|
// docshell are of type MAIL.
|
|
//
|
|
if (!mDocShell)
|
|
return;
|
|
|
|
nsCOMPtr<nsIDocShell> docshell = mDocShell;
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
|
do {
|
|
uint32_t appType = 0;
|
|
nsresult rv = docshell->GetAppType(&appType);
|
|
if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
|
|
return; // do not prefetch from mailnews
|
|
docshell->GetParent(getter_AddRefs(parentItem));
|
|
if (parentItem) {
|
|
docshell = do_QueryInterface(parentItem);
|
|
if (!docshell) {
|
|
NS_ERROR("cannot get a docshell from a treeItem!");
|
|
return;
|
|
}
|
|
}
|
|
} while (parentItem);
|
|
|
|
// OK, we passed the security check...
|
|
|
|
nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
|
|
if (prefetchService) {
|
|
// construct URI using document charset
|
|
const nsACString &charset = mDocument->GetDocumentCharacterSet();
|
|
nsCOMPtr<nsIURI> uri;
|
|
NS_NewURI(getter_AddRefs(uri), aHref,
|
|
charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
|
|
mDocument->GetDocBaseURI());
|
|
if (uri) {
|
|
nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aSource);
|
|
prefetchService->PrefetchURI(uri, mDocumentURI, domNode, aExplicit);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::PrefetchDNS(const nsAString &aHref)
|
|
{
|
|
nsAutoString hostname;
|
|
|
|
if (StringBeginsWith(aHref, NS_LITERAL_STRING("//"))) {
|
|
hostname = Substring(aHref, 2);
|
|
}
|
|
else {
|
|
nsCOMPtr<nsIURI> uri;
|
|
NS_NewURI(getter_AddRefs(uri), aHref);
|
|
if (!uri) {
|
|
return;
|
|
}
|
|
nsresult rv;
|
|
bool isLocalResource = false;
|
|
rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
|
|
&isLocalResource);
|
|
if (NS_SUCCEEDED(rv) && !isLocalResource) {
|
|
nsAutoCString host;
|
|
uri->GetHost(host);
|
|
CopyUTF8toUTF16(host, hostname);
|
|
}
|
|
}
|
|
|
|
if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
|
|
nsHTMLDNSPrefetch::PrefetchLow(hostname);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin)
|
|
{
|
|
// construct URI using document charset
|
|
const nsACString& charset = mDocument->GetDocumentCharacterSet();
|
|
nsCOMPtr<nsIURI> uri;
|
|
NS_NewURI(getter_AddRefs(uri), aHref,
|
|
charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
|
|
mDocument->GetDocBaseURI());
|
|
|
|
if (uri && mDocument) {
|
|
mDocument->MaybePreconnect(uri, dom::Element::StringToCORSMode(aCrossOrigin));
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
|
|
nsIURI *aManifestURI,
|
|
bool aFetchedWithHTTPGetOrEquiv,
|
|
CacheSelectionAction *aAction)
|
|
{
|
|
nsresult rv;
|
|
|
|
*aAction = CACHE_SELECTION_NONE;
|
|
|
|
nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
|
|
do_QueryInterface(mDocument);
|
|
NS_ASSERTION(applicationCacheDocument,
|
|
"mDocument must implement nsIApplicationCacheContainer.");
|
|
|
|
if (aLoadApplicationCache) {
|
|
nsCOMPtr<nsIURI> groupURI;
|
|
rv = aLoadApplicationCache->GetManifestURI(getter_AddRefs(groupURI));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool equal = false;
|
|
rv = groupURI->Equals(aManifestURI, &equal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!equal) {
|
|
// This is a foreign entry, force a reload to avoid loading the foreign
|
|
// entry. The entry will be marked as foreign to avoid loading it again.
|
|
|
|
*aAction = CACHE_SELECTION_RELOAD;
|
|
}
|
|
else {
|
|
// The http manifest attribute URI is equal to the manifest URI of
|
|
// the cache the document was loaded from - associate the document with
|
|
// that cache and invoke the cache update process.
|
|
#ifdef DEBUG
|
|
nsAutoCString docURISpec, clientID;
|
|
mDocumentURI->GetAsciiSpec(docURISpec);
|
|
aLoadApplicationCache->GetClientID(clientID);
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
|
|
("Selection: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
|
|
#endif
|
|
|
|
rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Document will be added as implicit entry to the cache as part of
|
|
// the update process.
|
|
*aAction = CACHE_SELECTION_UPDATE;
|
|
}
|
|
}
|
|
else {
|
|
// The document was not loaded from an application cache
|
|
// Here we know the manifest has the same origin as the
|
|
// document. There is call to CheckMayLoad() on it above.
|
|
|
|
if (!aFetchedWithHTTPGetOrEquiv) {
|
|
// The document was not loaded using HTTP GET or equivalent
|
|
// method. The spec says to run the cache selection algorithm w/o
|
|
// the manifest specified.
|
|
*aAction = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
|
|
}
|
|
else {
|
|
// Always do an update in this case
|
|
*aAction = CACHE_SELECTION_UPDATE;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
|
|
nsIURI **aManifestURI,
|
|
CacheSelectionAction *aAction)
|
|
{
|
|
*aManifestURI = nullptr;
|
|
*aAction = CACHE_SELECTION_NONE;
|
|
|
|
nsresult rv;
|
|
|
|
if (aLoadApplicationCache) {
|
|
// The document was loaded from an application cache, use that
|
|
// application cache as the document's application cache.
|
|
nsCOMPtr<nsIApplicationCacheContainer> applicationCacheDocument =
|
|
do_QueryInterface(mDocument);
|
|
NS_ASSERTION(applicationCacheDocument,
|
|
"mDocument must implement nsIApplicationCacheContainer.");
|
|
|
|
#ifdef DEBUG
|
|
nsAutoCString docURISpec, clientID;
|
|
mDocumentURI->GetAsciiSpec(docURISpec);
|
|
aLoadApplicationCache->GetClientID(clientID);
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
|
|
("Selection, no manifest: assigning app cache %s to document %s", clientID.get(), docURISpec.get()));
|
|
#endif
|
|
|
|
rv = applicationCacheDocument->SetApplicationCache(aLoadApplicationCache);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Return the uri and invoke the update process for the selected
|
|
// application cache.
|
|
rv = aLoadApplicationCache->GetManifestURI(aManifestURI);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
*aAction = CACHE_SELECTION_UPDATE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsContentSink::ProcessOfflineManifest(nsIContent *aElement)
|
|
{
|
|
// Only check the manifest for root document nodes.
|
|
if (aElement != mDocument->GetRootElement()) {
|
|
return;
|
|
}
|
|
|
|
// Don't bother processing offline manifest for documents
|
|
// without a docshell
|
|
if (!mDocShell) {
|
|
return;
|
|
}
|
|
|
|
// Check for a manifest= attribute.
|
|
nsAutoString manifestSpec;
|
|
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec);
|
|
ProcessOfflineManifest(manifestSpec);
|
|
}
|
|
|
|
void
|
|
nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
|
|
{
|
|
// Don't bother processing offline manifest for documents
|
|
// without a docshell
|
|
if (!mDocShell) {
|
|
return;
|
|
}
|
|
|
|
// If this document has been interecepted, let's skip the processing of the
|
|
// manifest.
|
|
if (nsContentUtils::IsControlledByServiceWorker(mDocument)) {
|
|
return;
|
|
}
|
|
|
|
// If the docshell's in private browsing mode, we don't want to do any
|
|
// manifest processing.
|
|
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);
|
|
if (loadContext->UsePrivateBrowsing()) {
|
|
return;
|
|
}
|
|
|
|
nsresult rv;
|
|
|
|
// Grab the application cache the document was loaded from, if any.
|
|
nsCOMPtr<nsIApplicationCache> applicationCache;
|
|
|
|
nsCOMPtr<nsIApplicationCacheChannel> applicationCacheChannel =
|
|
do_QueryInterface(mDocument->GetChannel());
|
|
if (applicationCacheChannel) {
|
|
bool loadedFromApplicationCache;
|
|
rv = applicationCacheChannel->GetLoadedFromApplicationCache(
|
|
&loadedFromApplicationCache);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
|
|
if (loadedFromApplicationCache) {
|
|
rv = applicationCacheChannel->GetApplicationCache(
|
|
getter_AddRefs(applicationCache));
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aManifestSpec.IsEmpty() && !applicationCache) {
|
|
// Not loaded from an application cache, and no manifest
|
|
// attribute. Nothing to do here.
|
|
return;
|
|
}
|
|
|
|
CacheSelectionAction action = CACHE_SELECTION_NONE;
|
|
nsCOMPtr<nsIURI> manifestURI;
|
|
|
|
if (aManifestSpec.IsEmpty()) {
|
|
action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
|
|
}
|
|
else {
|
|
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI),
|
|
aManifestSpec, mDocument,
|
|
mDocumentURI);
|
|
if (!manifestURI) {
|
|
return;
|
|
}
|
|
|
|
// Documents must list a manifest from the same origin
|
|
rv = mDocument->NodePrincipal()->CheckMayLoad(manifestURI, true, false);
|
|
if (NS_FAILED(rv)) {
|
|
action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
|
|
}
|
|
else {
|
|
// Only continue if the document has permission to use offline APIs or
|
|
// when preferences indicate to permit it automatically.
|
|
if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) &&
|
|
!nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) &&
|
|
!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
|
|
return;
|
|
}
|
|
|
|
bool fetchedWithHTTPGetOrEquiv = false;
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mDocument->GetChannel()));
|
|
if (httpChannel) {
|
|
nsAutoCString method;
|
|
rv = httpChannel->GetRequestMethod(method);
|
|
if (NS_SUCCEEDED(rv))
|
|
fetchedWithHTTPGetOrEquiv = method.EqualsLiteral("GET");
|
|
}
|
|
|
|
rv = SelectDocAppCache(applicationCache, manifestURI,
|
|
fetchedWithHTTPGetOrEquiv, &action);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (action == CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST) {
|
|
rv = SelectDocAppCacheNoManifest(applicationCache,
|
|
getter_AddRefs(manifestURI),
|
|
&action);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (action)
|
|
{
|
|
case CACHE_SELECTION_NONE:
|
|
break;
|
|
case CACHE_SELECTION_UPDATE: {
|
|
nsCOMPtr<nsIOfflineCacheUpdateService> updateService =
|
|
do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
|
|
|
|
if (updateService) {
|
|
nsCOMPtr<nsIDOMDocument> domdoc = do_QueryInterface(mDocument);
|
|
updateService->ScheduleOnDocumentStop(manifestURI, mDocumentURI,
|
|
mDocument->NodePrincipal(), domdoc);
|
|
}
|
|
break;
|
|
}
|
|
case CACHE_SELECTION_RELOAD: {
|
|
// This situation occurs only for toplevel documents, see bottom
|
|
// of SelectDocAppCache method.
|
|
// The document has been loaded from a different offline cache group than
|
|
// the manifest it refers to, i.e. this is a foreign entry, mark it as such
|
|
// and force a reload to avoid loading it. The next attempt will not
|
|
// choose it.
|
|
|
|
applicationCacheChannel->MarkOfflineCacheEntryAsForeign();
|
|
|
|
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
|
|
|
|
webNav->Stop(nsIWebNavigation::STOP_ALL);
|
|
webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
|
|
break;
|
|
}
|
|
default:
|
|
NS_ASSERTION(false,
|
|
"Cache selection algorithm didn't decide on proper action");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::ScrollToRef()
|
|
{
|
|
mDocument->ScrollToRef();
|
|
}
|
|
|
|
void
|
|
nsContentSink::StartLayout(bool aIgnorePendingSheets)
|
|
{
|
|
if (mLayoutStarted) {
|
|
// Nothing to do here
|
|
return;
|
|
}
|
|
|
|
mDeferredLayoutStart = true;
|
|
|
|
if (!aIgnorePendingSheets && WaitForPendingSheets()) {
|
|
// Bail out; we'll start layout when the sheets load
|
|
return;
|
|
}
|
|
|
|
mDeferredLayoutStart = false;
|
|
|
|
// Notify on all our content. If none of our presshells have started layout
|
|
// yet it'll be a no-op except for updating our data structures, a la
|
|
// UpdateChildCounts() (because we don't want to double-notify on whatever we
|
|
// have right now). If some of them _have_ started layout, we want to make
|
|
// sure to flush tags instead of just calling UpdateChildCounts() after we
|
|
// loop over the shells.
|
|
FlushTags();
|
|
|
|
mLayoutStarted = true;
|
|
mLastNotificationTime = PR_Now();
|
|
|
|
mDocument->SetMayStartLayout(true);
|
|
nsCOMPtr<nsIPresShell> shell = mDocument->GetShell();
|
|
// Make sure we don't call Initialize() for a shell that has
|
|
// already called it. This can happen when the layout frame for
|
|
// an iframe is constructed *between* the Embed() call for the
|
|
// docshell in the iframe, and the content sink's call to OpenBody().
|
|
// (Bug 153815)
|
|
if (shell && !shell->DidInitialize()) {
|
|
nsRect r = shell->GetPresContext()->GetVisibleArea();
|
|
nsCOMPtr<nsIPresShell> shellGrip = shell;
|
|
nsresult rv = shell->Initialize(r.width, r.height);
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// If the document we are loading has a reference or it is a
|
|
// frameset document, disable the scroll bars on the views.
|
|
|
|
mDocument->SetScrollToRef(mDocument->GetDocumentURI());
|
|
}
|
|
|
|
void
|
|
nsContentSink::NotifyAppend(nsIContent* aContainer, uint32_t aStartIndex)
|
|
{
|
|
if (aContainer->GetUncomposedDoc() != mDocument) {
|
|
// aContainer is not actually in our document anymore.... Just bail out of
|
|
// here; notifying on our document for this append would be wrong.
|
|
return;
|
|
}
|
|
|
|
mInNotification++;
|
|
|
|
{
|
|
// Scope so we call EndUpdate before we decrease mInNotification
|
|
MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
|
|
nsNodeUtils::ContentAppended(aContainer,
|
|
aContainer->GetChildAt(aStartIndex),
|
|
aStartIndex);
|
|
mLastNotificationTime = PR_Now();
|
|
}
|
|
|
|
mInNotification--;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsContentSink::Notify(nsITimer *timer)
|
|
{
|
|
if (mParsing) {
|
|
// We shouldn't interfere with our normal DidProcessAToken logic
|
|
mDroppedTimer = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (WaitForPendingSheets()) {
|
|
mDeferredFlushTags = true;
|
|
} else {
|
|
FlushTags();
|
|
|
|
// Now try and scroll to the reference
|
|
// XXX Should we scroll unconditionally for history loads??
|
|
ScrollToRef();
|
|
}
|
|
|
|
mNotificationTimer = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
nsContentSink::IsTimeToNotify()
|
|
{
|
|
if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
|
|
mInMonolithicContainer) {
|
|
return false;
|
|
}
|
|
|
|
if (WaitForPendingSheets()) {
|
|
mDeferredFlushTags = true;
|
|
return false;
|
|
}
|
|
|
|
PRTime now = PR_Now();
|
|
|
|
int64_t interval = GetNotificationInterval();
|
|
int64_t diff = now - mLastNotificationTime;
|
|
|
|
if (diff > interval) {
|
|
mBackoffCount--;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::WillInterruptImpl()
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
|
|
("nsContentSink::WillInterrupt: this=%p", this));
|
|
#ifndef SINK_NO_INCREMENTAL
|
|
if (WaitForPendingSheets()) {
|
|
mDeferredFlushTags = true;
|
|
} else if (sNotifyOnTimer && mLayoutStarted) {
|
|
if (mBackoffCount && !mInMonolithicContainer) {
|
|
int64_t now = PR_Now();
|
|
int64_t interval = GetNotificationInterval();
|
|
int64_t diff = now - mLastNotificationTime;
|
|
|
|
// If it's already time for us to have a notification
|
|
if (diff > interval || mDroppedTimer) {
|
|
mBackoffCount--;
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
|
|
("nsContentSink::WillInterrupt: flushing tags since we've "
|
|
"run out time; backoff count: %d", mBackoffCount));
|
|
result = FlushTags();
|
|
if (mDroppedTimer) {
|
|
ScrollToRef();
|
|
mDroppedTimer = false;
|
|
}
|
|
} else if (!mNotificationTimer) {
|
|
interval -= diff;
|
|
int32_t delay = interval;
|
|
|
|
// Convert to milliseconds
|
|
delay /= PR_USEC_PER_MSEC;
|
|
|
|
mNotificationTimer = do_CreateInstance("@mozilla.org/timer;1",
|
|
&result);
|
|
if (NS_SUCCEEDED(result)) {
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
|
|
("nsContentSink::WillInterrupt: setting up timer with "
|
|
"delay %d", delay));
|
|
|
|
result =
|
|
mNotificationTimer->InitWithCallback(this, delay,
|
|
nsITimer::TYPE_ONE_SHOT);
|
|
if (NS_FAILED(result)) {
|
|
mNotificationTimer = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
|
|
("nsContentSink::WillInterrupt: flushing tags "
|
|
"unconditionally"));
|
|
result = FlushTags();
|
|
}
|
|
#endif
|
|
|
|
mParsing = false;
|
|
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::WillResumeImpl()
|
|
{
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
|
|
("nsContentSink::WillResume: this=%p", this));
|
|
|
|
mParsing = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::DidProcessATokenImpl()
|
|
{
|
|
if (mRunsToCompletion || !mParser) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get the current user event time
|
|
nsIPresShell *shell = mDocument->GetShell();
|
|
if (!shell) {
|
|
// If there's no pres shell in the document, return early since
|
|
// we're not laying anything out here.
|
|
return NS_OK;
|
|
}
|
|
|
|
// Increase before comparing to gEventProbeRate
|
|
++mDeflectedCount;
|
|
|
|
// Check if there's a pending event
|
|
if (sPendingEventMode != 0 && !mHasPendingEvent &&
|
|
(mDeflectedCount % sEventProbeRate) == 0) {
|
|
nsViewManager* vm = shell->GetViewManager();
|
|
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
|
|
nsCOMPtr<nsIWidget> widget;
|
|
vm->GetRootWidget(getter_AddRefs(widget));
|
|
mHasPendingEvent = widget && widget->HasPendingInputEvent();
|
|
}
|
|
|
|
if (mHasPendingEvent && sPendingEventMode == 2) {
|
|
return NS_ERROR_HTMLPARSER_INTERRUPTED;
|
|
}
|
|
|
|
// Have we processed enough tokens to check time?
|
|
if (!mHasPendingEvent &&
|
|
mDeflectedCount < uint32_t(mDynamicLowerValue ? sInteractiveDeflectCount :
|
|
sPerfDeflectCount)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
mDeflectedCount = 0;
|
|
|
|
// Check if it's time to return to the main event loop
|
|
if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
|
|
return NS_ERROR_HTMLPARSER_INTERRUPTED;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
|
|
{
|
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
|
if (appShell)
|
|
appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
|
|
}
|
|
|
|
void
|
|
nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
|
|
{
|
|
// Remember nested updates from updates that we started.
|
|
if (mInNotification > 0 && mUpdatesInNotification < 2) {
|
|
++mUpdatesInNotification;
|
|
}
|
|
|
|
// If we're in a script and we didn't do the notification,
|
|
// something else in the script processing caused the
|
|
// notification to occur. Since this could result in frame
|
|
// creation, make sure we've flushed everything before we
|
|
// continue.
|
|
|
|
if (!mInNotification++) {
|
|
FlushTags();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
|
|
{
|
|
// If we're in a script and we didn't do the notification,
|
|
// something else in the script processing caused the
|
|
// notification to occur. Update our notion of how much
|
|
// has been flushed to include any new content if ending
|
|
// this update leaves us not inside a notification.
|
|
if (!--mInNotification) {
|
|
UpdateChildCounts();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::DidBuildModelImpl(bool aTerminated)
|
|
{
|
|
if (mDocument) {
|
|
MOZ_ASSERT(aTerminated ||
|
|
mDocument->GetReadyStateEnum() ==
|
|
nsIDocument::READYSTATE_LOADING, "Bad readyState");
|
|
mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
|
|
}
|
|
|
|
if (mScriptLoader) {
|
|
mScriptLoader->ParsingComplete(aTerminated);
|
|
}
|
|
|
|
if (!mDocument->HaveFiredDOMTitleChange()) {
|
|
mDocument->NotifyPossibleTitleChange(false);
|
|
}
|
|
|
|
// Cancel a timer if we had one out there
|
|
if (mNotificationTimer) {
|
|
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,
|
|
("nsContentSink::DidBuildModel: canceling notification "
|
|
"timeout"));
|
|
mNotificationTimer->Cancel();
|
|
mNotificationTimer = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsContentSink::DropParserAndPerfHint(void)
|
|
{
|
|
if (!mParser) {
|
|
// Make sure we don't unblock unload too many times
|
|
return;
|
|
}
|
|
|
|
// Ref. Bug 49115
|
|
// Do this hack to make sure that the parser
|
|
// doesn't get destroyed, accidently, before
|
|
// the circularity, between sink & parser, is
|
|
// actually broken.
|
|
// Drop our reference to the parser to get rid of a circular
|
|
// reference.
|
|
RefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
|
|
|
|
if (mDynamicLowerValue) {
|
|
// Reset the performance hint which was set to FALSE
|
|
// when mDynamicLowerValue was set.
|
|
FavorPerformanceHint(true, 0);
|
|
}
|
|
|
|
if (!mRunsToCompletion) {
|
|
mDocument->UnblockOnload(true);
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsContentSink::IsScriptExecutingImpl()
|
|
{
|
|
return !!mScriptLoader->GetCurrentScript();
|
|
}
|
|
|
|
nsresult
|
|
nsContentSink::WillParseImpl(void)
|
|
{
|
|
if (mRunsToCompletion || !mDocument) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIPresShell *shell = mDocument->GetShell();
|
|
if (!shell) {
|
|
return NS_OK;
|
|
}
|
|
|
|
uint32_t currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
|
|
|
if (sEnablePerfMode == 0) {
|
|
nsViewManager* vm = shell->GetViewManager();
|
|
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
|
|
uint32_t lastEventTime;
|
|
vm->GetLastUserEventTime(lastEventTime);
|
|
|
|
bool newDynLower =
|
|
mDocument->IsInBackgroundWindow() ||
|
|
((currentTime - mBeginLoadTime) > uint32_t(sInitialPerfTime) &&
|
|
(currentTime - lastEventTime) < uint32_t(sInteractiveTime));
|
|
|
|
if (mDynamicLowerValue != newDynLower) {
|
|
FavorPerformanceHint(!newDynLower, 0);
|
|
mDynamicLowerValue = newDynLower;
|
|
}
|
|
}
|
|
|
|
mDeflectedCount = 0;
|
|
mHasPendingEvent = false;
|
|
|
|
mCurrentParseEndTime = currentTime +
|
|
(mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsContentSink::WillBuildModelImpl()
|
|
{
|
|
if (!mRunsToCompletion) {
|
|
mDocument->BlockOnload();
|
|
|
|
mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
|
}
|
|
|
|
mDocument->ResetScrolledToRefAlready();
|
|
|
|
if (mProcessLinkHeaderEvent.get()) {
|
|
mProcessLinkHeaderEvent.Revoke();
|
|
|
|
DoProcessLinkHeader();
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
void
|
|
nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
|
|
{
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
mozilla::services::GetObserverService();
|
|
if (observerService) {
|
|
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
|
|
observerService->
|
|
NotifyObservers(domDoc, "document-element-inserted",
|
|
EmptyString().get());
|
|
}
|
|
|
|
nsContentUtils::DispatchChromeEvent(aDoc, aDoc,
|
|
NS_LITERAL_STRING("DOMDocElementInserted"),
|
|
true, false);
|
|
}
|