mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1246851 (Part 1) - Add a new SurfacePipe API for writing to image surfaces in a safe and composable manner. r=njn (2e3353a6a7) - Bug 1246851 (Part 2) - Add SurfaceFilter implementations for basic surface output operations. r=njn (fa30948a3f) - Bug 1246851 (Part 3) - Add a factory for constructing SurfacePipes. r=njn (7a746d3ec8) - Bug 1191347 - Explicitly release surfaces on the main thread in TestDecodeToSurface. r=me (fa1a68dc9a) - Bug 1246851 (Part 4) - Add a test suite for SurfacePipes and SurfaceFilters. r=njn (380dc94c08) - Bug 1247152 (Part 1) - Use SurfacePipe in the GIF decoder. r=njn (8b3d76f017) - Bug 1247152 (Part 2) - Remove even more code from the GIF decoder. r=edwin (80c8cc5e1c) - side effects Bug 1247152 (Part 1) (5b6cbf0ad5) - Bug 1237232 - Properly check the result of Vector append() calls in security/. r=keeler (b06dce061f) - Bug 1235308 - Fix -Wimplicit-fallthrough warnings in security/. r=keeler (ac5c3bf540) - Bug 1235188 - Fix -Wformat warnings in security/certverifier/. r=keeler (25ee7ee77c) - Bug 1004149 - Remove some dead code. r=keeler (59fedcb6a6) - Bug 1004149 - Return mozilla::pkix::Result values in nsNSSHttpInterface functions. r=keeler (76933c7d94) - Bug 1187173 - Disable warning C4623 on security/certverifier. r=briansmith (c1353b0577) - Bug 1256484 - Disable C4456 and C4458 to unblock compilation on VS2015; r=keeler (b51ac368ba) - Bug 1251009 - Remove unused nsICertificateDialogs.notifyCACertExists() method. r=keeler, r=mfinkle (9ca9aee3d0) - Bug 1249224 - window.open() should open a new window in the same container, r=bz (c57c76ec2f) - Bug 1245451 - add default nullptr value to mChrome. r=bsmedberg (3236ea34df) - Bug 1255849. Add some documentation for AutoJSAPI instances that seem to be used just for cxpushing. r=bholley (60a81652de) - Bug 1189554 - Make Saved Passwords dialog resizable on Windows again. r=smaug (a367796251) - Bug 1252974 - Convert screen's available dimensions to CSS-pixel units in nsWindowWatcher. r=emk (5524055ab0) - Bug 1233328 - Part 1: Ignore SHA-1 pins in PublicKeyPinningService.cpp. r=keeler (e5fe732a4b) - Bug 1233328 - Part 2: Use SHA-256 StaticFingerprints directly instead창 of StaticPinset since the SHA-1 StaticFingerprints entry will always be null. r=keeler (50f88c76da) - Bug 1256089 - Fix Mutex support for tier-3 platforms; r=froydnj (76ab483843) - Bug 1257019 - Add move construction to js::Mutex<T>. r=terrence (383ad474ba) - No bug, Automated HPKP preload list update from host bld-linux64-spot-309 - a=hpkp-update (0a6d3b9c40) - No bug, Automated HPKP preload list update from host bld-linux64-spot-223 - a=hpkp-update (7b3dbac6f8) - Bug 1255655 - Const-ify kPinset_* arrays. r=cykesiopka. (ddbaad40a0) - No bug, Automated HPKP preload list update from host bld-linux64-spot-543 - a=hpkp-update (f5c37e366a) - bug 1233853 - make nsSyncJPAKE aware of NSS shutdown r=jcj (9f74b5a46f) - Bug 1215734 - Expand GeckoMediaPlugin sandbox policy for Clang 3.7 ASan. r=kang (a96e0429e5) - part Bug 1154738 - Fixed WMFUtils.cpp compilation on mingw (9ba8bd1481) - Bug 1256498. Explicitly convert to float. r=bas (ce97ef100e) - Bug 1223736 - Part 1: Set correct effective transform on mask layers. r=thinker (a87514ac4f) - Bug 1249813 - part 1 - revise nsShmImage to allow draw targets anywhere inside its bounds. r=jrmuizel (cba4cdf8c9) - Bug 1249813 - part 2 - make Cairo mark a surface as clear if clip covers entire surface. r=jrmuizel (45ccfcfc15) - Bug 1249813 - part 3 - tell the compositor if the root layer has opaque content so it can skip clears. r=mattwoodrow (2abaa0cf8b) - Bug 1255303 - Use SurfaceFormat::B8G8R8X8 as back buffer if possible r=jrmuizel (5f81a83123) - Bug 1253860 - Don't update the scrollbar unless we're actually painting. r=mstange (d3a2482408) - Bug 1253860 - Add a flag on scroll frames indicating if they have an APZ counterpart. r=mstange (2aef746ee1) - Bug 1253860 - Skip paints for main thread scrolls if we can ask APZ to handle the scrolling for us. r=mstange (4483da1f16) - Bug 1244116 - Telemetry for mixed content requests by plugins. r=smaug, p=ally (fd5f87f666) - Bug 1252829 - CSP Telemetry. r=ckerschb, p=bsmedberg (8d340fa824) - Bug 1246464: Add 'const' to some stylesheet args in nsDocument methods. r=heycam (4e744d81d2) - Bug 1255705 - Add some useful logging that can be enabled at compile time. r=botond (80f0202160) - Bug 1255856 - Don't allow paint-skipping if there are windowed plugins on the page. r=mstange,jimm (25e6d8ed22) - Bug 1256727 - Don't allow paint-skipping on pages with scroll-linked effects. r=mstange (a8bace52ff) - Bug 1247098 - Take document resolution into account when computing root composition bounds for displayport base. r=tnikkel (1b7b61c82e) - Bug 1250550 - Ensure a scroll event posted during a refresh driver tick fires during that same tick. r=mats (d5bfc24524) - Bug 1253739 - Fix incorrect namespace on forward declaration. r=botond (dfc7aac51e) - Bug 1253489 - Update SendFenceHandleIfPresent() r=nical (798c209dff) - Bug 1253860 - Stop APZC from reprocessing stale metrics on unrelated layer tree updates. r=botond (1013df0068) - Bug 1253860 - Add machinery to update APZ's scroll offset without a main-thread paint. r=botond (cb95baf9c6) - Bug 1239564 - Post translate maskSurface to renderTarget. r=roc (66c56d227d) - Bug 1223736 - Part 2: Draw masks in the correct coordinate space when doing 3d transforms in BasicCompositor. r=lsalzman (2d62616534) - Bug 1223736 - Part 3: Remove the distinction between 2d and 3d masks since it only adds complexity. r=Bas (61c2306875) - Bug 1137561 - Follow up VS2015 build error. r=masayuki (f12716a1ab) - Bug 1217275 Fix missing \n in IMMHandler::HandleDocumentFeed(), it was replaced to empty string accidentally r=m_kato (3315b1c270) - Bug 1243268 - Adjust ATOK workaround. r=masayuki (13af7184d1) - Bug 1242690 - If a drag block is interrupted by something else, have it create a new drag block when it resumes. r=rbarker (fe3dc8deac) - Bug 1242690 - Add untransforming of mouse events not in a drag block. r=rbarker (a39e715efe) - Bug 1241991 - Switch mTreeLock from a Monitor to a Mutex. r=kats (0eca284591) - Bug 1242690 - Further refine the mouse event untransformation code to only apply to events directed at a scrollbar. r=rbarker (5c92ca2807) - Bug 1251608 - Add a root-content annotation to the APZ test data structure. r=botond (a1ee8e496a) - Bug 1249748 - Ensure the mHandledByAPZ flag is set on WidgetTouchEvents that are handled by APZ. r=botond (11bdfae896) - Bug 1242690 - Don't apply the main-thread callback transform for events in a drag block. r=rbarker (3db1405b68) - Bug 1243589 - Use SingleTiledContentClient even for scrollable layers if the layer is smaller than a single tile. r=mattwoodrow (56bb664de1) - Bug 1250517 - Differentiate between no critical display port and empty critical display port in ClientTiledPaintedLayer; r=kats (1b809fac8e) - Bug 1255448 - Call ClientMultiTiledLayerBuffer::PaintThebes even when region to paint is empty. r=mattwoodrow (31ac878dc0) - Bug 1255907 - Fix unification build issues in APZ & Layers. r=kats (9829525402) - Bug 1256344 - If a long-press is interrupted by a non-touch block, don't dispatch the long-press event. r=botond (b3bdd0e58e) - Bug 1256341 - Guard against scenarios where GenerateSingleTap is called without an active touch block. r=botond (d4ec208407) - Bug 1230552 - Minor follow-up to add an assertion. rs=kats (6f9eec7bd4) - Bug 1247964 - Allow InputBlockState::SetScrolledApzc to accept new APZC when it is an ancestor of the current APZC r=kats # Please enter the commit message for your changes. Lines starting (08ce9cfa98) - Bug 1257264 - When apz.allow_immediate_handoff=false, APZ handoff should not occur when panning changes direction r=botond (6ec9ec22e6) - Bug 1250213 - Ensure the scroll offset does not go outside the page bounds when going full screen r=kats (ace8e8a80c) - Bug 1241332 - part 1, Request content repaint at end of APZ animation r=kats (74f7e249f2) - Bug 1255705 - Generalize the NotifyLayersUpdated short-circuit codepath to trigger on empty transactions as well. r=botond (0344d44844) - Bug 1250614 - Repeated zooming in bug on mobile Wikipedia site r=botond (459f02b8d3) - Bug 1251001 - Input fields at the bottom of a page do not pan into view when gaining focus. r=botond (770102bf9f) - Bug 1190093 (Comment Tweak) - Add better comments for nsIDocument::mIsShowing and mVisible. r=me DONTBUILD (e3822ef086) - Bug 1217226: P1. Use VideoInfo display size data rather than attempt to detect value in stream. r=cpearce (a4a7e9b19a) - Bug 1217226: P2. Implement WMFMediaDataDecoder::ConfigurationChanged. r=cpearce (52177525c5) - fix misspatch (61a694fe3d) - Bug 1249706: Added telemetry for the proportion of frames dropped keyed by several details. r=jya (cb459d971c) - Bug 1202296 - Recreate the MFTDecoder when we want to disable DXVA. r=cpearce (d82999e94f) - Bug 1176071 - Handle WMF MFTDecoder returning success but no output, with telemetry. r=mattwoodrow,r=vladan (da8017c92b) - align, cleanup (9a86d51dfd) - no bug - fix case of nsIDocShell.h in WindowsUIUtils.cpp (0ccabaa445) - Bug 1187724 Don't dispatch KeyboardEvents when the target of WM_APPCOMMAND is a windowed plug-in for preventing deadlock r=jimm (7b6d83559c) - Bug 1187178 - Use MOZ_WINSDK_MAXVER instead of #ifndef. r=jimm (06c949ddb9) - bits of Bug 1165515 - Part 13-2: Replace usage of PRLogModuleLevel (7beaa2dcc4) - Bug 1257791: Return correct DPI and printing scale from nsDeviceContextSpecWin when printing to PDF. r=jimm (87360301ea) - Bug 1242295 - Fix compile error in nsDeviceContextSpecWin. r=jimm (d1d4680319) - Bug 1229881 - fix off-by-one error in nsPrinterEnumeratorWin::GetPrinterNameList; r=dbaron; a=KWierso (439061ba50) - Bug 1239683 - Replace NS_UNCONSTRAINEDSIZE with NS_MAXSIZE in windows/nsWindow.cpp. r=mats (4135189bec) - Bug 1033488 - Send RTL information to child process by WM_INPUTLANGCHANGE. r=masayuki (eaf8f70d34) - Bug 1238137 - Telemetry pings for main thread touch scrolling (Windows only). r=kats (f2194a2965) - Bug 1156182 - Ensure nsWindow::Destroy() is called before destroying mPresentLock to avoid a race with the compositor thread. r=Bas (0452ffc641) - Bug 1173617. Don't cache titlebar caption sizes unless the widget has a titlebar. r=jimm (b29e190504) - Bug 580165 - Clean up dead code related to missing screen managers in widget. r=jimm (bf83f21ddc) - Bug 1256501: Fix warning C4312 with 64-bit VS2015 in widget/windows/nsWindow.cpp; r=jimm (635151964e) - Bug 1242690 - Squash together DispatchAPZAwareEvent and DispatchInputEvent. r=dvander (d7b4fea361) - Bug 1242616: Add break in nsWindow.cpp WM_GETOBJECT handling. r=tbsaunde (eb516d4119) - Bug 1239353 - Don't try to change DPI on the fly for popup windows, they remain connected to their parent's presShell and therefore need to share its resolution. r=emk (1491b84fd1) - Bug 1246389 - Resize window appropriately on WM_DPICHANGED messages for dynamic resolution changes. r=emk (f3dbfcdbb1) - Bug 1254019 - Don't attempt to resize a maximized window on DPI change; and when handling a DPI change, constrain the resized window to the screen bounds. r=emk (2047c2dcb5) - Bug 1252191 - use UniquePtr instead of ScopedFreePtr in PoisonIOInterposerMac.cpp; r=aklotz (7c26e55b76) - Bug 1233208: Disable IOInterposer on Beta and Release; r=froydnj (04a6f8b07c) - crashreporter (377572bbb1) - Bug 1055322 - The realloc for libnestegg should free with size 0. r=froydnj (ea624646ca) - Bug 1236789. Avoid creating an unnecessary thread pool thread for tail-dispatch in TaskQueue. r=bholley (e7fb9e4373) - Bug 1255655 - Const-ify named CIDs. r=froydnj. (03b414d92b) - Bug 1250396 (part 1) - Document a subtle contraint on nsIAtom. r=froydnj. (ff279149ac) - Bug 1250396 (part 2) - Remove nsStaticAtomStringType. r=froydnj. (5520507680) - Bug 1255343 - Stop returning nsresult from NS_RegisterStaticAtoms; r=ehsan (de1d387937) - Bug 1251495 - remove unnecessary Logging.h include from nsStaticAtom.h; r=erahm (5226a840fa)
This commit is contained in:
@@ -13535,6 +13535,11 @@ public:
|
||||
{
|
||||
nsAutoPopupStatePusher popupStatePusher(mPopupState);
|
||||
|
||||
// We need to set up an AutoJSAPI here for the following reason: When we do
|
||||
// OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
|
||||
// which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
|
||||
// So we need to fake things so that we don't look like native code as far
|
||||
// as LegacyIsCallerNativeCode() is concerned.
|
||||
AutoJSAPI jsapi;
|
||||
if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
|
||||
mHandler->OnLinkClickSync(mContent, mURI,
|
||||
|
||||
@@ -844,7 +844,7 @@ nsDOMWindowUtils::SendWheelEvent(float aX,
|
||||
|
||||
wheelEvent.refPoint = nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
|
||||
|
||||
widget->DispatchAPZAwareEvent(&wheelEvent);
|
||||
widget->DispatchInputEvent(&wheelEvent);
|
||||
|
||||
if (widget->AsyncPanZoomEnabled()) {
|
||||
// Computing overflow deltas is not compatible with APZ, so if APZ is
|
||||
@@ -2596,6 +2596,8 @@ nsDOMWindowUtils::ZoomToFocusedInput()
|
||||
uint32_t flags = layers::DISABLE_ZOOM_OUT;
|
||||
if (!Preferences::GetBool("formhelper.autozoom")) {
|
||||
flags |= layers::PAN_INTO_VIEW_ONLY;
|
||||
} else {
|
||||
flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE;
|
||||
}
|
||||
|
||||
CSSRect bounds = nsLayoutUtils::GetBoundingContentRect(content, rootScrollFrame);
|
||||
|
||||
+22
-2
@@ -1573,6 +1573,26 @@ nsDocument::~nsDocument()
|
||||
Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel);
|
||||
|
||||
Accumulate(Telemetry::SCROLL_LINKED_EFFECT_FOUND, mHasScrollLinkedEffect);
|
||||
|
||||
// record mixed object subrequest telemetry
|
||||
if (mHasMixedContentObjectSubrequest) {
|
||||
/* mixed object subrequest loaded on page*/
|
||||
Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1);
|
||||
} else {
|
||||
/* no mixed object subrequests loaded on page*/
|
||||
Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0);
|
||||
}
|
||||
|
||||
// record CSP telemetry on this document
|
||||
if (mHasCSP) {
|
||||
Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1);
|
||||
}
|
||||
if (mHasUnsafeInlineCSP) {
|
||||
Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
|
||||
}
|
||||
if (mHasUnsafeEvalCSP) {
|
||||
Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2311,7 +2331,7 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
|
||||
|
||||
void
|
||||
nsDocument::RemoveStyleSheetsFromStyleSets(
|
||||
nsTArray<StyleSheetHandle::RefPtr>& aSheets,
|
||||
const nsTArray<StyleSheetHandle::RefPtr>& aSheets,
|
||||
SheetType aType)
|
||||
{
|
||||
// The stylesheets should forget us
|
||||
@@ -4151,7 +4171,7 @@ nsDocument::GetStyleSheetAt(int32_t aIndex) const
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsDocument::GetIndexOfStyleSheet(StyleSheetHandle aSheet) const
|
||||
nsDocument::GetIndexOfStyleSheet(const StyleSheetHandle aSheet) const
|
||||
{
|
||||
return mStyleSheets.IndexOf(aSheet);
|
||||
}
|
||||
|
||||
@@ -777,7 +777,8 @@ public:
|
||||
*/
|
||||
virtual int32_t GetNumberOfStyleSheets() const override;
|
||||
virtual mozilla::StyleSheetHandle GetStyleSheetAt(int32_t aIndex) const override;
|
||||
virtual int32_t GetIndexOfStyleSheet(mozilla::StyleSheetHandle aSheet) const override;
|
||||
virtual int32_t GetIndexOfStyleSheet(
|
||||
const mozilla::StyleSheetHandle aSheet) const override;
|
||||
virtual void AddStyleSheet(mozilla::StyleSheetHandle aSheet) override;
|
||||
virtual void RemoveStyleSheet(mozilla::StyleSheetHandle aSheet) override;
|
||||
|
||||
@@ -1490,7 +1491,7 @@ protected:
|
||||
|
||||
void RemoveDocStyleSheetsFromStyleSets();
|
||||
void RemoveStyleSheetsFromStyleSets(
|
||||
nsTArray<mozilla::StyleSheetHandle::RefPtr>& aSheets,
|
||||
const nsTArray<mozilla::StyleSheetHandle::RefPtr>& aSheets,
|
||||
mozilla::SheetType aType);
|
||||
void ResetStylesheetsToURI(nsIURI* aURI);
|
||||
void FillStyleSet(mozilla::StyleSetHandle aStyleSet);
|
||||
|
||||
@@ -12069,6 +12069,10 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
}
|
||||
}
|
||||
|
||||
// XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
|
||||
// (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
|
||||
// But note that if you change this to GetEntryGlobal(), say, then
|
||||
// OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
|
||||
const bool checkForPopup = !nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
|
||||
!isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
|
||||
|
||||
|
||||
+57
-4
@@ -633,6 +633,38 @@ public:
|
||||
mHasMixedDisplayContentBlocked = aHasMixedDisplayContentBlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mixed content object subrequest flag for this document.
|
||||
*/
|
||||
void SetHasMixedContentObjectSubrequest(bool aHasMixedContentObjectSubrequest)
|
||||
{
|
||||
mHasMixedContentObjectSubrequest = aHasMixedContentObjectSubrequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CSP flag for this document.
|
||||
*/
|
||||
void SetHasCSP(bool aHasCSP)
|
||||
{
|
||||
mHasCSP = aHasCSP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unsafe-inline CSP flag for this document.
|
||||
*/
|
||||
void SetHasUnsafeInlineCSP(bool aHasUnsafeInlineCSP)
|
||||
{
|
||||
mHasUnsafeInlineCSP = aHasUnsafeInlineCSP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set unsafe-eval CSP flag for this document.
|
||||
*/
|
||||
void SetHasUnsafeEvalCSP(bool aHasUnsafeEvalCSP)
|
||||
{
|
||||
mHasUnsafeEvalCSP = aHasUnsafeEvalCSP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tracking content blocked flag for this document.
|
||||
*/
|
||||
@@ -979,7 +1011,8 @@ public:
|
||||
* @param aSheet the sheet to get the index of
|
||||
* @return aIndex the index of the sheet in the full list
|
||||
*/
|
||||
virtual int32_t GetIndexOfStyleSheet(mozilla::StyleSheetHandle aSheet) const = 0;
|
||||
virtual int32_t GetIndexOfStyleSheet(
|
||||
const mozilla::StyleSheetHandle aSheet) const = 0;
|
||||
|
||||
/**
|
||||
* Replace the stylesheets in aOldSheets with the stylesheets in
|
||||
@@ -2742,6 +2775,10 @@ public:
|
||||
bool InlineScriptAllowedByCSP();
|
||||
|
||||
void ReportHasScrollLinkedEffect();
|
||||
bool HasScrollLinkedEffect() const
|
||||
{
|
||||
return mHasScrollLinkedEffect;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
@@ -2907,11 +2944,15 @@ protected:
|
||||
// True iff we've ever fired a DOMTitleChanged event for this document
|
||||
bool mHaveFiredTitleChange : 1;
|
||||
|
||||
// True iff IsShowing() should be returning true
|
||||
// State for IsShowing(). mIsShowing starts off false. It becomes true when
|
||||
// OnPageShow happens and becomes false when OnPageHide happens. So it's false
|
||||
// before the initial load completes and when we're in bfcache or unloaded,
|
||||
// true otherwise.
|
||||
bool mIsShowing : 1;
|
||||
|
||||
// True iff the document "page" is not hidden (i.e. currently in the
|
||||
// bfcache)
|
||||
// State for IsVisible(). mVisible starts off true. It becomes false when
|
||||
// OnPageHide happens, and becomes true again when OnPageShow happens. So
|
||||
// it's false only when we're in bfcache or unloaded.
|
||||
bool mVisible : 1;
|
||||
|
||||
// True if our content viewer has been removed from the docshell
|
||||
@@ -2969,6 +3010,18 @@ protected:
|
||||
// True if a document has blocked Mixed Display/Passive Content (see nsMixedContentBlocker.cpp)
|
||||
bool mHasMixedDisplayContentBlocked : 1;
|
||||
|
||||
// True if a document loads a plugin object that attempts to load mixed content subresources through necko(see nsMixedContentBlocker.cpp)
|
||||
bool mHasMixedContentObjectSubrequest : 1;
|
||||
|
||||
// True if a document load has a CSP attached.
|
||||
bool mHasCSP : 1;
|
||||
|
||||
// True if a document load has a CSP with unsafe-eval attached.
|
||||
bool mHasUnsafeEvalCSP : 1;
|
||||
|
||||
// True if a document load has a CSP with unsafe-inline attached.
|
||||
bool mHasUnsafeInlineCSP : 1;
|
||||
|
||||
// True if a document has blocked Tracking Content
|
||||
bool mHasTrackingContentBlocked : 1;
|
||||
|
||||
|
||||
@@ -1341,7 +1341,7 @@ bool TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
|
||||
localEvent.widget = widget;
|
||||
localEvent.refPoint -= GetChildProcessOffset();
|
||||
|
||||
widget->DispatchAPZAwareEvent(&localEvent);
|
||||
widget->DispatchInputEvent(&localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,10 @@ MediaFormatReader::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (HasVideo()) {
|
||||
ReportDroppedFramesTelemetry();
|
||||
}
|
||||
|
||||
mDemuxerInitRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
@@ -667,6 +671,7 @@ MediaFormatReader::NotifyNewOutput(TrackType aTrack, MediaData* aSample)
|
||||
decoder.mOutput.AppendElement(aSample);
|
||||
decoder.mNumSamplesOutput++;
|
||||
decoder.mNumSamplesOutputTotal++;
|
||||
decoder.mNumSamplesOutputTotalSinceTelemetry++;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
@@ -910,6 +915,9 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
|
||||
LOG("%s stream id has changed from:%d to:%d, draining decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
if (aTrack == TrackType::kVideoTrack) {
|
||||
ReportDroppedFramesTelemetry();
|
||||
}
|
||||
decoder.mNeedDraining = true;
|
||||
decoder.mNextStreamSourceID = Some(info->GetID());
|
||||
ScheduleUpdate(aTrack);
|
||||
@@ -1371,6 +1379,7 @@ MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped)
|
||||
mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped);
|
||||
}
|
||||
mVideo.mNumSamplesSkippedTotal += aSkipped;
|
||||
mVideo.mNumSamplesSkippedTotalSinceTelemetry += aSkipped;
|
||||
MOZ_ASSERT(!mVideo.mError); // We have flushed the decoder, no frame could
|
||||
// have been decoded (and as such errored)
|
||||
NotifyDecodingRequested(TrackInfo::kVideoTrack);
|
||||
@@ -1700,4 +1709,51 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString)
|
||||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::ReportDroppedFramesTelemetry()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
const VideoInfo* info =
|
||||
mVideo.mInfo ? mVideo.mInfo->GetAsVideoInfo() : &mInfo.mVideo;
|
||||
|
||||
if (!info || !mVideo.mDecoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString keyPhrase = nsCString("MimeType=");
|
||||
keyPhrase.Append(info->mMimeType);
|
||||
keyPhrase.Append("; ");
|
||||
|
||||
keyPhrase.Append("Resolution=");
|
||||
keyPhrase.AppendInt(info->mDisplay.width);
|
||||
keyPhrase.Append('x');
|
||||
keyPhrase.AppendInt(info->mDisplay.height);
|
||||
keyPhrase.Append("; ");
|
||||
|
||||
keyPhrase.Append("HardwareAcceleration=");
|
||||
if (VideoIsHardwareAccelerated()) {
|
||||
keyPhrase.Append(mVideo.mDecoder->GetDescriptionName());
|
||||
keyPhrase.Append("enabled");
|
||||
} else {
|
||||
keyPhrase.Append("disabled");
|
||||
}
|
||||
|
||||
if (mVideo.mNumSamplesOutputTotalSinceTelemetry) {
|
||||
uint32_t percentage =
|
||||
100 * mVideo.mNumSamplesSkippedTotalSinceTelemetry /
|
||||
mVideo.mNumSamplesOutputTotalSinceTelemetry;
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
|
||||
LOG("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK");
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DETAILED_DROPPED_FRAMES_PROPORTION,
|
||||
keyPhrase,
|
||||
percentage);
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
mVideo.mNumSamplesSkippedTotalSinceTelemetry = 0;
|
||||
mVideo.mNumSamplesOutputTotalSinceTelemetry = 0;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -234,6 +234,8 @@ private:
|
||||
, mNumSamplesOutput(0)
|
||||
, mNumSamplesOutputTotal(0)
|
||||
, mNumSamplesSkippedTotal(0)
|
||||
, mNumSamplesOutputTotalSinceTelemetry(0)
|
||||
, mNumSamplesSkippedTotalSinceTelemetry(0)
|
||||
, mSizeOfQueue(0)
|
||||
, mIsHardwareAccelerated(false)
|
||||
, mLastStreamSourceID(UINT32_MAX)
|
||||
@@ -312,6 +314,9 @@ private:
|
||||
uint64_t mNumSamplesOutputTotal;
|
||||
uint64_t mNumSamplesSkippedTotal;
|
||||
|
||||
uint64_t mNumSamplesOutputTotalSinceTelemetry;
|
||||
uint64_t mNumSamplesSkippedTotalSinceTelemetry;
|
||||
|
||||
// These get overriden in the templated concrete class.
|
||||
// Indicate if we have a pending promise for decoded frame.
|
||||
// Rejecting the promise will stop the reader from decoding ahead.
|
||||
@@ -465,6 +470,9 @@ private:
|
||||
{
|
||||
OnSeekFailed(TrackType::kAudioTrack, aFailure);
|
||||
}
|
||||
|
||||
void ReportDroppedFramesTelemetry();
|
||||
|
||||
// Temporary seek information while we wait for the data
|
||||
Maybe<SeekTarget> mOriginalSeekTarget;
|
||||
Maybe<media::TimeUnit> mPendingSeekTime;
|
||||
|
||||
@@ -236,7 +236,9 @@ MFTDecoder::Output(RefPtr<IMFSample>* aOutput)
|
||||
// Treat other errors as unexpected, and warn.
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
MOZ_ASSERT(output.pSample);
|
||||
if (!output.pSample) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (mDiscontinuity) {
|
||||
output.pSample->SetUINT32(MFSampleExtension_Discontinuity, TRUE);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "WMFUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
extern mozilla::LogModule* GetPDMLog();
|
||||
@@ -226,6 +226,16 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset,
|
||||
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
if (!sample) {
|
||||
LOG("Audio MFTDecoder returned success but null output.");
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([]() -> void {
|
||||
LOG("Reporting telemetry AUDIO_MFT_OUTPUT_NULL_SAMPLES");
|
||||
Telemetry::Accumulate(Telemetry::ID::AUDIO_MFT_OUTPUT_NULL_SAMPLES, 1);
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(task.forget());
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
RefPtr<IMFMediaBuffer> buffer;
|
||||
hr = sample->ConvertToContiguousBuffer(getter_AddRefs(buffer));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
@@ -198,4 +198,27 @@ WMFMediaDataDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const {
|
||||
return mMFTManager && mMFTManager->IsHardwareAccelerated(aFailureReason);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFMediaDataDecoder::ConfigurationChanged(const TrackInfo& aConfig)
|
||||
{
|
||||
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethodWithArg<UniquePtr<TrackInfo>&&>(
|
||||
this,
|
||||
&WMFMediaDataDecoder::ProcessConfigurationChanged,
|
||||
aConfig.Clone());
|
||||
mTaskQueue->Dispatch(runnable.forget());
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
WMFMediaDataDecoder::ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig)
|
||||
{
|
||||
if (mMFTManager) {
|
||||
mMFTManager->ConfigurationChanged(*aConfig);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -52,6 +52,8 @@ public:
|
||||
|
||||
virtual TrackInfo::TrackType GetType() = 0;
|
||||
|
||||
virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
|
||||
|
||||
virtual const char* GetDescriptionName() const = 0;
|
||||
|
||||
protected:
|
||||
@@ -83,6 +85,8 @@ public:
|
||||
|
||||
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
|
||||
|
||||
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
|
||||
|
||||
const char* GetDescriptionName() const override
|
||||
{
|
||||
return mMFTManager ? mMFTManager->GetDescriptionName() : "";
|
||||
@@ -108,6 +112,10 @@ private:
|
||||
|
||||
void ProcessShutdown();
|
||||
|
||||
// Called on the task queue. Tell the MFT that the next Input will have a
|
||||
// different configuration (typically resolution change).
|
||||
void ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig);
|
||||
|
||||
RefPtr<FlushableTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride)
|
||||
{
|
||||
// Try to get the default stride from the media type.
|
||||
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
|
||||
@@ -49,16 +49,11 @@ GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
||||
|
||||
// Stride attribute not set, calculate it.
|
||||
GUID subtype = GUID_NULL;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
|
||||
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
|
||||
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, aWidth, (LONG*)(aOutStride));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
return hr;
|
||||
@@ -188,7 +183,7 @@ LoadDLLs()
|
||||
#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
|
||||
static FunctionType FunctionName##Ptr = nullptr; \
|
||||
if (!FunctionName##Ptr) { \
|
||||
FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L#DLL), #FunctionName); \
|
||||
FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L ## #DLL), #FunctionName); \
|
||||
if (!FunctionName##Ptr) { \
|
||||
NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
|
||||
return E_FAIL; \
|
||||
@@ -282,7 +277,6 @@ MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
|
||||
HRESULT
|
||||
MFCreateDXGIDeviceManager(UINT *pResetToken, IMFDXGIDeviceManager **ppDXVAManager)
|
||||
{
|
||||
DECL_FUNCTION_PTR(MFCreateDXGIDeviceManager, UINT*, IMFDXGIDeviceManager**);
|
||||
ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
|
||||
return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ HRESULT
|
||||
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames);
|
||||
|
||||
HRESULT
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride);
|
||||
GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride);
|
||||
|
||||
int32_t
|
||||
MFOffsetToInt32(const MFOffset& aOffset);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "IMFYCbCrImage.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
extern mozilla::LogModule* GetPDMLog();
|
||||
@@ -70,9 +71,14 @@ WMFVideoMFTManager::WMFVideoMFTManager(
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
bool aDXVAEnabled)
|
||||
: mImageContainer(aImageContainer)
|
||||
: mVideoInfo(aConfig)
|
||||
, mVideoStride(0)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mDXVAEnabled(aDXVAEnabled)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mNullOutputCount(0)
|
||||
, mGotValidOutputAfterNullOutput(false)
|
||||
, mGotExcessiveNullOutput(false)
|
||||
// mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
|
||||
// Init().
|
||||
{
|
||||
@@ -98,6 +104,20 @@ WMFVideoMFTManager::~WMFVideoMFTManager()
|
||||
if (mDXVA2Manager) {
|
||||
DeleteOnMainThread(mDXVA2Manager);
|
||||
}
|
||||
|
||||
// Record whether the video decoder successfully decoded, or output null
|
||||
// samples but did/didn't recover.
|
||||
uint32_t telemetry = (mNullOutputCount == 0) ? 0 :
|
||||
(mGotValidOutputAfterNullOutput && mGotExcessiveNullOutput) ? 1 :
|
||||
mGotExcessiveNullOutput ? 2 :
|
||||
mGotValidOutputAfterNullOutput ? 3 :
|
||||
4;
|
||||
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() -> void {
|
||||
LOG(nsPrintfCString("Reporting telemetry VIDEO_MFT_OUTPUT_NULL_SAMPLES=%d", telemetry).get());
|
||||
Telemetry::Accumulate(Telemetry::ID::VIDEO_MFT_OUTPUT_NULL_SAMPLES, telemetry);
|
||||
});
|
||||
AbstractThread::MainThread()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
const GUID&
|
||||
@@ -150,8 +170,6 @@ public:
|
||||
bool
|
||||
WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9)
|
||||
{
|
||||
MOZ_ASSERT(!mDXVA2Manager);
|
||||
|
||||
// If we use DXVA but aren't running with a D3D layer manager then the
|
||||
// readback of decoded video frames from GPU to CPU memory grinds painting
|
||||
// to a halt, and makes playback performance *worse*.
|
||||
@@ -159,6 +177,7 @@ WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9)
|
||||
mDXVAFailureReason.AssignLiteral("Hardware video decoding disabled or blacklisted");
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!mDXVA2Manager);
|
||||
if (mLayersBackend != LayersBackend::LAYERS_D3D9 &&
|
||||
mLayersBackend != LayersBackend::LAYERS_D3D11) {
|
||||
mDXVAFailureReason.AssignLiteral("Unsupported layers backend");
|
||||
@@ -250,13 +269,6 @@ WMFVideoMFTManager::InitInternal(bool aForceD3D9)
|
||||
|
||||
LOG("Video Decoder initialized, Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
|
||||
|
||||
// Just in case ConfigureVideoFrameGeometry() does not set these
|
||||
mVideoInfo = VideoInfo();
|
||||
mVideoStride = 0;
|
||||
mVideoWidth = 0;
|
||||
mVideoHeight = 0;
|
||||
mPictureRegion.SetEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -323,36 +335,19 @@ WMFVideoMFTManager::Input(MediaRawData* aSample)
|
||||
// This code tests if the given resolution can be supported directly on the GPU,
|
||||
// and makes sure we only ask the MFT for DXVA if it can be supported properly.
|
||||
bool
|
||||
WMFVideoMFTManager::MaybeToggleDXVA(IMFMediaType* aType)
|
||||
WMFVideoMFTManager::CanUseDXVA(IMFMediaType* aType)
|
||||
{
|
||||
MOZ_ASSERT(mDXVA2Manager);
|
||||
// SupportsConfig only checks for valid h264 decoders currently.
|
||||
if (!mDXVA2Manager || mStreamType != H264) {
|
||||
return false;
|
||||
if (mStreamType != H264) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Assume the current samples duration is representative for the
|
||||
// entire video.
|
||||
float framerate = 1000000.0 / mLastDuration;
|
||||
|
||||
if (mDXVA2Manager->SupportsConfig(aType, framerate)) {
|
||||
if (!mUseHwAccel) {
|
||||
// DXVA disabled, but supported for this resolution
|
||||
ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager());
|
||||
HRESULT hr = mDecoder->SendMFTMessage(MFT_MESSAGE_SET_D3D_MANAGER, manager);
|
||||
if (SUCCEEDED(hr)) {
|
||||
mUseHwAccel = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (mUseHwAccel) {
|
||||
// DXVA enabled, and not supported for this resolution
|
||||
HRESULT hr = mDecoder->SendMFTMessage(MFT_MESSAGE_SET_D3D_MANAGER, 0);
|
||||
MOZ_ASSERT(SUCCEEDED(hr), "Attempting to fall back to software failed?");
|
||||
mUseHwAccel = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return mDXVA2Manager->SupportsConfig(aType, framerate);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
@@ -366,14 +361,14 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry()
|
||||
// change then we need to renegotiate our media types,
|
||||
// and resubmit our previous frame (since the MFT appears
|
||||
// to lose it otherwise).
|
||||
if (MaybeToggleDXVA(mediaType)) {
|
||||
hr = SetDecoderMediaTypes();
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
HRESULT hr = mDecoder->GetOutputMediaType(mediaType);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
if (mUseHwAccel && !CanUseDXVA(mediaType)) {
|
||||
mDXVAEnabled = false;
|
||||
if (!Init()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
mDecoder->Input(mLastInput);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Verify that the video subtype is what we expect it to be.
|
||||
@@ -387,26 +382,17 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry()
|
||||
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL);
|
||||
NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL);
|
||||
|
||||
nsIntRect pictureRegion;
|
||||
hr = GetPictureRegion(mediaType, pictureRegion);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
uint32_t aspectNum = 0, aspectDenom = 0;
|
||||
hr = MFGetAttributeRatio(mediaType,
|
||||
MF_MT_PIXEL_ASPECT_RATIO,
|
||||
&aspectNum,
|
||||
&aspectDenom);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
mVideoInfo.mImage.width = width;
|
||||
mVideoInfo.mImage.height = height;
|
||||
nsIntRect pictureRegion = mVideoInfo.mImage;
|
||||
// Calculate and validate the picture region and frame dimensions after
|
||||
// scaling by the pixel aspect ratio.
|
||||
nsIntSize frameSize = nsIntSize(width, height);
|
||||
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
|
||||
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
|
||||
nsIntSize displaySize = nsIntSize(mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
|
||||
if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
|
||||
// Video track's frame sizes will overflow. Ignore the video track.
|
||||
return E_FAIL;
|
||||
@@ -418,18 +404,13 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry()
|
||||
}
|
||||
|
||||
// Success! Save state.
|
||||
mVideoInfo.mDisplay = displaySize;
|
||||
GetDefaultStride(mediaType, &mVideoStride);
|
||||
mVideoWidth = width;
|
||||
mVideoHeight = height;
|
||||
mPictureRegion = pictureRegion;
|
||||
GetDefaultStride(mediaType, width, &mVideoStride);
|
||||
|
||||
LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
|
||||
LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d)",
|
||||
width, height,
|
||||
mVideoStride,
|
||||
mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
|
||||
displaySize.width, displaySize.height,
|
||||
aspectNum, aspectDenom);
|
||||
pictureRegion.x, pictureRegion.y, pictureRegion.width, pictureRegion.height,
|
||||
mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -471,25 +452,28 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
// i.e., Y, then V, then U.
|
||||
VideoData::YCbCrBuffer b;
|
||||
|
||||
uint32_t videoWidth = mVideoInfo.mImage.width;
|
||||
uint32_t videoHeight = mVideoInfo.mImage.height;
|
||||
|
||||
// Y (Y') plane
|
||||
b.mPlanes[0].mData = data;
|
||||
b.mPlanes[0].mStride = stride;
|
||||
b.mPlanes[0].mHeight = mVideoHeight;
|
||||
b.mPlanes[0].mWidth = mVideoWidth;
|
||||
b.mPlanes[0].mHeight = videoHeight;
|
||||
b.mPlanes[0].mWidth = videoWidth;
|
||||
b.mPlanes[0].mOffset = 0;
|
||||
b.mPlanes[0].mSkip = 0;
|
||||
|
||||
// The V and U planes are stored 16-row-aligned, so we need to add padding
|
||||
// to the row heights to ensure the Y'CbCr planes are referenced properly.
|
||||
uint32_t padding = 0;
|
||||
if (mVideoHeight % 16 != 0) {
|
||||
padding = 16 - (mVideoHeight % 16);
|
||||
if (videoHeight % 16 != 0) {
|
||||
padding = 16 - (videoHeight % 16);
|
||||
}
|
||||
uint32_t y_size = stride * (mVideoHeight + padding);
|
||||
uint32_t v_size = stride * (mVideoHeight + padding) / 4;
|
||||
uint32_t y_size = stride * (videoHeight + padding);
|
||||
uint32_t v_size = stride * (videoHeight + padding) / 4;
|
||||
uint32_t halfStride = (stride + 1) / 2;
|
||||
uint32_t halfHeight = (mVideoHeight + 1) / 2;
|
||||
uint32_t halfWidth = (mVideoWidth + 1) / 2;
|
||||
uint32_t halfHeight = (videoHeight + 1) / 2;
|
||||
uint32_t halfWidth = (videoWidth + 1) / 2;
|
||||
|
||||
// U plane (Cb)
|
||||
b.mPlanes[1].mData = data + y_size + v_size;
|
||||
@@ -518,7 +502,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
VideoData::SetVideoDataToImage(image,
|
||||
mVideoInfo,
|
||||
b,
|
||||
mPictureRegion,
|
||||
mVideoInfo.mImage,
|
||||
false);
|
||||
|
||||
RefPtr<VideoData> v =
|
||||
@@ -530,7 +514,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
image.forget(),
|
||||
false,
|
||||
-1,
|
||||
mPictureRegion);
|
||||
mVideoInfo.mImage);
|
||||
|
||||
v.forget(aOutVideoData);
|
||||
return S_OK;
|
||||
@@ -551,7 +535,7 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
|
||||
|
||||
RefPtr<Image> image;
|
||||
hr = mDXVA2Manager->CopyToImage(aSample,
|
||||
mPictureRegion,
|
||||
mVideoInfo.mImage,
|
||||
mImageContainer,
|
||||
getter_AddRefs(image));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
@@ -569,7 +553,7 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
|
||||
image.forget(),
|
||||
false,
|
||||
-1,
|
||||
mPictureRegion);
|
||||
mVideoInfo.mImage);
|
||||
|
||||
NS_ENSURE_TRUE(v, E_FAIL);
|
||||
v.forget(aOutVideoData);
|
||||
@@ -610,6 +594,23 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
||||
continue;
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (!sample) {
|
||||
LOG("Video MFTDecoder returned success but no output!");
|
||||
// On some machines/input the MFT returns success but doesn't output
|
||||
// a video frame. If we detect this, try again, but only up to a
|
||||
// point; after 250 failures, give up. Note we count all failures
|
||||
// over the life of the decoder, as we may end up exiting with a
|
||||
// NEED_MORE_INPUT and coming back to hit the same error. So just
|
||||
// counting with a local variable (like typeChangeCount does) may
|
||||
// not work in this situation.
|
||||
++mNullOutputCount;
|
||||
if (mNullOutputCount > 250) {
|
||||
LOG("Excessive Video MFTDecoder returning success but no output; giving up");
|
||||
mGotExcessiveNullOutput = true;
|
||||
return E_FAIL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Else unexpected error, assert, and bail.
|
||||
@@ -630,6 +631,10 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
||||
|
||||
aOutData = frame;
|
||||
|
||||
if (mNullOutputCount) {
|
||||
mGotValidOutputAfterNullOutput = true;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -647,4 +652,22 @@ WMFVideoMFTManager::IsHardwareAccelerated(nsACString& aFailureReason) const
|
||||
return mDecoder && mUseHwAccel;
|
||||
}
|
||||
|
||||
const char*
|
||||
WMFVideoMFTManager::GetDescriptionName() const
|
||||
{
|
||||
if (mDecoder && mUseHwAccel && mDXVA2Manager) {
|
||||
return (mDXVA2Manager->IsD3D11()) ?
|
||||
"D3D11 Hardware Decoder" : "D3D9 Hardware Decoder";
|
||||
} else {
|
||||
return "wmf software video decoder";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
|
||||
{
|
||||
MOZ_ASSERT(aConfig.GetAsVideoInfo());
|
||||
mVideoInfo = *aConfig.GetAsVideoInfo();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -39,12 +39,9 @@ public:
|
||||
return TrackInfo::kVideoTrack;
|
||||
}
|
||||
|
||||
const char* GetDescriptionName() const override
|
||||
{
|
||||
nsCString failureReason;
|
||||
return IsHardwareAccelerated(failureReason)
|
||||
? "wmf hardware video decoder" : "wmf software video decoder";
|
||||
}
|
||||
void ConfigurationChanged(const TrackInfo& aConfig) override;
|
||||
|
||||
const char* GetDescriptionName() const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -64,14 +61,11 @@ private:
|
||||
|
||||
HRESULT SetDecoderMediaTypes();
|
||||
|
||||
bool MaybeToggleDXVA(IMFMediaType* aType);
|
||||
bool CanUseDXVA(IMFMediaType* aType);
|
||||
|
||||
// Video frame geometry.
|
||||
VideoInfo mVideoInfo;
|
||||
uint32_t mVideoStride;
|
||||
uint32_t mVideoWidth;
|
||||
uint32_t mVideoHeight;
|
||||
nsIntRect mPictureRegion;
|
||||
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||
@@ -79,7 +73,7 @@ private:
|
||||
RefPtr<IMFSample> mLastInput;
|
||||
float mLastDuration;
|
||||
|
||||
const bool mDXVAEnabled;
|
||||
bool mDXVAEnabled;
|
||||
const layers::LayersBackend mLayersBackend;
|
||||
bool mUseHwAccel;
|
||||
|
||||
@@ -96,6 +90,10 @@ private:
|
||||
|
||||
const GUID& GetMFTGUID();
|
||||
const GUID& GetMediaSubtypeGUID();
|
||||
|
||||
uint32_t mNullOutputCount;
|
||||
bool mGotValidOutputAfterNullOutput;
|
||||
bool mGotExcessiveNullOutput;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -122,9 +122,6 @@ TCPServerSocket::Close()
|
||||
void
|
||||
TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket)
|
||||
{
|
||||
AutoJSAPI api;
|
||||
api.Init(GetOwnerGlobal());
|
||||
|
||||
TCPServerSocketEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
|
||||
@@ -626,6 +626,9 @@ nsCSPContext::SetRequestContext(nsIDOMDocument* aDOMDocument,
|
||||
// console messages until it becomes available, see flushConsoleMessages
|
||||
mQueueUpMessages = !mInnerWindowID;
|
||||
mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
|
||||
|
||||
// set the flag on the document for CSP telemetry
|
||||
doc->SetHasCSP(true);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
|
||||
|
||||
@@ -81,6 +81,10 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
mLoadingPrincipal = nullptr;
|
||||
}
|
||||
|
||||
nsWeakPtr GetLoadingContext(){
|
||||
return mLoadingContext;
|
||||
}
|
||||
|
||||
private:
|
||||
bool permitsInternal(CSPDirective aDir,
|
||||
nsIURI* aContentLocation,
|
||||
|
||||
@@ -578,6 +578,10 @@ nsCSPParser::keywordSource()
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) {
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mCSPContext->GetLoadingContext());
|
||||
if (doc) {
|
||||
doc->SetHasUnsafeInlineCSP(true);
|
||||
}
|
||||
// make sure script-src only contains 'unsafe-inline' once;
|
||||
// ignore duplicates and log warning
|
||||
if (mUnsafeInlineKeywordSrc) {
|
||||
@@ -593,6 +597,10 @@ nsCSPParser::keywordSource()
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_EVAL)) {
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mCSPContext->GetLoadingContext());
|
||||
if (doc) {
|
||||
doc->SetHasUnsafeEvalCSP(true);
|
||||
}
|
||||
return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
@@ -799,6 +799,11 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
}
|
||||
}
|
||||
|
||||
// set hasMixedContentObjectSubrequest on this object if necessary
|
||||
if (aContentType == TYPE_OBJECT_SUBREQUEST) {
|
||||
rootDoc->SetHasMixedContentObjectSubrequest(true);
|
||||
}
|
||||
|
||||
// If the content is display content, and the pref says display content should be blocked, block it.
|
||||
if (sBlockMixedDisplay && classification == eMixedDisplay) {
|
||||
if (allowMixedContent) {
|
||||
|
||||
@@ -37,5 +37,6 @@ if CONFIG['MOZ_XUL']:
|
||||
FINAL_LIBRARY = 'xul'
|
||||
# For nsJSUtils
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "nsJSUtils.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "nsDocShell.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
@@ -81,6 +82,7 @@ struct nsWatcherWindowEntry
|
||||
{
|
||||
|
||||
nsWatcherWindowEntry(nsIDOMWindow* aWindow, nsIWebBrowserChrome* aChrome)
|
||||
: mChrome(nullptr)
|
||||
{
|
||||
#ifdef USEWEAKREFS
|
||||
mWindow = do_GetWeakReference(aWindow);
|
||||
@@ -451,6 +453,36 @@ nsWindowWatcher::OpenWindow2(nsIDOMWindow* aParent,
|
||||
aResult);
|
||||
}
|
||||
|
||||
// This static function checks if the aDocShell uses an UserContextId equal to
|
||||
// nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID or equal to the
|
||||
// userContextId of subjectPrincipal, if not null.
|
||||
static bool
|
||||
CheckUserContextCompatibility(nsIDocShell* aDocShell)
|
||||
{
|
||||
MOZ_ASSERT(aDocShell);
|
||||
|
||||
uint32_t userContextId =
|
||||
static_cast<nsDocShell*>(aDocShell)->GetOriginAttributes().mUserContextId;
|
||||
|
||||
if (userContextId == nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> subjectPrincipal =
|
||||
nsContentUtils::GetCurrentJSContext()
|
||||
? nsContentUtils::SubjectPrincipal() : nullptr;
|
||||
|
||||
if (!subjectPrincipal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t principalUserContextId;
|
||||
nsresult rv = subjectPrincipal->GetUserContextId(&principalUserContextId);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return principalUserContextId == userContextId;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
|
||||
const char* aUrl,
|
||||
@@ -606,6 +638,9 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
|
||||
bool isCallerChrome =
|
||||
nsContentUtils::LegacyIsCallerChromeOrNativeCode() && !openedFromRemoteTab;
|
||||
|
||||
// XXXbz Why is an AutoJSAPI good enough here? Wouldn't AutoEntryScript (so
|
||||
// we affect the entry global) make more sense? Or do we just want to affect
|
||||
// GetSubjectPrincipal()?
|
||||
dom::AutoJSAPI jsapiChromeGuard;
|
||||
|
||||
bool windowTypeIsChrome =
|
||||
@@ -692,6 +727,19 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
|
||||
do_QueryInterface(newDocShellItem);
|
||||
webNav->Stop(nsIWebNavigation::STOP_NETWORK);
|
||||
}
|
||||
|
||||
// If this is a new window, but it's incompatible with the current
|
||||
// userContextId, we ignore it and we pretend that nothing has been
|
||||
// returned by ProvideWindow.
|
||||
if (!windowIsNew && newDocShellItem) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(newDocShellItem);
|
||||
if (!CheckUserContextCompatibility(docShell)) {
|
||||
newWindow = nullptr;
|
||||
newDocShellItem = nullptr;
|
||||
windowIsNew = false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (rv == NS_ERROR_ABORT) {
|
||||
// NS_ERROR_ABORT means the window provider has flat-out rejected
|
||||
// the open-window call and we should bail. Don't return an error
|
||||
@@ -983,6 +1031,18 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a new window, we must set the userContextId from the
|
||||
// subjectPrincipal.
|
||||
if (windowIsNew && subjectPrincipal) {
|
||||
uint32_t userContextId;
|
||||
rv = subjectPrincipal->GetUserContextId(&userContextId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
auto* docShell = static_cast<nsDocShell*>(newDocShell.get());
|
||||
|
||||
docShell->SetUserContextId(userContextId);
|
||||
}
|
||||
|
||||
if (isNewToplevelWindow) {
|
||||
// Notify observers that the window is open and ready.
|
||||
// The window has not yet started to load a document.
|
||||
@@ -993,6 +1053,10 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
// Before loading the URI we want to be 100% sure that we use the correct
|
||||
// userContextId.
|
||||
MOZ_ASSERT(CheckUserContextCompatibility(newDocShell));
|
||||
|
||||
if (uriToLoad && aNavigate) {
|
||||
newDocShell->LoadURI(
|
||||
uriToLoad,
|
||||
@@ -1628,7 +1692,7 @@ nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
if (aDialog && !presenceFlag) {
|
||||
if (aDialog && aFeaturesSpecified && !presenceFlag) {
|
||||
chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
|
||||
}
|
||||
|
||||
@@ -2140,8 +2204,14 @@ nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
|
||||
int32_t winWidth = width + (sizeChromeWidth ? 0 : chromeWidth),
|
||||
winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
|
||||
|
||||
screen->GetAvailRectDisplayPix(&screenLeft, &screenTop, &screenWidth,
|
||||
&screenHeight);
|
||||
// Get screen dimensions (in device pixels)
|
||||
screen->GetAvailRect(&screenLeft, &screenTop, &screenWidth,
|
||||
&screenHeight);
|
||||
// Convert them to CSS pixels
|
||||
screenLeft = NSToIntRound(screenLeft / scale);
|
||||
screenTop = NSToIntRound(screenTop / scale);
|
||||
screenWidth = NSToIntRound(screenWidth / scale);
|
||||
screenHeight = NSToIntRound(screenHeight / scale);
|
||||
|
||||
if (aSizeSpec.SizeSpecified()) {
|
||||
/* Unlike position, force size out-of-bounds check only if
|
||||
|
||||
@@ -2083,6 +2083,7 @@ _cairo_surface_paint (cairo_surface_t *surface,
|
||||
cairo_clip_t *clip)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
if (unlikely (surface->status))
|
||||
return surface->status;
|
||||
@@ -2114,7 +2115,10 @@ _cairo_surface_paint (cairo_surface_t *surface,
|
||||
status = _cairo_surface_fallback_paint (surface, op, source, clip);
|
||||
|
||||
FINISH:
|
||||
surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
|
||||
surface->is_clear = op == CAIRO_OPERATOR_CLEAR &&
|
||||
(clip == NULL ||
|
||||
(_cairo_surface_get_extents (surface, &extents) &&
|
||||
_cairo_clip_contains_rectangle (clip, &extents)));
|
||||
|
||||
return _cairo_surface_set_error (surface, status);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Units.h" // for ScreenPoint
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
|
||||
#include "mozilla/gfx/Point.h" // for IntSize, Point
|
||||
#include "mozilla/gfx/Rect.h" // for Rect, IntRect
|
||||
@@ -363,10 +364,14 @@ public:
|
||||
* If aRenderBoundsOut is non-null, it will be set to the render bounds
|
||||
* actually used by the compositor in window space. If aRenderBoundsOut
|
||||
* is returned empty, composition should be aborted.
|
||||
*
|
||||
* If aOpaque is true, then all of aInvalidRegion will be drawn to with
|
||||
* opaque content.
|
||||
*/
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect* aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect* aClipRectOut = nullptr,
|
||||
gfx::Rect* aRenderBoundsOut = nullptr) = 0;
|
||||
|
||||
|
||||
@@ -230,8 +230,7 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OpenMode)
|
||||
// We rely on the items in this enum being sequential
|
||||
enum class MaskType : uint8_t {
|
||||
MaskNone = 0, // no mask layer
|
||||
Mask2d, // mask layer for layers with 2D transforms
|
||||
Mask3d, // mask layer for layers with 3D transforms
|
||||
Mask, // mask layer
|
||||
NumMaskTypes
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/PersistentBufferProvider.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
||||
|
||||
@@ -34,10 +34,6 @@ EffectMask::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
aStream << nsPrintfCString("EffectMask (0x%p)", this).get();
|
||||
AppendToString(aStream, mSize, " [size=", "]");
|
||||
AppendToString(aStream, mMaskTransform, " [mask-transform=", "]");
|
||||
|
||||
if (mIs3D) {
|
||||
aStream << " [is-3d]";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -85,7 +85,6 @@ struct EffectMask : public Effect
|
||||
const gfx::Matrix4x4 &aMaskTransform)
|
||||
: Effect(EffectTypes::MASK)
|
||||
, mMaskTexture(aMaskTexture)
|
||||
, mIs3D(false)
|
||||
, mSize(aSize)
|
||||
, mMaskTransform(aMaskTransform)
|
||||
{}
|
||||
@@ -93,7 +92,6 @@ struct EffectMask : public Effect
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
|
||||
TextureSource* mMaskTexture;
|
||||
bool mIs3D;
|
||||
gfx::IntSize mSize;
|
||||
gfx::Matrix4x4 mMaskTransform;
|
||||
};
|
||||
|
||||
@@ -234,6 +234,12 @@ public:
|
||||
mDoSmoothScroll = aOther.mDoSmoothScroll;
|
||||
}
|
||||
|
||||
void UpdateScrollInfo(uint32_t aScrollGeneration, const CSSPoint& aScrollOffset)
|
||||
{
|
||||
mScrollOffset = aScrollOffset;
|
||||
mScrollGeneration = aScrollGeneration;
|
||||
}
|
||||
|
||||
// Make a copy of this FrameMetrics object which does not have any pointers
|
||||
// to heap-allocated memory (i.e. is Plain Old Data, or 'POD'), and is
|
||||
// therefore safe to be placed into shared memory.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/RefPtr.h" // for already_AddRefed
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
@@ -1202,7 +1202,6 @@ SenderHelper::SendMaskEffect(GLContext* aGLContext,
|
||||
// Expose packet creation here, so we could dump secondary mask effect attributes.
|
||||
auto packet = MakeUnique<layerscope::Packet>();
|
||||
TexturePacket::EffectMask* mask = packet->mutable_texture()->mutable_mask();
|
||||
mask->set_mis3d(aEffect->mIs3D);
|
||||
mask->mutable_msize()->set_w(aEffect->mSize.width);
|
||||
mask->mutable_msize()->set_h(aEffect->mSize.height);
|
||||
auto element = reinterpret_cast<const Float *>(&(aEffect->mMaskTransform));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mozilla/UniquePtr.h>
|
||||
#include "gfxMatrix.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -16,10 +17,12 @@ namespace gl { class GLContext; }
|
||||
|
||||
namespace layers {
|
||||
|
||||
|
||||
namespace layerscope { class Packet; }
|
||||
|
||||
struct EffectChain;
|
||||
class LayerComposite;
|
||||
class TextureHost;
|
||||
|
||||
class LayerScope {
|
||||
public:
|
||||
|
||||
@@ -1466,11 +1466,7 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToS
|
||||
ComputeEffectiveTransformsForChildren(idealTransform);
|
||||
}
|
||||
|
||||
if (idealTransform.CanDraw2D()) {
|
||||
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
|
||||
} else {
|
||||
ComputeEffectiveTransformForMaskLayers(Matrix4x4());
|
||||
}
|
||||
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "APZCTreeManager.h"
|
||||
#include "AsyncPanZoomController.h"
|
||||
#include "Compositor.h" // for Compositor
|
||||
#include "DragTracker.h" // for DragTracker
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "HitTestingTreeNode.h" // for HitTestingTreeNode
|
||||
#include "InputBlockState.h" // for InputBlockState
|
||||
@@ -138,7 +139,7 @@ APZCTreeManager::UpdateHitTestingTree(CompositorBridgeParent* aCompositor,
|
||||
{
|
||||
APZThreadUtils::AssertOnCompositorThread();
|
||||
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
// For testing purposes, we log some data to the APZTestData associated with
|
||||
// the layers id that originated this update.
|
||||
@@ -492,6 +493,10 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
|
||||
aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
|
||||
"parentScrollId", apzc->GetParent()->GetGuid().mScrollId);
|
||||
}
|
||||
if (aMetrics.IsRootContent()) {
|
||||
aState.mPaintLogger.LogTestData(aMetrics.GetScrollId(),
|
||||
"isRootContent", true);
|
||||
}
|
||||
}
|
||||
|
||||
if (newApzc) {
|
||||
@@ -614,10 +619,6 @@ WillHandleWheelEvent(WidgetWheelEvent* aEvent)
|
||||
static bool
|
||||
WillHandleMouseEvent(const WidgetMouseEventBase& aEvent)
|
||||
{
|
||||
if (!gfxPrefs::APZDragEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aEvent.mMessage == eMouseMove ||
|
||||
aEvent.mMessage == eMouseDown ||
|
||||
aEvent.mMessage == eMouseUp;
|
||||
@@ -666,14 +667,22 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
|
||||
touchInput.mHandledByAPZ = true;
|
||||
result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
|
||||
break;
|
||||
} case MOUSE_INPUT: {
|
||||
MouseInput& mouseInput = aEvent.AsMouseInput();
|
||||
|
||||
if (DragTracker::StartsDrag(mouseInput)) {
|
||||
// If this is the start of a drag we need to unambiguously know if it's
|
||||
// going to land on a scrollbar or not. We can't apply an untransform
|
||||
// here without knowing that, so we need to ensure the untransform is
|
||||
// a no-op.
|
||||
FlushRepaintsToClearScreenToGeckoTransform();
|
||||
}
|
||||
|
||||
bool hitScrollbar = false;
|
||||
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(mouseInput.mOrigin,
|
||||
&hitResult);
|
||||
&hitResult, &hitScrollbar);
|
||||
|
||||
// When the mouse is outside the window we still want to handle dragging
|
||||
// but we won't find an APZC. Fallback to root APZC then.
|
||||
@@ -687,15 +696,36 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
/* aTargetConfirmed = */ false,
|
||||
mouseInput, aOutInputBlockId);
|
||||
|
||||
if (result == nsEventStatus_eConsumeDoDefault) {
|
||||
// This input event is part of a drag block, so whether or not it is
|
||||
// directed at a scrollbar depends on whether the drag block started
|
||||
// on a scrollbar.
|
||||
hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar);
|
||||
}
|
||||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
|
||||
// TODO Dagging on a scrollbar probably behaves differently from
|
||||
// the other input types in that the gecko coordinates are the same
|
||||
// as the screen coordinates even though the async transform on the APZC
|
||||
// is changing. I'm not really sure at this point and it'll take some
|
||||
// though to figure out properly.
|
||||
//mouseInput.mOrigin = untransformedOrigin;
|
||||
if (!hitScrollbar) {
|
||||
// The input was not targeted at a scrollbar, so we untransform it
|
||||
// like we do for other content. Scrollbars are "special" because they
|
||||
// have special handling in AsyncCompositionManager when resolution is
|
||||
// applied. TODO: we should find a better way to deal with this.
|
||||
ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
|
||||
ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
|
||||
ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
Maybe<ScreenPoint> untransformedRefPoint = UntransformBy(
|
||||
outTransform, mouseInput.mOrigin);
|
||||
if (untransformedRefPoint) {
|
||||
mouseInput.mOrigin = *untransformedRefPoint;
|
||||
}
|
||||
} else {
|
||||
// Likewise, if the input was targeted at a scrollbar, we don't want to
|
||||
// apply the callback transform in the main thread, so we remove the
|
||||
// scrollid from the guid. We need to keep the layersId intact so
|
||||
// that the response from the child process doesn't get discarded.
|
||||
aOutTargetGuid->mScrollId = FrameMetrics::NULL_SCROLL_ID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} case SCROLLWHEEL_INPUT: {
|
||||
@@ -865,6 +895,7 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
uint64_t* aOutInputBlockId)
|
||||
{
|
||||
aInput.mHandledByAPZ = true;
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
// If we are panned into overscroll and a second finger goes down,
|
||||
// ignore that second touch point completely. The touch-start for it is
|
||||
@@ -1125,6 +1156,7 @@ APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
|
||||
for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
|
||||
*touchEvent.touches.AppendElement() = touchInput.mTouches[i].ToNewDOMTouch();
|
||||
}
|
||||
touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
|
||||
return result;
|
||||
}
|
||||
case eWheelEventClass: {
|
||||
@@ -1189,7 +1221,7 @@ void
|
||||
APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
|
||||
const Maybe<ZoomConstraints>& aConstraints)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
|
||||
MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
|
||||
|
||||
@@ -1248,7 +1280,7 @@ APZCTreeManager::FlushRepaintsToClearScreenToGeckoTransform()
|
||||
// matched APZCs is the same. It is simplest to ensure that by flushing the
|
||||
// pending repaint requests, which makes all of the untransforms empty (and
|
||||
// therefore equal).
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
ForEachNode(mRootNode.get(),
|
||||
@@ -1273,7 +1305,7 @@ APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
|
||||
void
|
||||
APZCTreeManager::AdjustScrollForSurfaceShift(const ScreenPoint& aShift)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
|
||||
if (apzc) {
|
||||
apzc->AdjustScrollForSurfaceShift(aShift);
|
||||
@@ -1289,7 +1321,7 @@ APZCTreeManager::ClearTree()
|
||||
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
|
||||
mInputQueue.get(), &InputQueue::Clear));
|
||||
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
// Collect the nodes into a list, and then destroy each one.
|
||||
// We can't destroy them as we collect them, because ForEachNode()
|
||||
@@ -1311,7 +1343,7 @@ APZCTreeManager::ClearTree()
|
||||
RefPtr<HitTestingTreeNode>
|
||||
APZCTreeManager::GetRootNode() const
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
return mRootNode;
|
||||
}
|
||||
|
||||
@@ -1503,7 +1535,7 @@ APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
|
||||
MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
|
||||
RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
|
||||
@@ -1533,13 +1565,16 @@ APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
|
||||
}
|
||||
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
HitTestResult* aOutHitResult,
|
||||
bool* aOutHitScrollbar)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
HitTestResult hitResult = HitNothing;
|
||||
ParentLayerPoint point = ViewAs<ParentLayerPixel>(aPoint,
|
||||
PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point, &hitResult);
|
||||
RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point,
|
||||
&hitResult, aOutHitScrollbar);
|
||||
|
||||
if (aOutHitResult) {
|
||||
*aOutHitResult = hitResult;
|
||||
@@ -1568,7 +1603,7 @@ APZCTreeManager::BuildOverscrollHandoffChain(const RefPtr<AsyncPanZoomController
|
||||
// order in which scroll will be handed off to them.
|
||||
|
||||
// Grab tree lock since we'll be walking the APZC tree.
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
// Build the chain. If there is a scroll parent link, we use that. This is
|
||||
// needed to deal with scroll info layers, because they participate in handoff
|
||||
@@ -1641,7 +1676,7 @@ APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled)
|
||||
RefPtr<HitTestingTreeNode>
|
||||
APZCTreeManager::FindScrollNode(const AsyncDragMetrics& aDragMetrics)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
return DepthFirstSearch(mRootNode.get(),
|
||||
[&aDragMetrics](HitTestingTreeNode* aNode) {
|
||||
@@ -1652,7 +1687,8 @@ APZCTreeManager::FindScrollNode(const AsyncDragMetrics& aDragMetrics)
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
|
||||
const ParentLayerPoint& aHitTestPoint,
|
||||
HitTestResult* aOutHitResult)
|
||||
HitTestResult* aOutHitResult,
|
||||
bool* aOutHitScrollbar)
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
@@ -1704,6 +1740,13 @@ APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
|
||||
|
||||
if (*aOutHitResult != HitNothing) {
|
||||
MOZ_ASSERT(resultNode);
|
||||
if (aOutHitScrollbar) {
|
||||
for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
|
||||
if (n->IsScrollbarNode()) {
|
||||
*aOutHitScrollbar = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
AsyncPanZoomController* result = resultNode->GetNearestContainingApzcWithSameLayersId();
|
||||
if (!result) {
|
||||
result = FindRootApzcForLayersId(resultNode->GetLayersId());
|
||||
@@ -1872,7 +1915,7 @@ ScreenToParentLayerMatrix4x4
|
||||
APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const
|
||||
{
|
||||
Matrix4x4 result;
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment above. This function is called with aApzc at L, and the loop
|
||||
@@ -1913,7 +1956,7 @@ ParentLayerToScreenMatrix4x4
|
||||
APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const
|
||||
{
|
||||
Matrix4x4 result;
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment above. This function is called with aApzc at L, and the loop
|
||||
@@ -1942,7 +1985,7 @@ APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) co
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
MutexAutoLock lock(mTreeLock);
|
||||
RefPtr<AsyncPanZoomController> apzc;
|
||||
// For now, we only ever want to do pinching on the root-content APZC for
|
||||
// a given layers id.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/APZUtils.h" // for HitTestResult
|
||||
#include "mozilla/layers/TouchCounter.h"// for TouchCounter
|
||||
#include "mozilla/Monitor.h" // for Monitor
|
||||
#include "mozilla/Mutex.h" // for Mutex
|
||||
#include "mozilla/TimeStamp.h" // for mozilla::TimeStamp
|
||||
#include "mozilla/Vector.h" // for mozilla::Vector
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
@@ -44,7 +44,8 @@ enum AllowedTouchBehavior {
|
||||
enum ZoomToRectBehavior : uint32_t {
|
||||
DEFAULT_BEHAVIOR = 0,
|
||||
DISABLE_ZOOM_OUT = 1 << 0,
|
||||
PAN_INTO_VIEW_ONLY = 1 << 1
|
||||
PAN_INTO_VIEW_ONLY = 1 << 1,
|
||||
ONLY_ZOOM_TO_DEFAULT_SCALE = 1 << 2
|
||||
};
|
||||
|
||||
class Layer;
|
||||
@@ -437,7 +438,8 @@ public:
|
||||
*/
|
||||
RefPtr<HitTestingTreeNode> GetRootNode() const;
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
HitTestResult* aOutHitResult);
|
||||
HitTestResult* aOutHitResult,
|
||||
bool* aOutHitScrollbar = nullptr);
|
||||
ScreenToParentLayerMatrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const;
|
||||
ParentLayerToScreenMatrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
|
||||
private:
|
||||
@@ -455,7 +457,8 @@ private:
|
||||
GuidComparator aComparator);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode,
|
||||
const ParentLayerPoint& aHitTestPoint,
|
||||
HitTestResult* aOutHitResult);
|
||||
HitTestResult* aOutHitResult,
|
||||
bool* aOutHitScrollbar);
|
||||
AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
|
||||
AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
|
||||
AsyncPanZoomController* FindRootContentOrRootApzc() const;
|
||||
@@ -534,7 +537,7 @@ private:
|
||||
* is considered part of the APZC tree management state.
|
||||
* Finally, the lock needs to be held when accessing mZoomConstraints.
|
||||
* IMPORTANT: See the note about lock ordering at the top of this file. */
|
||||
mutable mozilla::Monitor mTreeLock;
|
||||
mutable mozilla::Mutex mTreeLock;
|
||||
RefPtr<HitTestingTreeNode> mRootNode;
|
||||
/* Holds the zoom constraints for scrollable layers, as determined by the
|
||||
* the main-thread gecko code. */
|
||||
|
||||
@@ -1032,6 +1032,10 @@ static float GetAxisScale(AsyncDragMetrics::DragDirection aDir, T aValue) {
|
||||
nsEventStatus AsyncPanZoomController::HandleDragEvent(const MouseInput& aEvent,
|
||||
const AsyncDragMetrics& aDragMetrics)
|
||||
{
|
||||
if (!gfxPrefs::APZDragEnabled()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
if (!GetApzcTreeManager()) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
@@ -2035,7 +2039,13 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
||||
if (controller) {
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
if (CurrentTouchBlock()->IsDuringFastFling()) {
|
||||
CancelableBlockState* block = CurrentInputBlock();
|
||||
MOZ_ASSERT(block);
|
||||
if (!block->AsTouchBlock()) {
|
||||
APZC_LOG("%p dropping long-press because some non-touch block interrupted it\n", this);
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
if (block->AsTouchBlock()->IsDuringFastFling()) {
|
||||
APZC_LOG("%p dropping long-press because of fast fling\n", this);
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
@@ -2057,8 +2067,21 @@ nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ScreenIntPoint& aP
|
||||
if (controller) {
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aPoint, &geckoScreenPoint)) {
|
||||
if (!CurrentTouchBlock()->SetSingleTapOccurred()) {
|
||||
return nsEventStatus_eIgnore;
|
||||
CancelableBlockState* block = CurrentInputBlock();
|
||||
MOZ_ASSERT(block);
|
||||
TouchBlockState* touch = block->AsTouchBlock();
|
||||
// |block| may be a non-touch block in the case where this function is
|
||||
// invoked by GestureEventListener on a timeout. In that case we already
|
||||
// verified that the single tap is allowed so we let it through.
|
||||
// XXX there is a bug here that in such a case the touch block that
|
||||
// generated this tap will not get its mSingleTapOccurred flag set.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1256344#c6
|
||||
if (touch) {
|
||||
if (touch->IsDuringFastFling()) {
|
||||
APZC_LOG("%p dropping single-tap because it was during a fast-fling\n", this);
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
touch->SetSingleTapOccurred();
|
||||
}
|
||||
// Because this may be being running as part of APZCTreeManager::ReceiveInputEvent,
|
||||
// calling controller->HandleSingleTap directly might mean that content receives
|
||||
@@ -2326,7 +2349,18 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
||||
ParentLayerPoint displacement = aStartPoint - aEndPoint;
|
||||
|
||||
ParentLayerPoint overscroll; // will be used outside monitor block
|
||||
{
|
||||
|
||||
// If the direction of panning is reversed within the same input block,
|
||||
// a later event in the block could potentially scroll an APZC earlier
|
||||
// in the handoff chain, than an earlier event in the block (because
|
||||
// the earlier APZC was scrolled to its extent in the original direction).
|
||||
// If immediate handoff is disallowed, we want to disallow this (to
|
||||
// preserve the property that a single input block only scrolls one APZC),
|
||||
// so we skip the earlier APZC.
|
||||
bool scrollThisApzc = gfxPrefs::APZAllowImmediateHandoff() ||
|
||||
(CurrentInputBlock() && (!CurrentInputBlock()->GetScrolledApzc() || this == CurrentInputBlock()->GetScrolledApzc()));
|
||||
|
||||
if (scrollThisApzc) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
ParentLayerPoint adjustedDisplacement;
|
||||
@@ -2351,6 +2385,8 @@ bool AsyncPanZoomController::AttemptScroll(ParentLayerPoint& aStartPoint,
|
||||
ScheduleCompositeAndMaybeRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
} else {
|
||||
overscroll = displacement;
|
||||
}
|
||||
|
||||
// Adjust the start point to reflect the consumed portion of the scroll.
|
||||
@@ -2683,7 +2719,10 @@ void AsyncPanZoomController::AdjustScrollForSurfaceShift(const ScreenPoint& aShi
|
||||
/ mFrameMetrics.GetZoom();
|
||||
APZC_LOG("%p adjusting scroll position by %s for surface shift\n",
|
||||
this, Stringify(adjustment).c_str());
|
||||
mFrameMetrics.ScrollBy(adjustment);
|
||||
CSSPoint scrollOffset = mFrameMetrics.GetScrollOffset();
|
||||
scrollOffset.y = mY.ClampOriginToScrollableRect(scrollOffset.y + adjustment.y);
|
||||
scrollOffset.x = mX.ClampOriginToScrollableRect(scrollOffset.x + adjustment.x);
|
||||
mFrameMetrics.SetScrollOffset(scrollOffset);
|
||||
ScheduleCompositeAndMaybeRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
@@ -2979,7 +3018,10 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
|
||||
mAnimation = nullptr;
|
||||
SetState(NOTHING);
|
||||
}
|
||||
if (wantsRepaints) {
|
||||
// Request a repaint at the end of the animation in case something such as a
|
||||
// call to NotifyLayersUpdated was invoked during the animation and Gecko's
|
||||
// current state is some intermediate point of the animation.
|
||||
if (!continueAnimation || wantsRepaints) {
|
||||
RequestContentRepaint();
|
||||
}
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
@@ -3247,6 +3289,15 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
bool isDefault = mFrameMetrics.IsDefault();
|
||||
|
||||
if ((aLayerMetrics == mLastContentPaintMetrics) && !isDefault) {
|
||||
// No new information here, skip it. Note that this is not just an
|
||||
// optimization; it's correctness too. In the case where we get one of these
|
||||
// stale aLayerMetrics *after* a call to NotifyScrollUpdated, processing the
|
||||
// stale aLayerMetrics would clobber the more up-to-date information from
|
||||
// NotifyScrollUpdated.
|
||||
APZC_LOG("%p NotifyLayersUpdated short-circuit\n", this);
|
||||
return;
|
||||
}
|
||||
mLastContentPaintMetrics = aLayerMetrics;
|
||||
|
||||
mFrameMetrics.SetScrollParentId(aLayerMetrics.GetScrollParentId());
|
||||
@@ -3449,6 +3500,35 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncPanZoomController::NotifyScrollUpdated(uint32_t aScrollGeneration,
|
||||
const CSSPoint& aScrollOffset)
|
||||
{
|
||||
APZThreadUtils::AssertOnCompositorThread();
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
APZC_LOG("%p NotifyScrollUpdated(%d, %s)\n", this, aScrollGeneration,
|
||||
Stringify(aScrollOffset).c_str());
|
||||
|
||||
bool scrollOffsetUpdated = aScrollGeneration != mFrameMetrics.GetScrollGeneration();
|
||||
if (!scrollOffsetUpdated) {
|
||||
return;
|
||||
}
|
||||
APZC_LOG("%p updating scroll offset from %s to %s\n", this,
|
||||
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
|
||||
Stringify(aScrollOffset).c_str());
|
||||
|
||||
mFrameMetrics.UpdateScrollInfo(aScrollGeneration, aScrollOffset);
|
||||
AcknowledgeScrollUpdate();
|
||||
mExpectedGeckoMetrics.UpdateScrollInfo(aScrollGeneration, aScrollOffset);
|
||||
CancelAnimation();
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
// We don't call ScheduleComposite() here because that happens higher up
|
||||
// in the call stack, when LayerTransactionParent handles this message.
|
||||
// If we did it here it would incur an extra message posting unnecessarily.
|
||||
}
|
||||
|
||||
void
|
||||
AsyncPanZoomController::AcknowledgeScrollUpdate() const
|
||||
{
|
||||
@@ -3550,12 +3630,31 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) {
|
||||
FrameMetrics endZoomToMetrics = mFrameMetrics;
|
||||
if (aFlags & PAN_INTO_VIEW_ONLY) {
|
||||
targetZoom = currentZoom;
|
||||
} else if(aFlags & ONLY_ZOOM_TO_DEFAULT_SCALE) {
|
||||
CSSToParentLayerScale zoomAtDefaultScale =
|
||||
mFrameMetrics.GetDevPixelsPerCSSPixel() * LayoutDeviceToParentLayerScale(1.0);
|
||||
if (targetZoom.scale > zoomAtDefaultScale.scale) {
|
||||
// Only change the zoom if we are less than the default zoom
|
||||
if (currentZoom.scale < zoomAtDefaultScale.scale) {
|
||||
targetZoom = zoomAtDefaultScale;
|
||||
} else {
|
||||
targetZoom = currentZoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
endZoomToMetrics.SetZoom(CSSToParentLayerScale2D(targetZoom));
|
||||
|
||||
// Adjust the zoomToRect to a sensible position to prevent overscrolling.
|
||||
CSSSize sizeAfterZoom = endZoomToMetrics.CalculateCompositedSizeInCssPixels();
|
||||
|
||||
// Vertically center the zoomed element in the screen.
|
||||
if (!zoomOut && (sizeAfterZoom.height > aRect.height)) {
|
||||
aRect.y -= (sizeAfterZoom.height - aRect.height) * 0.5f;
|
||||
if (aRect.y < 0.0f) {
|
||||
aRect.y = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// If either of these conditions are met, the page will be
|
||||
// overscrolled after zoomed
|
||||
if (aRect.y + sizeAfterZoom.height > cssPageRect.height) {
|
||||
@@ -3567,14 +3666,6 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) {
|
||||
aRect.x = aRect.x > 0 ? aRect.x : 0;
|
||||
}
|
||||
|
||||
// Vertically center the zoomed element in the screen.
|
||||
if (!zoomOut && (sizeAfterZoom.height > aRect.height)) {
|
||||
aRect.y -= (sizeAfterZoom.height - aRect.height) * 0.5f;
|
||||
if (aRect.y < 0.0f) {
|
||||
aRect.y = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
|
||||
|
||||
StartAnimation(new ZoomAnimation(
|
||||
|
||||
@@ -187,6 +187,13 @@ public:
|
||||
void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint,
|
||||
bool aThisLayerTreeUpdated);
|
||||
|
||||
/**
|
||||
* A lightweight version of NotifyLayersUpdated that allows just the scroll
|
||||
* offset and scroll generation from the main thread to be propagated to APZ.
|
||||
*/
|
||||
void NotifyScrollUpdated(uint32_t aScrollGeneration,
|
||||
const CSSPoint& aScrollOffset);
|
||||
|
||||
/**
|
||||
* The platform implementation must set the compositor parent so that we can
|
||||
* request composites.
|
||||
@@ -614,11 +621,6 @@ protected:
|
||||
*/
|
||||
APZCTreeManager* GetApzcTreeManager() const;
|
||||
|
||||
/**
|
||||
* Gets a ref to the input queue that is shared across the entire tree manager.
|
||||
*/
|
||||
const RefPtr<InputQueue>& GetInputQueue() const;
|
||||
|
||||
/**
|
||||
* Convert ScreenPoint relative to the screen to CSSPoint relative
|
||||
* to the parent document. This excludes the transient compositor transform.
|
||||
@@ -813,6 +815,11 @@ public:
|
||||
*/
|
||||
void ResetTouchInputState();
|
||||
|
||||
/**
|
||||
* Gets a ref to the input queue that is shared across the entire tree manager.
|
||||
*/
|
||||
const RefPtr<InputQueue>& GetInputQueue() const;
|
||||
|
||||
private:
|
||||
void CancelAnimationAndGestureState();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include <sstream>
|
||||
#include "Units.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "DragTracker.h"
|
||||
|
||||
#include "InputData.h"
|
||||
|
||||
#define DRAG_LOG(...)
|
||||
// #define DRAG_LOG(...) printf_stderr("DRAG: " __VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
DragTracker::DragTracker()
|
||||
: mInDrag(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
DragTracker::StartsDrag(const MouseInput& aInput)
|
||||
{
|
||||
return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_DOWN;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
DragTracker::EndsDrag(const MouseInput& aInput)
|
||||
{
|
||||
return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_UP;
|
||||
}
|
||||
|
||||
void
|
||||
DragTracker::Update(const MouseInput& aInput)
|
||||
{
|
||||
if (StartsDrag(aInput)) {
|
||||
DRAG_LOG("Starting drag\n");
|
||||
mInDrag = true;
|
||||
} else if (EndsDrag(aInput)) {
|
||||
DRAG_LOG("Ending drag\n");
|
||||
mInDrag = false;
|
||||
mOnScrollbar = Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DragTracker::InDrag() const
|
||||
{
|
||||
return mInDrag;
|
||||
}
|
||||
|
||||
bool
|
||||
DragTracker::IsOnScrollbar(bool aOnScrollbar)
|
||||
{
|
||||
if (!mOnScrollbar) {
|
||||
DRAG_LOG("Setting hitscrollbar %d\n", aOnScrollbar);
|
||||
mOnScrollbar = Some(aOnScrollbar);
|
||||
}
|
||||
return mOnScrollbar.value();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,39 @@
|
||||
/* -*- 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 mozilla_layers_DragTracker_h
|
||||
#define mozilla_layers_DragTracker_h
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MouseInput;
|
||||
|
||||
namespace layers {
|
||||
|
||||
// DragTracker simply tracks a sequence of mouse inputs and allows us to tell
|
||||
// if we are in a drag or not (i.e. the left mouse button went down and hasn't
|
||||
// gone up yet).
|
||||
class DragTracker
|
||||
{
|
||||
public:
|
||||
DragTracker();
|
||||
static bool StartsDrag(const MouseInput& aInput);
|
||||
static bool EndsDrag(const MouseInput& aInput);
|
||||
void Update(const MouseInput& aInput);
|
||||
bool InDrag() const;
|
||||
bool IsOnScrollbar(bool aOnScrollbar);
|
||||
|
||||
private:
|
||||
Maybe<bool> mOnScrollbar;
|
||||
bool mInDrag;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_layers_DragTracker_h */
|
||||
@@ -444,7 +444,7 @@ void GestureEventListener::HandleInputTimeoutLongTap()
|
||||
}
|
||||
}
|
||||
|
||||
void GestureEventListener::HandleInputTimeoutMaxTap()
|
||||
void GestureEventListener::HandleInputTimeoutMaxTap(bool aDuringFastFling)
|
||||
{
|
||||
GEL_LOG("Running max-tap timeout task in state %d\n", mState);
|
||||
|
||||
@@ -455,7 +455,9 @@ void GestureEventListener::HandleInputTimeoutMaxTap()
|
||||
} else if (mState == GESTURE_FIRST_SINGLE_TOUCH_UP ||
|
||||
mState == GESTURE_SECOND_SINGLE_TOUCH_DOWN) {
|
||||
SetState(GESTURE_NONE);
|
||||
TriggerSingleTapConfirmedEvent();
|
||||
if (!aDuringFastFling) {
|
||||
TriggerSingleTapConfirmedEvent();
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("Unhandled state upon MAX_TAP timeout");
|
||||
SetState(GESTURE_NONE);
|
||||
@@ -520,8 +522,10 @@ void GestureEventListener::CreateMaxTapTimeoutTask()
|
||||
{
|
||||
mLastTapInput = mLastTouchInput;
|
||||
|
||||
TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->CurrentTouchBlock();
|
||||
mMaxTapTimeoutTask =
|
||||
NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap);
|
||||
NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap,
|
||||
block->IsDuringFastFling());
|
||||
|
||||
mAsyncPanZoomController->PostDelayedTask(
|
||||
mMaxTapTimeoutTask,
|
||||
|
||||
@@ -137,7 +137,7 @@ private:
|
||||
nsEventStatus HandleInputTouchMove();
|
||||
nsEventStatus HandleInputTouchCancel();
|
||||
void HandleInputTimeoutLongTap();
|
||||
void HandleInputTimeoutMaxTap();
|
||||
void HandleInputTimeoutMaxTap(bool aDuringFastFling);
|
||||
|
||||
void TriggerSingleTapConfirmedEvent();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread
|
||||
#include "mozilla/layers/APZUtils.h" // for CompleteAsyncTransform
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform::operator Matrix4x4()
|
||||
#include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "UnitTransforms.h" // for ViewAs
|
||||
|
||||
@@ -114,6 +115,12 @@ HitTestingTreeNode::GetScrollSize() const
|
||||
return mScrollSize;
|
||||
}
|
||||
|
||||
bool
|
||||
HitTestingTreeNode::IsScrollbarNode() const
|
||||
{
|
||||
return (mScrollDir != Layer::NONE);
|
||||
}
|
||||
|
||||
void
|
||||
HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling)
|
||||
{
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
void SetScrollbarData(FrameMetrics::ViewID aScrollViewId, Layer::ScrollDirection aDir, int32_t aScrollSize);
|
||||
bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
|
||||
int32_t GetScrollSize() const;
|
||||
bool IsScrollbarNode() const;
|
||||
|
||||
/* Convert aPoint into the LayerPixel space for the layer corresponding to
|
||||
* this node. */
|
||||
|
||||
@@ -87,9 +87,33 @@ InputBlockState::IsTargetConfirmed() const
|
||||
return mTargetConfirmed;
|
||||
}
|
||||
|
||||
bool
|
||||
InputBlockState::IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB)
|
||||
{
|
||||
if (aA == aB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seenA = false;
|
||||
for (size_t i = 0; i < mOverscrollHandoffChain->Length(); ++i) {
|
||||
AsyncPanZoomController* apzc = mOverscrollHandoffChain->GetApzcAtIndex(i);
|
||||
if (apzc == aB) {
|
||||
return seenA;
|
||||
}
|
||||
if (apzc == aA) {
|
||||
seenA = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InputBlockState::SetScrolledApzc(AsyncPanZoomController* aApzc)
|
||||
{
|
||||
// An input block should only have one scrolled APZC.
|
||||
MOZ_ASSERT(!mScrolledApzc || mScrolledApzc == aApzc);
|
||||
|
||||
mScrolledApzc = aApzc;
|
||||
}
|
||||
|
||||
@@ -716,16 +740,11 @@ TouchBlockState::IsDuringFastFling() const
|
||||
return mDuringFastFling;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
TouchBlockState::SetSingleTapOccurred()
|
||||
{
|
||||
TBS_LOG("%p attempting to set single-tap occurred; disallowed=%d\n",
|
||||
this, mDuringFastFling);
|
||||
if (!mDuringFastFling) {
|
||||
mSingleTapOccurred = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
TBS_LOG("%p setting single-tap-occurred flag\n", this);
|
||||
mSingleTapOccurred = true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
#include "InputData.h" // for MultiTouchInput
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/APZUtils.h" // for TouchBehaviorFlags
|
||||
#include "mozilla/layers/AsyncDragMetrics.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsTArray.h" // for nsTArray
|
||||
#include "TouchCounter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@@ -54,6 +56,11 @@ public:
|
||||
protected:
|
||||
virtual void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
|
||||
|
||||
private:
|
||||
// Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
|
||||
// |mOverscrollHandoffChain|.
|
||||
bool IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB);
|
||||
|
||||
private:
|
||||
RefPtr<AsyncPanZoomController> mTargetApzc;
|
||||
bool mTargetConfirmed;
|
||||
@@ -409,10 +416,8 @@ public:
|
||||
/**
|
||||
* Set the single-tap-occurred flag that indicates that this touch block
|
||||
* triggered a single tap event.
|
||||
* @return true if the flag was set. This may not happen if, for example,
|
||||
* SetDuringFastFling was previously called.
|
||||
*/
|
||||
bool SetSingleTapOccurred();
|
||||
void SetSingleTapOccurred();
|
||||
/**
|
||||
* @return true iff the single-tap-occurred flag is set on this block.
|
||||
*/
|
||||
|
||||
@@ -185,7 +185,7 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
|
||||
// On a new mouse down we can have a new target so we must force a new block
|
||||
// with a new target.
|
||||
bool newBlock = aEvent.mType == MouseInput::MOUSE_DOWN && aEvent.IsLeftButton();
|
||||
bool newBlock = DragTracker::StartsDrag(aEvent);
|
||||
|
||||
DragBlockState* block = nullptr;
|
||||
if (!newBlock && !mInputBlockQueue.IsEmpty()) {
|
||||
@@ -196,8 +196,20 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
block = nullptr;
|
||||
}
|
||||
|
||||
if (!block && mDragTracker.InDrag()) {
|
||||
// If there's no current drag block, but we're getting a move with a button
|
||||
// down, we need to start a new drag block because we're obviously already
|
||||
// in the middle of a drag (it probably got interrupted by something else).
|
||||
INPQ_LOG("got a drag event outside a drag block, need to create a block to hold it\n");
|
||||
newBlock = true;
|
||||
}
|
||||
|
||||
mDragTracker.Update(aEvent);
|
||||
|
||||
if (!newBlock && !block) {
|
||||
return nsEventStatus_eConsumeDoDefault;
|
||||
// This input event is not in a drag block, so we're not doing anything
|
||||
// with it, return eIgnore.
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
@@ -218,7 +230,7 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
|
||||
block->AddEvent(aEvent.AsMouseInput());
|
||||
|
||||
// The first event will confirm the block or not.
|
||||
// This input event created a new drag block, so return DoDefault.
|
||||
return nsEventStatus_eConsumeDoDefault;
|
||||
}
|
||||
|
||||
@@ -230,13 +242,12 @@ InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
|
||||
block->AddEvent(aEvent.AsMouseInput());
|
||||
}
|
||||
|
||||
bool mouseUp = aEvent.mType == MouseInput::MOUSE_UP && aEvent.IsLeftButton();
|
||||
if (mouseUp) {
|
||||
if (DragTracker::EndsDrag(aEvent)) {
|
||||
block->MarkMouseUpReceived();
|
||||
}
|
||||
|
||||
// If we're not the first event then we need to wait for the confirmation of
|
||||
// the block.
|
||||
// The event was added to the drag block and could potentially cause
|
||||
// scrolling, so return DoDefault.
|
||||
return nsEventStatus_eConsumeDoDefault;
|
||||
}
|
||||
|
||||
@@ -537,6 +548,19 @@ InputQueue::AllowScrollHandoff() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::IsDragOnScrollbar(bool aHitScrollbar)
|
||||
{
|
||||
if (!mDragTracker.InDrag()) {
|
||||
return false;
|
||||
}
|
||||
// Now that we know we are in a drag, get the info from the drag tracker.
|
||||
// We keep it in the tracker rather than the block because the block can get
|
||||
// interrupted by something else (like a wheel event) and then a new block
|
||||
// will get created without the info we want. The tracker will persist though.
|
||||
return mDragTracker.IsOnScrollbar(aHitScrollbar);
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId) {
|
||||
INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get());
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#define mozilla_layers_InputQueue_h
|
||||
|
||||
#include "APZUtils.h"
|
||||
#include "DragTracker.h"
|
||||
#include "InputData.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "TouchCounter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -118,6 +120,12 @@ public:
|
||||
* Whether the current pending block allows scroll handoff.
|
||||
*/
|
||||
bool AllowScrollHandoff() const;
|
||||
/**
|
||||
* If there is currently a drag in progress, return whether or not it was
|
||||
* targeted at a scrollbar. If the drag was newly-created and doesn't know,
|
||||
* use the provided |aOnScrollbar| to populate that information.
|
||||
*/
|
||||
bool IsDragOnScrollbar(bool aOnScrollbar);
|
||||
|
||||
private:
|
||||
~InputQueue();
|
||||
@@ -182,6 +190,9 @@ private:
|
||||
|
||||
// Track touches so we know when to clear mLastActiveApzc
|
||||
TouchCounter mTouchCounter;
|
||||
|
||||
// Track mouse inputs so we know if we're in a drag or not
|
||||
DragTracker mDragTracker;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
|
||||
#include "APZCTreeManager.h"
|
||||
#include "APZUtils.h" // for CancelAnimationFlags
|
||||
#include "Layers.h" // for Layer::ScrollDirection
|
||||
#include "Units.h" // for ScreenPoint
|
||||
|
||||
@@ -39,46 +39,6 @@ function convertTestData(testData) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Utilities for reconstructing the structure of the APZC tree from
|
||||
// 'parentScrollId' entries in the APZ test data.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// Create a node with scroll id 'id' in the APZC tree.
|
||||
function makeNode(id) {
|
||||
return {scrollId: id, children: []};
|
||||
}
|
||||
|
||||
// Find a node with scroll id 'id' in the APZC tree rooted at 'root'.
|
||||
function findNode(root, id) {
|
||||
if (root.scrollId == id) {
|
||||
return root;
|
||||
}
|
||||
for (var i = 0; i < root.children.length; ++i) {
|
||||
var subtreeResult = findNode(root.children[i], id);
|
||||
if (subtreeResult != null) {
|
||||
return subtreeResult;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add a child -> parent link to the APZC tree rooted at 'root'.
|
||||
function addLink(root, child, parent) {
|
||||
var parentNode = findNode(root, parent);
|
||||
if (parentNode == null) {
|
||||
parentNode = makeNode(parent);
|
||||
root.children.push(parentNode);
|
||||
}
|
||||
parentNode.children.push(makeNode(child));
|
||||
}
|
||||
|
||||
// Add a root node to the APZC tree. It will become a direct
|
||||
// child of 'root'.
|
||||
function addRoot(root, id) {
|
||||
root.children.push(makeNode(id));
|
||||
}
|
||||
|
||||
// Given APZ test data for a single paint on the compositor side,
|
||||
// reconstruct the APZC tree structure from the 'parentScrollId'
|
||||
// entries that were logged. More specifically, the subset of the
|
||||
@@ -89,13 +49,51 @@ function buildApzcTree(paint) {
|
||||
// The APZC tree can potentially have multiple root nodes,
|
||||
// so we invent a node that is the parent of all roots.
|
||||
// This 'root' does not correspond to an APZC.
|
||||
var root = makeNode(-1);
|
||||
var root = {scrollId: -1, children: []};
|
||||
for (var scrollId in paint) {
|
||||
paint[scrollId].children = [];
|
||||
paint[scrollId].scrollId = scrollId;
|
||||
}
|
||||
for (var scrollId in paint) {
|
||||
var parentNode = null;
|
||||
if ("hasNoParentWithSameLayersId" in paint[scrollId]) {
|
||||
addRoot(root, scrollId);
|
||||
parentNode = root;
|
||||
} else if ("parentScrollId" in paint[scrollId]) {
|
||||
addLink(root, scrollId, paint[scrollId]["parentScrollId"]);
|
||||
parentNode = paint[paint[scrollId].parentScrollId];
|
||||
}
|
||||
parentNode.children.push(paint[scrollId]);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
// Given an APZC tree produced by buildApzcTree, return the RCD node in
|
||||
// the tree, or null if there was none.
|
||||
function findRcdNode(apzcTree) {
|
||||
if (!!apzcTree.isRootContent) { // isRootContent will be undefined or "1"
|
||||
return apzcTree;
|
||||
}
|
||||
for (var i = 0; i < apzcTree.children.length; i++) {
|
||||
var rcd = findRcdNode(apzcTree.children[i]);
|
||||
if (rcd != null) {
|
||||
return rcd;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function flushApzRepaints(aCallback, aWindow = window) {
|
||||
if (!aCallback) {
|
||||
throw "A callback must be provided!";
|
||||
}
|
||||
var repaintDone = function() {
|
||||
SpecialPowers.Services.obs.removeObserver(repaintDone, "apz-repaints-flushed", false);
|
||||
setTimeout(aCallback, 0);
|
||||
};
|
||||
SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed", false);
|
||||
if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) {
|
||||
dump("Flushed APZ repaints, waiting for callback...\n");
|
||||
} else {
|
||||
dump("Flushing APZ repaints was a no-op, triggering callback directly...\n");
|
||||
repaintDone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ ScrollFrame(nsIContent* aContent,
|
||||
{
|
||||
// Scroll the window to the desired spot
|
||||
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
|
||||
if (sf) {
|
||||
sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer());
|
||||
}
|
||||
|
||||
bool scrollUpdated = false;
|
||||
CSSPoint apzScrollOffset = aMetrics.GetScrollOffset();
|
||||
CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
|
||||
|
||||
@@ -278,6 +278,7 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
// Since APZ doesn't know about it we don't want to send a response for
|
||||
// this block; we want to just skip over it from the point of view of
|
||||
// prevent-default notifications.
|
||||
APZES_LOG("Got a synthetic touch-start!\n");
|
||||
break;
|
||||
}
|
||||
if (isTouchPrevented) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
|
||||
#include "mozilla/dom/CheckerboardReportServiceBinding.h" // for dom::CheckerboardReports
|
||||
#include "nsContentUtils.h" // for nsContentUtils
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
@@ -166,26 +166,34 @@ BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect,
|
||||
}
|
||||
|
||||
already_AddRefed<CompositingRenderTarget>
|
||||
BasicCompositor::CreateRenderTargetForWindow(const IntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
|
||||
BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
|
||||
{
|
||||
if (aBufferMode != BufferMode::BUFFER_NONE) {
|
||||
return CreateRenderTarget(aRect, aInit);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDrawTarget);
|
||||
MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
|
||||
|
||||
if (aRect.width * aRect.height == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDrawTarget);
|
||||
RefPtr<BasicCompositingRenderTarget> rt;
|
||||
IntRect rect = aRect.ToUnknownRect();
|
||||
|
||||
// Adjust bounds rect to account for new origin at (0, 0).
|
||||
IntRect rect(0, 0, aRect.XMost(), aRect.YMost());
|
||||
RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(mDrawTarget, rect);
|
||||
|
||||
if (aInit == INIT_MODE_CLEAR) {
|
||||
mDrawTarget->ClearRect(gfx::Rect(aRect));
|
||||
if (aBufferMode != BufferMode::BUFFER_NONE) {
|
||||
RefPtr<DrawTarget> target = mWidget->CreateBackBufferDrawTarget(mDrawTarget, aRect);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
rt = new BasicCompositingRenderTarget(target, rect);
|
||||
} else {
|
||||
IntRect windowRect = rect;
|
||||
// Adjust bounds rect to account for new origin at (0, 0).
|
||||
if (windowRect.Size() != mDrawTarget->GetSize()) {
|
||||
windowRect.ExpandToEnclose(IntPoint(0, 0));
|
||||
}
|
||||
rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect);
|
||||
if (aInit == INIT_MODE_CLEAR) {
|
||||
mDrawTarget->ClearRect(Rect(rect - rt->GetOrigin()));
|
||||
}
|
||||
}
|
||||
|
||||
return rt.forget();
|
||||
@@ -389,6 +397,25 @@ RoundOut(Rect r)
|
||||
return IntRect(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
|
||||
static void
|
||||
SetupMask(const EffectChain& aEffectChain,
|
||||
DrawTarget* aDest,
|
||||
const IntPoint& aOffset,
|
||||
RefPtr<SourceSurface>& aMaskSurface,
|
||||
Matrix& aMaskTransform)
|
||||
{
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
aMaskSurface = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(aDest);
|
||||
if (!aMaskSurface) {
|
||||
gfxWarning() << "Invalid sourceMask effect";
|
||||
}
|
||||
MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
|
||||
aMaskTransform = effectMask->mMaskTransform.As2D();
|
||||
aMaskTransform.PostTranslate(-aOffset.x, -aOffset.y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
const gfx::Rect& aClipRect,
|
||||
@@ -434,7 +461,8 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
// When we apply the 3D transformation, we do it against a temporary
|
||||
// surface, so undo the coordinate offset.
|
||||
new3DTransform = Matrix4x4::Translation(aRect.x, aRect.y, 0) * aTransform;
|
||||
new3DTransform = aTransform;
|
||||
new3DTransform.PreTranslate(aRect.x, aRect.y, 0);
|
||||
}
|
||||
|
||||
buffer->PushClipRect(aClipRect);
|
||||
@@ -444,16 +472,8 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
RefPtr<SourceSurface> sourceMask;
|
||||
Matrix maskTransform;
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
|
||||
if (!sourceMask) {
|
||||
gfxWarning() << "Invalid sourceMask effect";
|
||||
}
|
||||
MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
|
||||
MOZ_ASSERT(!effectMask->mIs3D);
|
||||
maskTransform = effectMask->mMaskTransform.As2D();
|
||||
maskTransform.PreTranslate(-offset.x, -offset.y);
|
||||
if (aTransform.Is2D()) {
|
||||
SetupMask(aEffectChain, dest, offset, sourceMask, maskTransform);
|
||||
}
|
||||
|
||||
CompositionOp blendMode = CompositionOp::OP_OVER;
|
||||
@@ -560,8 +580,40 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
Transform(temp, source, new3DTransform, transformBounds.TopLeft());
|
||||
|
||||
SetupMask(aEffectChain, buffer, offset, sourceMask, maskTransform);
|
||||
|
||||
// Adjust for the fact that our content now start at 0,0 instead
|
||||
// of the top left of transformBounds.
|
||||
transformBounds.MoveTo(0, 0);
|
||||
buffer->DrawSurface(temp, transformBounds, transformBounds);
|
||||
maskTransform.PostTranslate(-transformBounds.x, -transformBounds.y);
|
||||
|
||||
if (sourceMask) {
|
||||
// Transform the source by it's normal transform, and then the inverse
|
||||
// of the mask transform so that it's in the mask's untransformed
|
||||
// coordinate space.
|
||||
Matrix old = buffer->GetTransform();
|
||||
Matrix sourceTransform = old;
|
||||
|
||||
Matrix inverseMask = maskTransform;
|
||||
inverseMask.Invert();
|
||||
|
||||
sourceTransform *= inverseMask;
|
||||
|
||||
SurfacePattern source(temp, ExtendMode::CLAMP, sourceTransform);
|
||||
|
||||
buffer->PushClipRect(transformBounds);
|
||||
|
||||
// Mask in the untransformed coordinate space, and then transform
|
||||
// by the mask transform to put the result back into destination
|
||||
// coords.
|
||||
buffer->SetTransform(maskTransform);
|
||||
buffer->MaskSurface(source, sourceMask, Point(0, 0));
|
||||
buffer->SetTransform(old);
|
||||
|
||||
buffer->PopClip();
|
||||
} else {
|
||||
buffer->DrawSurface(temp, transformBounds, transformBounds);
|
||||
}
|
||||
}
|
||||
|
||||
buffer->PopClip();
|
||||
@@ -577,6 +629,7 @@ void
|
||||
BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect *aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect *aClipRectOut /* = nullptr */,
|
||||
gfx::Rect *aRenderBoundsOut /* = nullptr */)
|
||||
{
|
||||
@@ -627,7 +680,9 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
// Setup an intermediate render target to buffer all compositing. We will
|
||||
// copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
|
||||
RefPtr<CompositingRenderTarget> target =
|
||||
CreateRenderTargetForWindow(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR, bufferMode);
|
||||
CreateRenderTargetForWindow(mInvalidRect,
|
||||
aOpaque ? INIT_MODE_NONE : INIT_MODE_CLEAR,
|
||||
bufferMode);
|
||||
if (!target) {
|
||||
if (!mTarget) {
|
||||
mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
const gfx::IntPoint &aSourcePoint) override;
|
||||
|
||||
virtual already_AddRefed<CompositingRenderTarget>
|
||||
CreateRenderTargetForWindow(const gfx::IntRect& aRect,
|
||||
CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect,
|
||||
SurfaceInitMode aInit,
|
||||
BufferMode aBufferMode);
|
||||
|
||||
@@ -97,6 +97,7 @@ public:
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect *aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect *aClipRectOut = nullptr,
|
||||
gfx::Rect *aRenderBoundsOut = nullptr) override;
|
||||
virtual void EndFrame() override;
|
||||
|
||||
@@ -32,6 +32,7 @@ ClientTiledPaintedLayer::ClientTiledPaintedLayer(ClientLayerManager* const aMana
|
||||
ClientLayerManager::PaintedLayerCreationHint aCreationHint)
|
||||
: PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint)
|
||||
, mContentClient()
|
||||
, mHaveSingleTiledContentClient(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
|
||||
mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
|
||||
@@ -181,13 +182,15 @@ ClientTiledPaintedLayer::BeginPaint()
|
||||
+ displayportMetrics.GetCompositionBounds().TopLeft();
|
||||
Maybe<LayerRect> criticalDisplayPortTransformed =
|
||||
ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort, layerBounds);
|
||||
if (!criticalDisplayPortTransformed) {
|
||||
mPaintData.ResetPaintData();
|
||||
return;
|
||||
if (criticalDisplayPortTransformed) {
|
||||
mPaintData.mCriticalDisplayPort = Some(RoundedToInt(*criticalDisplayPortTransformed));
|
||||
} else {
|
||||
mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
|
||||
}
|
||||
mPaintData.mCriticalDisplayPort = RoundedToInt(*criticalDisplayPortTransformed);
|
||||
}
|
||||
TILING_LOG("TILING %p: Critical displayport %s\n", this, Stringify(mPaintData.mCriticalDisplayPort).c_str());
|
||||
TILING_LOG("TILING %p: Critical displayport %s\n", this,
|
||||
mPaintData.mCriticalDisplayPort ?
|
||||
Stringify(*mPaintData.mCriticalDisplayPort).c_str() : "not set");
|
||||
|
||||
// Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
|
||||
// before any async transforms have occurred, we can use the zoom for this.
|
||||
@@ -200,11 +203,11 @@ ClientTiledPaintedLayer::BeginPaint()
|
||||
ParentLayerToLayerMatrix4x4 transformToBounds = mPaintData.mTransformToCompBounds.Inverse();
|
||||
Maybe<LayerRect> compositionBoundsTransformed = ApplyParentLayerToLayerTransform(
|
||||
transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
|
||||
if (!compositionBoundsTransformed) {
|
||||
mPaintData.ResetPaintData();
|
||||
return;
|
||||
if (compositionBoundsTransformed) {
|
||||
mPaintData.mCompositionBounds = *compositionBoundsTransformed;
|
||||
} else {
|
||||
mPaintData.mCompositionBounds.SetEmpty();
|
||||
}
|
||||
mPaintData.mCompositionBounds = *compositionBoundsTransformed;
|
||||
TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
|
||||
|
||||
// Calculate the scroll offset since the last transaction
|
||||
@@ -260,7 +263,7 @@ ClientTiledPaintedLayer::UseProgressiveDraw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
if (!mPaintData.mCriticalDisplayPort) {
|
||||
// This catches three scenarios:
|
||||
// 1) This layer doesn't have a scrolling ancestor
|
||||
// 2) This layer is subject to OMTA transforms
|
||||
@@ -279,7 +282,7 @@ ClientTiledPaintedLayer::UseProgressiveDraw() {
|
||||
if (ClientManager()->AsyncPanZoomEnabled()) {
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
|
||||
MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
|
||||
MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is set
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
if (!IsScrollingOnCompositor(parentMetrics)) {
|
||||
return false;
|
||||
@@ -295,22 +298,24 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
// If we have no high-precision stuff to draw, or we have started drawing low-precision
|
||||
// already, then we shouldn't do anything there.
|
||||
if (aInvalidRegion.IsEmpty() || mPaintData.mLowPrecisionPaintCount != 0) {
|
||||
// If we have started drawing low-precision already, then we
|
||||
// shouldn't do anything there.
|
||||
if (mPaintData.mLowPrecisionPaintCount != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only draw progressively when the resolution is unchanged
|
||||
if (UseProgressiveDraw() &&
|
||||
// Only draw progressively when there is something to paint and the
|
||||
// resolution is unchanged
|
||||
if (!aInvalidRegion.IsEmpty() &&
|
||||
UseProgressiveDraw() &&
|
||||
mContentClient->GetTiledBuffer()->GetFrameResolution() == mPaintData.mResolution) {
|
||||
// Store the old valid region, then clear it before painting.
|
||||
// We clip the old valid region to the visible region, as it only gets
|
||||
// used to decide stale content (currently valid and previously visible)
|
||||
nsIntRegion oldValidRegion = mContentClient->GetTiledBuffer()->GetValidRegion();
|
||||
oldValidRegion.And(oldValidRegion, aVisibleRegion);
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect());
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());
|
||||
@@ -319,11 +324,12 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
|
||||
oldValidRegion, &mPaintData, aCallback, aCallbackData);
|
||||
}
|
||||
|
||||
// Otherwise do a non-progressive paint
|
||||
// Otherwise do a non-progressive paint. We must do this even when
|
||||
// the region to paint is empty as the valid region may have shrunk.
|
||||
|
||||
mValidRegion = aVisibleRegion;
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect());
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
|
||||
@@ -344,7 +350,8 @@ ClientTiledPaintedLayer::RenderLowPrecision(nsIntRegion& aInvalidRegion,
|
||||
{
|
||||
// Render the low precision buffer, if the visible region is larger than the
|
||||
// critical display port.
|
||||
if (!nsIntRegion(mPaintData.mCriticalDisplayPort.ToUnknownRect()).Contains(aVisibleRegion)) {
|
||||
if (!mPaintData.mCriticalDisplayPort ||
|
||||
!nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect()).Contains(aVisibleRegion)) {
|
||||
nsIntRegion oldValidRegion = mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
|
||||
oldValidRegion.And(oldValidRegion, aVisibleRegion);
|
||||
|
||||
@@ -415,18 +422,26 @@ ClientTiledPaintedLayer::RenderLayer()
|
||||
void *data = ClientManager()->GetPaintedLayerCallbackData();
|
||||
|
||||
IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
|
||||
if (mContentClient && !mContentClient->SupportsLayerSize(layerSize, ClientManager())) {
|
||||
IntSize tileSize(gfxPlatform::GetPlatform()->GetTileWidth(),
|
||||
gfxPlatform::GetPlatform()->GetTileHeight());
|
||||
|
||||
bool wantSingleTiledContentClient =
|
||||
(mCreationHint == LayerManager::NONE || layerSize <= tileSize) &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled();
|
||||
|
||||
if (mContentClient && mHaveSingleTiledContentClient && !wantSingleTiledContentClient) {
|
||||
mContentClient = nullptr;
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
if (!mContentClient) {
|
||||
if (mCreationHint == LayerManager::NONE &&
|
||||
SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
|
||||
gfxPrefs::LayersSingleTileEnabled()) {
|
||||
if (wantSingleTiledContentClient) {
|
||||
mContentClient = new SingleTiledContentClient(this, ClientManager());
|
||||
mHaveSingleTiledContentClient = true;
|
||||
} else {
|
||||
mContentClient = new MultiTiledContentClient(this, ClientManager());
|
||||
mHaveSingleTiledContentClient = false;
|
||||
}
|
||||
|
||||
mContentClient->Connect();
|
||||
@@ -490,16 +505,16 @@ ClientTiledPaintedLayer::RenderLayer()
|
||||
// critical displayport are discarded on the first update. Also make sure that we
|
||||
// only draw stuff inside the critical displayport on the first update.
|
||||
mValidRegion.And(mValidRegion, neededRegion);
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect());
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect());
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
|
||||
TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(mValidRegion).c_str());
|
||||
TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
|
||||
} else {
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect());
|
||||
if (mPaintData.mCriticalDisplayPort) {
|
||||
invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
|
||||
}
|
||||
TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
|
||||
}
|
||||
|
||||
@@ -133,6 +133,9 @@ private:
|
||||
void EndPaint();
|
||||
|
||||
RefPtr<TiledContentClient> mContentClient;
|
||||
// Flag to indicate if mContentClient is a SingleTiledContentClient. This is
|
||||
// only valid when mContentClient is non-null.
|
||||
bool mHaveSingleTiledContentClient;
|
||||
nsIntRegion mLowPrecisionValidRegion;
|
||||
BasicTiledLayerPaintData mPaintData;
|
||||
};
|
||||
|
||||
@@ -46,12 +46,6 @@ SingleTiledContentClient::ClientSupportsLayerSize(const gfx::IntSize& aSize, Cli
|
||||
return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize;
|
||||
}
|
||||
|
||||
bool
|
||||
SingleTiledContentClient::SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const
|
||||
{
|
||||
return ClientSupportsLayerSize(aSize, aManager);
|
||||
}
|
||||
|
||||
ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer* aPaintedLayer,
|
||||
CompositableClient* aCompositableClient,
|
||||
ClientLayerManager* aManager)
|
||||
|
||||
@@ -127,8 +127,6 @@ public:
|
||||
virtual ClientTiledLayerBuffer* GetTiledBuffer() override { return mTiledBuffer; }
|
||||
virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override { return nullptr; }
|
||||
|
||||
virtual bool SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const override;
|
||||
|
||||
private:
|
||||
RefPtr<ClientSingleTiledLayerBuffer> mTiledBuffer;
|
||||
};
|
||||
|
||||
@@ -916,47 +916,47 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
long start = PR_IntervalNow();
|
||||
#endif
|
||||
|
||||
// If this region is empty XMost() - 1 will give us a negative value.
|
||||
NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n");
|
||||
|
||||
if (!gfxPrefs::TiledDrawTargetEnabled()) {
|
||||
RefPtr<gfxContext> ctxt;
|
||||
if (!aPaintRegion.IsEmpty()) {
|
||||
|
||||
const IntRect bounds = aPaintRegion.GetBounds();
|
||||
{
|
||||
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferAlloc",
|
||||
RefPtr<gfxContext> ctxt;
|
||||
|
||||
const IntRect bounds = aPaintRegion.GetBounds();
|
||||
{
|
||||
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferAlloc",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
mSinglePaintDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
gfx::IntSize(ceilf(bounds.width * mResolution),
|
||||
ceilf(bounds.height * mResolution)),
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(
|
||||
GetContentType()));
|
||||
|
||||
if (!mSinglePaintDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctxt = new gfxContext(mSinglePaintDrawTarget);
|
||||
|
||||
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
|
||||
}
|
||||
ctxt->NewPath();
|
||||
ctxt->SetMatrix(
|
||||
ctxt->CurrentMatrix().Scale(mResolution, mResolution).
|
||||
Translate(-bounds.x, -bounds.y));
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 3) {
|
||||
printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferDraw",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
mSinglePaintDrawTarget =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
gfx::IntSize(ceilf(bounds.width * mResolution),
|
||||
ceilf(bounds.height * mResolution)),
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(
|
||||
GetContentType()));
|
||||
|
||||
if (!mSinglePaintDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctxt = new gfxContext(mSinglePaintDrawTarget);
|
||||
|
||||
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
|
||||
mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
|
||||
DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
|
||||
}
|
||||
ctxt->NewPath();
|
||||
ctxt->SetMatrix(
|
||||
ctxt->CurrentMatrix().Scale(mResolution, mResolution).
|
||||
Translate(-bounds.x, -bounds.y));
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (PR_IntervalNow() - start > 3) {
|
||||
printf_stderr("Slow alloc %i\n", PR_IntervalNow() - start);
|
||||
}
|
||||
start = PR_IntervalNow();
|
||||
#endif
|
||||
PROFILER_LABEL("ClientMultiTiledLayerBuffer", "PaintThebesSingleBufferDraw",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
mCallback(mPaintedLayer, ctxt, aPaintRegion, aDirtyRegion,
|
||||
DrawRegionClip::NONE, nsIntRegion(), mCallbackData);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
@@ -1132,79 +1132,81 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
for (size_t i = 0; i < newTileCount; ++i) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion)) {
|
||||
gfxCriticalError() << "ValidateTile failed";
|
||||
}
|
||||
}
|
||||
|
||||
if (gfxPrefs::TiledDrawTargetEnabled() && mMoz2DTiles.size() > 0) {
|
||||
gfx::TileSet tileset;
|
||||
for (size_t i = 0; i < mMoz2DTiles.size(); ++i) {
|
||||
mMoz2DTiles[i].mTileOrigin -= mTilingOrigin;
|
||||
}
|
||||
tileset.mTiles = &mMoz2DTiles[0];
|
||||
tileset.mTileCount = mMoz2DTiles.size();
|
||||
RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
|
||||
drawTarget->SetTransform(Matrix());
|
||||
|
||||
RefPtr<gfxContext> ctx = new gfxContext(drawTarget);
|
||||
ctx->SetMatrix(
|
||||
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
|
||||
|
||||
mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
|
||||
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
|
||||
mMoz2DTiles.clear();
|
||||
// Reset:
|
||||
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
|
||||
std::numeric_limits<int32_t>::max());
|
||||
}
|
||||
|
||||
bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
|
||||
|
||||
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
|
||||
// Only worry about padding when not doing low-res because it simplifies
|
||||
// the math and the artifacts won't be noticable
|
||||
// Edge padding prevents sampling artifacts when compositing.
|
||||
if (edgePaddingEnabled && mResolution == 1 &&
|
||||
tile.mFrontBuffer && tile.mFrontBuffer->IsLocked()) {
|
||||
|
||||
if (!aPaintRegion.IsEmpty()) {
|
||||
for (size_t i = 0; i < newTileCount; ++i) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
// Strictly speakig we want the unscaled rect here, but it doesn't matter
|
||||
// because we only run this code when the resolution is equal to 1.
|
||||
IntRect tileRect = IntRect(tileOffset.x, tileOffset.y,
|
||||
GetTileSize().width, GetTileSize().height);
|
||||
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
|
||||
nsIntRegion tileValidRegion = mValidRegion;
|
||||
tileValidRegion.OrWith(tileDrawRegion);
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only need to pad out if the tile has area that's not valid
|
||||
if (!tileValidRegion.Contains(tileRect)) {
|
||||
tileValidRegion = tileValidRegion.Intersect(tileRect);
|
||||
// translate the region into tile space and pad
|
||||
tileValidRegion.MoveBy(-IntPoint(tileOffset.x, tileOffset.y));
|
||||
RefPtr<DrawTarget> drawTarget = tile.mFrontBuffer->BorrowDrawTarget();
|
||||
PadDrawTargetOutFromRegion(drawTarget, tileValidRegion);
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
if (!ValidateTile(tile, GetTileOffset(tilePosition), tileDrawRegion)) {
|
||||
gfxCriticalError() << "ValidateTile failed";
|
||||
}
|
||||
}
|
||||
UnlockTile(tile);
|
||||
|
||||
if (gfxPrefs::TiledDrawTargetEnabled() && mMoz2DTiles.size() > 0) {
|
||||
gfx::TileSet tileset;
|
||||
for (size_t i = 0; i < mMoz2DTiles.size(); ++i) {
|
||||
mMoz2DTiles[i].mTileOrigin -= mTilingOrigin;
|
||||
}
|
||||
tileset.mTiles = &mMoz2DTiles[0];
|
||||
tileset.mTileCount = mMoz2DTiles.size();
|
||||
RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
|
||||
drawTarget->SetTransform(Matrix());
|
||||
|
||||
RefPtr<gfxContext> ctx = new gfxContext(drawTarget);
|
||||
ctx->SetMatrix(
|
||||
ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin)));
|
||||
|
||||
mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion,
|
||||
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
|
||||
mMoz2DTiles.clear();
|
||||
// Reset:
|
||||
mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
|
||||
std::numeric_limits<int32_t>::max());
|
||||
}
|
||||
|
||||
bool edgePaddingEnabled = gfxPrefs::TileEdgePaddingEnabled();
|
||||
|
||||
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
|
||||
// Only worry about padding when not doing low-res because it simplifies
|
||||
// the math and the artifacts won't be noticable
|
||||
// Edge padding prevents sampling artifacts when compositing.
|
||||
if (edgePaddingEnabled && mResolution == 1 &&
|
||||
tile.mFrontBuffer && tile.mFrontBuffer->IsLocked()) {
|
||||
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
// Strictly speakig we want the unscaled rect here, but it doesn't matter
|
||||
// because we only run this code when the resolution is equal to 1.
|
||||
IntRect tileRect = IntRect(tileOffset.x, tileOffset.y,
|
||||
GetTileSize().width, GetTileSize().height);
|
||||
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
|
||||
nsIntRegion tileValidRegion = mValidRegion;
|
||||
tileValidRegion.OrWith(tileDrawRegion);
|
||||
|
||||
// We only need to pad out if the tile has area that's not valid
|
||||
if (!tileValidRegion.Contains(tileRect)) {
|
||||
tileValidRegion = tileValidRegion.Intersect(tileRect);
|
||||
// translate the region into tile space and pad
|
||||
tileValidRegion.MoveBy(-IntPoint(tileOffset.x, tileOffset.y));
|
||||
RefPtr<DrawTarget> drawTarget = tile.mFrontBuffer->BorrowDrawTarget();
|
||||
PadDrawTargetOutFromRegion(drawTarget, tileValidRegion);
|
||||
}
|
||||
}
|
||||
UnlockTile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
mTiles = newTiles;
|
||||
@@ -1685,7 +1687,7 @@ BasicTiledLayerPaintData::ResetPaintData()
|
||||
mLowPrecisionPaintCount = 0;
|
||||
mPaintFinished = false;
|
||||
mCompositionBounds.SetEmpty();
|
||||
mCriticalDisplayPort.SetEmpty();
|
||||
mCriticalDisplayPort = Nothing();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -318,10 +318,10 @@ struct BasicTiledLayerPaintData {
|
||||
|
||||
/*
|
||||
* The critical displayport of the content from the nearest ancestor layer
|
||||
* that represents scrollable content with a display port set. Empty if a
|
||||
* critical displayport is not set.
|
||||
* that represents scrollable content with a display port set. isNothing()
|
||||
* if a critical displayport is not set.
|
||||
*/
|
||||
LayerIntRect mCriticalDisplayPort;
|
||||
Maybe<LayerIntRect> mCriticalDisplayPort;
|
||||
|
||||
/*
|
||||
* The render resolution of the document that the content this layer
|
||||
@@ -628,9 +628,6 @@ public:
|
||||
};
|
||||
virtual void UpdatedBuffer(TiledBufferType aType) = 0;
|
||||
|
||||
virtual bool SupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager) const
|
||||
{ return true; }
|
||||
|
||||
private:
|
||||
const char* mName;
|
||||
};
|
||||
|
||||
@@ -148,8 +148,7 @@ CompositableHost::SetCompositor(Compositor* aCompositor)
|
||||
|
||||
bool
|
||||
CompositableHost::AddMaskEffect(EffectChain& aEffects,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
bool aIs3D)
|
||||
const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
CompositableTextureSourceRef source;
|
||||
RefPtr<TextureHost> host = GetAsTextureHost();
|
||||
@@ -174,7 +173,6 @@ CompositableHost::AddMaskEffect(EffectChain& aEffects,
|
||||
RefPtr<EffectMask> effect = new EffectMask(source,
|
||||
source->GetSize(),
|
||||
aTransform);
|
||||
effect->mIs3D = aIs3D;
|
||||
aEffects.mSecondaryEffects[EffectTypes::MASK] = effect;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,7 @@ public:
|
||||
* @return true if the effect was added, false otherwise.
|
||||
*/
|
||||
bool AddMaskEffect(EffectChain& aEffects,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
bool aIs3D = false);
|
||||
const gfx::Matrix4x4& aTransform);
|
||||
|
||||
void RemoveMaskEffect();
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "apz/src/AsyncPanZoomController.h" // for AsyncPanZoomController
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for LayerRect, LayerPixel, etc
|
||||
#include "CompositableHost.h" // for CompositableHost
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
#include "nsTArray.h" // for AutoTArray
|
||||
#include <stack>
|
||||
#include "TextRenderer.h" // for TextRenderer
|
||||
#include <vector>
|
||||
#include "VRManager.h" // for VRManager
|
||||
|
||||
@@ -899,13 +899,15 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
|
||||
|
||||
CompositorBench(mCompositor, bounds);
|
||||
|
||||
MOZ_ASSERT(mRoot->GetOpacity() == 1);
|
||||
bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
|
||||
if (mRoot->GetClipRect()) {
|
||||
clipRect = *mRoot->GetClipRect();
|
||||
Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
|
||||
mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, nullptr, &actualBounds);
|
||||
mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, opaqueContent, nullptr, &actualBounds);
|
||||
} else {
|
||||
gfx::Rect rect;
|
||||
mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, &rect, &actualBounds);
|
||||
mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, opaqueContent, &rect, &actualBounds);
|
||||
clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
@@ -1158,8 +1160,10 @@ LayerManagerComposite::RenderToPresentationSurface()
|
||||
nsIntRegion invalid;
|
||||
Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
|
||||
Rect rect, actualBounds;
|
||||
MOZ_ASSERT(mRoot->GetOpacity() == 1);
|
||||
bool opaqueContent = (mRoot->GetContentFlags() & Layer::CONTENT_OPAQUE) != 0;
|
||||
|
||||
mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
|
||||
mCompositor->BeginFrame(invalid, nullptr, bounds, opaqueContent, &rect, &actualBounds);
|
||||
|
||||
// The Java side of Fennec sets a scissor rect that accounts for
|
||||
// chrome such as the URL bar. Override that so that the entire frame buffer
|
||||
@@ -1462,8 +1466,7 @@ LayerManagerComposite::CreateRefLayerComposite()
|
||||
}
|
||||
|
||||
LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer,
|
||||
EffectChain& aEffects,
|
||||
bool aIs3D)
|
||||
EffectChain& aEffects)
|
||||
: mCompositable(nullptr), mFailed(false)
|
||||
{
|
||||
if (!aMaskLayer) {
|
||||
@@ -1477,7 +1480,7 @@ LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCompositable->AddMaskEffect(aEffects, aMaskLayer->GetEffectiveTransform(), aIs3D)) {
|
||||
if (!mCompositable->AddMaskEffect(aEffects, aMaskLayer->GetEffectiveTransform())) {
|
||||
mCompositable = nullptr;
|
||||
mFailed = true;
|
||||
}
|
||||
|
||||
@@ -188,8 +188,7 @@ public:
|
||||
{
|
||||
public:
|
||||
AutoAddMaskEffect(Layer* aMaskLayer,
|
||||
EffectChain& aEffect,
|
||||
bool aIs3D = false);
|
||||
EffectChain& aEffect);
|
||||
~AutoAddMaskEffect();
|
||||
|
||||
bool Failed() const { return mFailed; }
|
||||
@@ -582,16 +581,11 @@ RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
|
||||
// no mask layers at all
|
||||
}
|
||||
|
||||
bool firstMaskIs3D = false;
|
||||
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
|
||||
firstMaskIs3D = !container->GetTransform().CanDraw2D();
|
||||
}
|
||||
|
||||
if (maskLayerCount <= 1) {
|
||||
// This is the common case. Render in one pass and return.
|
||||
EffectChain effectChain(aLayer);
|
||||
LayerManagerComposite::AutoAddMaskEffect
|
||||
autoMaskEffect(firstMask, effectChain, firstMaskIs3D);
|
||||
autoMaskEffect(firstMask, effectChain);
|
||||
aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain);
|
||||
aRenderCallback(effectChain, gfx::Rect(aClipRect));
|
||||
return;
|
||||
@@ -630,7 +624,7 @@ RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
|
||||
{
|
||||
EffectChain firstEffectChain(aLayer);
|
||||
LayerManagerComposite::AutoAddMaskEffect
|
||||
firstMaskEffect(firstMask, firstEffectChain, firstMaskIs3D);
|
||||
firstMaskEffect(firstMask, firstEffectChain);
|
||||
aRenderCallback(firstEffectChain, gfx::Rect(aClipRect - surfaceRect.TopLeft()));
|
||||
// firstTarget now contains the transformed source with the first mask and
|
||||
// opacity already applied.
|
||||
|
||||
@@ -565,6 +565,10 @@ public:
|
||||
|
||||
virtual void WaitAcquireFenceHandleSyncComplete() {};
|
||||
|
||||
virtual bool NeedsFenceHandle() { return false; }
|
||||
|
||||
virtual FenceHandle GetCompositorReleaseFence() { return FenceHandle(); }
|
||||
|
||||
protected:
|
||||
FenceHandle mReleaseFenceHandle;
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
|
||||
// These must be in the same order as the Mask enum.
|
||||
#define PS_MASK_NONE 0
|
||||
#define PS_MASK_2D 1
|
||||
#define PS_MASK_3D 2
|
||||
#define PS_MASK 1
|
||||
|
||||
// These must be in the same order as CompositionOp.
|
||||
#define PS_BLEND_MULTIPLY 0
|
||||
@@ -50,8 +49,7 @@ BlendOpToShaderConstant(gfx::CompositionOp aOp) {
|
||||
namespace {
|
||||
static inline void BlendShaderConstantAsserts() {
|
||||
static_assert(PS_MASK_NONE == int(mozilla::layers::MaskType::MaskNone), "shader constant is out of sync");
|
||||
static_assert(PS_MASK_2D == int(mozilla::layers::MaskType::Mask2d), "shader constant is out of sync");
|
||||
static_assert(PS_MASK_3D == int(mozilla::layers::MaskType::Mask3d), "shader constant is out of sync");
|
||||
static_assert(PS_MASK == int(mozilla::layers::MaskType::Mask), "shader constant is out of sync");
|
||||
static_assert(int(mozilla::gfx::CompositionOp::OP_LUMINOSITY) - int(mozilla::gfx::CompositionOp::OP_MULTIPLY) == 14,
|
||||
"shader constants are out of sync");
|
||||
}
|
||||
|
||||
@@ -907,12 +907,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
MaskType maskType = MaskType::MaskNone;
|
||||
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
if (aTransform.Is2D()) {
|
||||
maskType = MaskType::Mask2d;
|
||||
} else {
|
||||
MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EffectTypes::RGB);
|
||||
maskType = MaskType::Mask3d;
|
||||
}
|
||||
maskType = MaskType::Mask;
|
||||
|
||||
EffectMask* maskEffect =
|
||||
static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
@@ -1129,6 +1124,7 @@ void
|
||||
CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const Rect* aClipRectIn,
|
||||
const Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
Rect* aClipRectOut,
|
||||
Rect* aRenderBoundsOut)
|
||||
{
|
||||
@@ -1493,8 +1489,7 @@ DeviceAttachmentsD3D11::InitBlendShaders()
|
||||
{
|
||||
if (!mVSQuadBlendShader[MaskType::MaskNone]) {
|
||||
InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
|
||||
InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask2d);
|
||||
InitVertexShader(sLayerQuadBlendMask3DVS, mVSQuadBlendShader, MaskType::Mask3d);
|
||||
InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask);
|
||||
}
|
||||
if (!mBlendShader[MaskType::MaskNone]) {
|
||||
InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
|
||||
@@ -1506,21 +1501,19 @@ bool
|
||||
DeviceAttachmentsD3D11::CreateShaders()
|
||||
{
|
||||
InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
|
||||
InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask2d);
|
||||
InitVertexShader(sLayerQuadMask3DVS, mVSQuadShader, MaskType::Mask3d);
|
||||
InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask);
|
||||
|
||||
InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
|
||||
InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask2d);
|
||||
InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask);
|
||||
InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
|
||||
InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask2d);
|
||||
InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask);
|
||||
InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
|
||||
InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask2d);
|
||||
InitPixelShader(sRGBAShaderMask3D, mRGBAShader, MaskType::Mask3d);
|
||||
InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask);
|
||||
InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
|
||||
InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask2d);
|
||||
InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask);
|
||||
if (gfxPrefs::ComponentAlphaEnabled()) {
|
||||
InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone);
|
||||
InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask2d);
|
||||
InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask);
|
||||
}
|
||||
|
||||
InitVertexShader(sOculus050VRDistortionVS, getter_AddRefs(mVRDistortionVS[VRHMDType::Oculus050]));
|
||||
|
||||
@@ -111,6 +111,7 @@ public:
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect *aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect *aClipRectOut = nullptr,
|
||||
gfx::Rect *aRenderBoundsOut = nullptr) override;
|
||||
|
||||
|
||||
@@ -47,12 +47,6 @@ struct VS_OUTPUT {
|
||||
};
|
||||
|
||||
struct VS_MASK_OUTPUT {
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float2 vMaskCoords : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct VS_MASK_3D_OUTPUT {
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float3 vMaskCoords : TEXCOORD1;
|
||||
@@ -153,23 +147,6 @@ VS_MASK_OUTPUT LayerQuadMaskVS(const VS_INPUT aVertex)
|
||||
// calculate the position on the mask texture
|
||||
outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
|
||||
outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
|
||||
|
||||
outp.vTexCoords = TexCoords(aVertex.vPosition.xy);
|
||||
|
||||
return outp;
|
||||
}
|
||||
|
||||
VS_MASK_3D_OUTPUT LayerQuadMask3DVS(const VS_INPUT aVertex)
|
||||
{
|
||||
VS_MASK_3D_OUTPUT outp;
|
||||
float4 position = TransformedPosition(aVertex.vPosition);
|
||||
|
||||
outp.vPosition = VertexPosition(position);
|
||||
|
||||
// calculate the position on the mask texture
|
||||
position.xyz /= position.w;
|
||||
outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
|
||||
outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
|
||||
// We use the w coord to do non-perspective correct interpolation:
|
||||
// the quad might be transformed in 3D, in which case it will have some
|
||||
// perspective. The graphics card will do perspective-correct interpolation
|
||||
@@ -187,16 +164,9 @@ VS_MASK_3D_OUTPUT LayerQuadMask3DVS(const VS_INPUT aVertex)
|
||||
}
|
||||
|
||||
float4 RGBAShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
|
||||
}
|
||||
|
||||
float4 RGBAShaderMask3D(const VS_MASK_3D_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).r;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
|
||||
}
|
||||
|
||||
@@ -206,7 +176,7 @@ float4 RGBShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
result = tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity;
|
||||
result.a = fLayerOpacity;
|
||||
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
return result * mask;
|
||||
}
|
||||
@@ -240,7 +210,7 @@ float4 CalculateYCbCrColor(const float2 aTexCoords)
|
||||
|
||||
float4 YCbCrShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
|
||||
return CalculateYCbCrColor(aVertex.vTexCoords) * fLayerOpacity * mask;
|
||||
@@ -254,7 +224,7 @@ PS_OUTPUT ComponentAlphaShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
result.vAlpha = 1.0 - tRGBWhite.Sample(sSampler, aVertex.vTexCoords) + result.vSrc;
|
||||
result.vSrc.a = result.vAlpha.g;
|
||||
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
result.vSrc *= fLayerOpacity * mask;
|
||||
result.vAlpha *= fLayerOpacity * mask;
|
||||
@@ -264,7 +234,7 @@ PS_OUTPUT ComponentAlphaShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
|
||||
float4 SolidColorShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tMask.Sample(sSampler, maskCoords).r;
|
||||
return fLayerColor * mask;
|
||||
}
|
||||
@@ -325,18 +295,6 @@ VS_BLEND_OUTPUT LayerQuadBlendMaskVS(const VS_INPUT aVertex)
|
||||
{
|
||||
VS_MASK_OUTPUT v = LayerQuadMaskVS(aVertex);
|
||||
|
||||
VS_BLEND_OUTPUT o;
|
||||
o.vPosition = v.vPosition;
|
||||
o.vTexCoords = v.vTexCoords;
|
||||
o.vMaskCoords = float3(v.vMaskCoords, 0);
|
||||
o.vBackdropCoords = BackdropPosition(v.vPosition);
|
||||
return o;
|
||||
}
|
||||
|
||||
VS_BLEND_OUTPUT LayerQuadBlendMask3DVS(const VS_INPUT aVertex)
|
||||
{
|
||||
VS_MASK_3D_OUTPUT v = LayerQuadMask3DVS(aVertex);
|
||||
|
||||
VS_BLEND_OUTPUT o;
|
||||
o.vPosition = v.vPosition;
|
||||
o.vTexCoords = v.vTexCoords;
|
||||
@@ -367,7 +325,7 @@ float4 ComputeBlendSourceColor(const VS_BLEND_OUTPUT aVertex)
|
||||
VS_MASK_OUTPUT tmp;
|
||||
tmp.vPosition = aVertex.vPosition;
|
||||
tmp.vTexCoords = aVertex.vTexCoords;
|
||||
tmp.vMaskCoords = aVertex.vMaskCoords.xy;
|
||||
tmp.vMaskCoords = aVertex.vMaskCoords;
|
||||
|
||||
if (iBlendConfig.x == PS_LAYER_RGB) {
|
||||
return RGBShaderMask(tmp);
|
||||
@@ -377,13 +335,6 @@ float4 ComputeBlendSourceColor(const VS_BLEND_OUTPUT aVertex)
|
||||
return YCbCrShaderMask(tmp);
|
||||
}
|
||||
return SolidColorShaderMask(tmp);
|
||||
} else if (iBlendConfig.y == PS_MASK_3D) {
|
||||
// The only Mask 3D shader is RGBA.
|
||||
VS_MASK_3D_OUTPUT tmp;
|
||||
tmp.vPosition = aVertex.vPosition;
|
||||
tmp.vTexCoords = aVertex.vTexCoords;
|
||||
tmp.vMaskCoords = aVertex.vMaskCoords;
|
||||
return RGBAShaderMask3D(tmp);
|
||||
}
|
||||
|
||||
return float4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
+3199
-4571
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#if 0
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
|
||||
//
|
||||
//
|
||||
// Buffer Definitions:
|
||||
@@ -16,9 +16,9 @@
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim Slot Elements
|
||||
// ------------------------------ ---------- ------- ----------- ---- --------
|
||||
// $Globals cbuffer NA NA 0 1
|
||||
// Name Type Format Dim HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- -------------- ------
|
||||
// $Globals cbuffer NA NA cb0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
// approximately 10 instruction slots used
|
||||
vs_4_0
|
||||
dcl_constantbuffer cb0[2], immediateIndexed
|
||||
dcl_constantbuffer CB0[2], immediateIndexed
|
||||
dcl_input v0.xy
|
||||
dcl_input v1.xy
|
||||
dcl_input v2.xy
|
||||
@@ -106,10 +106,10 @@ ret
|
||||
|
||||
const BYTE Oculus050VRDistortionVS[] =
|
||||
{
|
||||
68, 88, 66, 67, 3, 61,
|
||||
196, 122, 10, 53, 44, 234,
|
||||
18, 242, 195, 238, 42, 90,
|
||||
72, 193, 1, 0, 0, 0,
|
||||
68, 88, 66, 67, 92, 195,
|
||||
173, 230, 45, 84, 78, 45,
|
||||
143, 175, 88, 53, 65, 235,
|
||||
243, 174, 1, 0, 0, 0,
|
||||
244, 5, 0, 0, 6, 0,
|
||||
0, 0, 56, 0, 0, 0,
|
||||
108, 1, 0, 0, 44, 3,
|
||||
@@ -303,9 +303,9 @@ const BYTE Oculus050VRDistortionVS[] =
|
||||
83, 76, 32, 83, 104, 97,
|
||||
100, 101, 114, 32, 67, 111,
|
||||
109, 112, 105, 108, 101, 114,
|
||||
32, 54, 46, 51, 46, 57,
|
||||
54, 48, 48, 46, 49, 54,
|
||||
51, 56, 52, 0, 171, 171,
|
||||
32, 49, 48, 46, 48, 46,
|
||||
49, 48, 48, 49, 49, 46,
|
||||
49, 54, 51, 56, 52, 0,
|
||||
73, 83, 71, 78, 152, 0,
|
||||
0, 0, 5, 0, 0, 0,
|
||||
8, 0, 0, 0, 128, 0,
|
||||
@@ -364,15 +364,15 @@ const BYTE Oculus050VRDistortionVS[] =
|
||||
ShaderBytes sOculus050VRDistortionVS = { Oculus050VRDistortionVS, sizeof(Oculus050VRDistortionVS) };
|
||||
#if 0
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
|
||||
//
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim Slot Elements
|
||||
// ------------------------------ ---------- ------- ----------- ---- --------
|
||||
// Linear sampler NA NA 0 1
|
||||
// Texture texture float4 2d 0 1
|
||||
// Name Type Format Dim HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- -------------- ------
|
||||
// Linear sampler NA NA s0 1
|
||||
// Texture texture float4 2d t0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -442,10 +442,10 @@ ret
|
||||
|
||||
const BYTE Oculus050VRDistortionPS[] =
|
||||
{
|
||||
68, 88, 66, 67, 108, 219,
|
||||
61, 216, 27, 0, 27, 222,
|
||||
242, 132, 183, 21, 166, 141,
|
||||
130, 39, 1, 0, 0, 0,
|
||||
68, 88, 66, 67, 17, 210,
|
||||
217, 234, 219, 61, 77, 84,
|
||||
3, 36, 81, 127, 138, 35,
|
||||
252, 53, 1, 0, 0, 0,
|
||||
128, 4, 0, 0, 6, 0,
|
||||
0, 0, 56, 0, 0, 0,
|
||||
60, 1, 0, 0, 132, 2,
|
||||
@@ -595,9 +595,9 @@ const BYTE Oculus050VRDistortionPS[] =
|
||||
76, 32, 83, 104, 97, 100,
|
||||
101, 114, 32, 67, 111, 109,
|
||||
112, 105, 108, 101, 114, 32,
|
||||
54, 46, 51, 46, 57, 54,
|
||||
48, 48, 46, 49, 54, 51,
|
||||
56, 52, 0, 171, 171, 171,
|
||||
49, 48, 46, 48, 46, 49,
|
||||
48, 48, 49, 49, 46, 49,
|
||||
54, 51, 56, 52, 0, 171,
|
||||
73, 83, 71, 78, 156, 0,
|
||||
0, 0, 5, 0, 0, 0,
|
||||
8, 0, 0, 0, 128, 0,
|
||||
|
||||
@@ -36,18 +36,15 @@ makeShaderPS RGBAShader
|
||||
makeShaderPS ComponentAlphaShader
|
||||
makeShaderPS YCbCrShader
|
||||
makeShaderVS LayerQuadMaskVS
|
||||
makeShaderVS LayerQuadMask3DVS
|
||||
makeShaderPS SolidColorShaderMask
|
||||
makeShaderPS RGBShaderMask
|
||||
makeShaderPS RGBAShaderMask
|
||||
makeShaderPS RGBAShaderMask3D
|
||||
makeShaderPS YCbCrShaderMask
|
||||
makeShaderPS ComponentAlphaShaderMask
|
||||
|
||||
# Mix-blend shaders
|
||||
makeShaderVS LayerQuadBlendVS
|
||||
makeShaderVS LayerQuadBlendMaskVS
|
||||
makeShaderVS LayerQuadBlendMask3DVS
|
||||
makeShaderPS BlendShader
|
||||
|
||||
SRC=CompositorD3D11VR.hlsl
|
||||
|
||||
@@ -265,7 +265,7 @@ CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
|
||||
d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);
|
||||
|
||||
IntPoint origin = mCurrentRT->GetOrigin();
|
||||
float renderTargetOffset[] = { origin.x, origin.y, 0, 0 };
|
||||
float renderTargetOffset[] = { float(origin.x), float(origin.y), 0, 0 };
|
||||
d3d9Device->SetVertexShaderConstantF(CBvRenderTargetOffset,
|
||||
renderTargetOffset,
|
||||
1);
|
||||
@@ -291,11 +291,7 @@ CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
|
||||
MaskType maskType = MaskType::MaskNone;
|
||||
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
if (aTransform.Is2D()) {
|
||||
maskType = MaskType::Mask2d;
|
||||
} else {
|
||||
maskType = MaskType::Mask3d;
|
||||
}
|
||||
maskType = MaskType::Mask;
|
||||
}
|
||||
|
||||
gfx::Rect backdropDest;
|
||||
@@ -682,6 +678,7 @@ void
|
||||
CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const Rect *aClipRectIn,
|
||||
const Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
Rect *aClipRectOut,
|
||||
Rect *aRenderBoundsOut)
|
||||
{
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect *aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect *aClipRectOut = nullptr,
|
||||
gfx::Rect *aRenderBoundsOut = nullptr) override;
|
||||
|
||||
|
||||
@@ -424,13 +424,6 @@ DeviceManagerD3D9::Init()
|
||||
gfxCriticalError() << failCreateShaderMsg << "LayerQuadVSMask: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask3D,
|
||||
getter_AddRefs(mLayerVSMask3D));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg << "LayerQuadVSMask3D: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPSMask,
|
||||
getter_AddRefs(mRGBPSMask));
|
||||
@@ -448,14 +441,6 @@ DeviceManagerD3D9::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPSMask3D,
|
||||
getter_AddRefs(mRGBAPSMask3D));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg << "RGBAShaderPSMask3D: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mDevice->CreatePixelShader((DWORD*)ComponentPass1ShaderPSMask,
|
||||
getter_AddRefs(mComponentPass1PSMask));
|
||||
|
||||
@@ -625,13 +610,8 @@ DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, MaskType aMaskType)
|
||||
maskTexRegister = 1;
|
||||
break;
|
||||
case RGBALAYER:
|
||||
if (aMaskType == MaskType::Mask2d) {
|
||||
mDevice->SetVertexShader(mLayerVSMask);
|
||||
mDevice->SetPixelShader(mRGBAPSMask);
|
||||
} else {
|
||||
mDevice->SetVertexShader(mLayerVSMask3D);
|
||||
mDevice->SetPixelShader(mRGBAPSMask3D);
|
||||
}
|
||||
mDevice->SetVertexShader(mLayerVSMask);
|
||||
mDevice->SetPixelShader(mRGBAPSMask);
|
||||
maskTexRegister = 1;
|
||||
break;
|
||||
case COMPONENTLAYERPASS1:
|
||||
|
||||
@@ -272,10 +272,8 @@ private:
|
||||
|
||||
/* As above, but using a mask layer */
|
||||
RefPtr<IDirect3DVertexShader9> mLayerVSMask;
|
||||
RefPtr<IDirect3DVertexShader9> mLayerVSMask3D;
|
||||
RefPtr<IDirect3DPixelShader9> mRGBPSMask;
|
||||
RefPtr<IDirect3DPixelShader9> mRGBAPSMask;
|
||||
RefPtr<IDirect3DPixelShader9> mRGBAPSMask3D;
|
||||
RefPtr<IDirect3DPixelShader9> mComponentPass1PSMask;
|
||||
RefPtr<IDirect3DPixelShader9> mComponentPass2PSMask;
|
||||
RefPtr<IDirect3DPixelShader9> mYCbCrPSMask;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,12 +29,6 @@ struct VS_OUTPUT {
|
||||
};
|
||||
|
||||
struct VS_OUTPUT_MASK {
|
||||
float4 vPosition : POSITION;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float2 vMaskCoords : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT_MASK_3D {
|
||||
float4 vPosition : POSITION;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float3 vMaskCoords : TEXCOORD1;
|
||||
@@ -105,46 +99,7 @@ VS_OUTPUT_MASK LayerQuadVSMask(const VS_INPUT aVertex)
|
||||
// calculate the position on the mask texture
|
||||
outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
|
||||
outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
|
||||
|
||||
size = vTextureCoords.zw;
|
||||
outp.vTexCoords.x = vTextureCoords.x + aVertex.vPosition.x * size.x;
|
||||
outp.vTexCoords.y = vTextureCoords.y + aVertex.vPosition.y * size.y;
|
||||
|
||||
return outp;
|
||||
}
|
||||
|
||||
VS_OUTPUT_MASK_3D LayerQuadVSMask3D(const VS_INPUT aVertex)
|
||||
{
|
||||
VS_OUTPUT_MASK_3D outp;
|
||||
float4 position = float4(0, 0, 0, 1);
|
||||
|
||||
// We use 4 component floats to uniquely describe a rectangle, by the structure
|
||||
// of x, y, width, height. This allows us to easily generate the 4 corners
|
||||
// of any rectangle from the 4 corners of the 0,0-1,1 quad that we use as the
|
||||
// stream source for our LayerQuad vertex shader. We do this by doing:
|
||||
// Xout = x + Xin * width
|
||||
// Yout = y + Yin * height
|
||||
float2 size = vLayerQuad.zw;
|
||||
position.x = vLayerQuad.x + aVertex.vPosition.x * size.x;
|
||||
position.y = vLayerQuad.y + aVertex.vPosition.y * size.y;
|
||||
|
||||
position = mul(mLayerTransform, position);
|
||||
outp.vPosition.w = position.w;
|
||||
outp.vPosition.xyz = position.xyz / position.w;
|
||||
outp.vPosition = outp.vPosition - vRenderTargetOffset;
|
||||
outp.vPosition.xyz *= outp.vPosition.w;
|
||||
|
||||
// adjust our vertices to match d3d9's pixel coordinate system
|
||||
// which has pixel centers at integer locations
|
||||
outp.vPosition.xy -= 0.5;
|
||||
|
||||
outp.vPosition = mul(mProjection, outp.vPosition);
|
||||
|
||||
// calculate the position on the mask texture
|
||||
position.xyz /= position.w;
|
||||
outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
|
||||
outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
|
||||
// correct for perspective correct interpolation, see comment in D3D10 shader
|
||||
// correct for perspective correct interpolation, see comment in D3D11 shader
|
||||
outp.vMaskCoords.z = 1;
|
||||
outp.vMaskCoords *= position.w;
|
||||
|
||||
@@ -211,7 +166,7 @@ float4 ComponentPass1ShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
float4 src = tex2D(s2D, aVertex.vTexCoords);
|
||||
float4 alphas = 1.0 - tex2D(s2DWhite, aVertex.vTexCoords) + src;
|
||||
alphas.a = alphas.g;
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return alphas * fLayerOpacity * mask;
|
||||
}
|
||||
@@ -221,19 +176,12 @@ float4 ComponentPass2ShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
float4 src = tex2D(s2D, aVertex.vTexCoords);
|
||||
float4 alphas = 1.0 - tex2D(s2DWhite, aVertex.vTexCoords) + src;
|
||||
src.a = alphas.g;
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return src * fLayerOpacity * mask;
|
||||
}
|
||||
|
||||
float4 RGBAShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return tex2D(s2D, aVertex.vTexCoords) * fLayerOpacity * mask;
|
||||
}
|
||||
|
||||
float4 RGBAShaderMask3D(const VS_OUTPUT_MASK_3D aVertex) : COLOR
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
@@ -245,7 +193,7 @@ float4 RGBShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
float4 result;
|
||||
result = tex2D(s2D, aVertex.vTexCoords);
|
||||
result.a = 1.0;
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return result * fLayerOpacity * mask;
|
||||
}
|
||||
@@ -274,14 +222,14 @@ float4 YCbCrShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
color.b = yuv.g * 1.16438 + yuv.b * 2.01723;
|
||||
color.a = 1.0f;
|
||||
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return color * fLayerOpacity * mask;
|
||||
}
|
||||
|
||||
float4 SolidColorShaderMask(const VS_OUTPUT_MASK aVertex) : COLOR
|
||||
{
|
||||
float2 maskCoords = aVertex.vMaskCoords;
|
||||
float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
|
||||
float mask = tex2D(s2DMask, maskCoords).a;
|
||||
return fLayerColor * mask;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,8 @@ fxc LayerManagerD3D9Shaders.hlsl -ESolidColorShader -nologo -Tps_2_0 -Fh$tempfil
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -ELayerQuadVSMask -nologo -Fh$tempfile -VnLayerQuadVSMask
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -ELayerQuadVSMask3D -nologo -Fh$tempfile -VnLayerQuadVSMask3D
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -ERGBAShaderMask -nologo -Tps_2_0 -Fh$tempfile -VnRGBAShaderPSMask
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -ERGBAShaderMask3D -nologo -Tps_2_0 -Fh$tempfile -VnRGBAShaderPSMask3D
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -EComponentPass1ShaderMask -nologo -Tps_2_0 -Fh$tempfile -VnComponentPass1ShaderPSMask
|
||||
cat $tempfile >> LayerManagerD3D9Shaders.h
|
||||
fxc LayerManagerD3D9Shaders.hlsl -EComponentPass2ShaderMask -nologo -Tps_2_0 -Fh$tempfile -VnComponentPass2ShaderPSMask
|
||||
|
||||
@@ -133,7 +133,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
MOZ_ASSERT(tex.get());
|
||||
compositable->RemoveTextureHost(tex);
|
||||
// send FenceHandle if present.
|
||||
SendFenceHandleIfPresent(op.textureParent(), compositable);
|
||||
SendFenceHandleIfPresent(op.textureParent());
|
||||
break;
|
||||
}
|
||||
case CompositableOperation::TOpRemoveTextureAsync: {
|
||||
@@ -150,8 +150,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
GetChildProcessId(),
|
||||
op.holderId(),
|
||||
op.transactionId(),
|
||||
op.textureParent(),
|
||||
compositable);
|
||||
op.textureParent());
|
||||
|
||||
// If the message is recievied via PLayerTransaction,
|
||||
// Send message back via PImageBridge.
|
||||
@@ -161,7 +160,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
op.transactionId()));
|
||||
} else {
|
||||
// send FenceHandle if present.
|
||||
SendFenceHandleIfPresent(op.textureParent(), compositable);
|
||||
SendFenceHandleIfPresent(op.textureParent());
|
||||
|
||||
ReplyRemoveTexture(OpReplyRemoveTexture(op.holderId(),
|
||||
op.transactionId()));
|
||||
|
||||
@@ -28,8 +28,7 @@ typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
|
||||
class CompositableParentManager : public ISurfaceAllocator
|
||||
{
|
||||
public:
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost) = 0;
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture) = 0;
|
||||
|
||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) = 0;
|
||||
|
||||
|
||||
@@ -447,25 +447,22 @@ ImageBridgeParent::ReplyRemoveTexture(base::ProcessId aChildProcessId,
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost)
|
||||
ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture)
|
||||
{
|
||||
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
|
||||
if (!texture) {
|
||||
if (!texture || !texture->NeedsFenceHandle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a ReleaseFence of CompositorOGL.
|
||||
if (aCompositableHost && aCompositableHost->GetCompositor()) {
|
||||
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
}
|
||||
FenceHandle fence = texture->GetCompositorReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
}
|
||||
|
||||
// Send a ReleaseFence that is set by HwcComposer2D.
|
||||
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
|
||||
// Send a ReleaseFence that is set to TextureHost by HwcComposer2D.
|
||||
fence = texture->GetAndResetReleaseFenceHandle();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
@@ -475,26 +472,23 @@ ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
void
|
||||
ImageBridgeParent::AppendDeliverFenceMessage(uint64_t aDestHolderId,
|
||||
uint64_t aTransactionId,
|
||||
PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost)
|
||||
PTextureParent* aTexture)
|
||||
{
|
||||
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
|
||||
if (!texture) {
|
||||
if (!texture || !texture->NeedsFenceHandle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a ReleaseFence of CompositorOGL.
|
||||
if (aCompositableHost && aCompositableHost->GetCompositor()) {
|
||||
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(aDestHolderId,
|
||||
aTransactionId,
|
||||
fence));
|
||||
}
|
||||
FenceHandle fence = texture->GetCompositorReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(aDestHolderId,
|
||||
aTransactionId,
|
||||
fence));
|
||||
}
|
||||
|
||||
// Send a ReleaseFence that is set by HwcComposer2D.
|
||||
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
|
||||
// Send a ReleaseFence that is set to TextureHost by HwcComposer2D.
|
||||
fence = texture->GetAndResetReleaseFenceHandle();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(aDestHolderId,
|
||||
aTransactionId,
|
||||
@@ -506,8 +500,7 @@ ImageBridgeParent::AppendDeliverFenceMessage(uint64_t aDestHolderId,
|
||||
ImageBridgeParent::AppendDeliverFenceMessage(base::ProcessId aChildProcessId,
|
||||
uint64_t aDestHolderId,
|
||||
uint64_t aTransactionId,
|
||||
PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost)
|
||||
PTextureParent* aTexture)
|
||||
{
|
||||
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
|
||||
if (!imageBridge) {
|
||||
@@ -515,8 +508,7 @@ ImageBridgeParent::AppendDeliverFenceMessage(base::ProcessId aChildProcessId,
|
||||
}
|
||||
imageBridge->AppendDeliverFenceMessage(aDestHolderId,
|
||||
aTransactionId,
|
||||
aTexture,
|
||||
aCompositableHost);
|
||||
aTexture);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
|
||||
@@ -59,8 +59,7 @@ public:
|
||||
Create(Transport* aTransport, ProcessId aChildProcessId);
|
||||
|
||||
// CompositableParentManager
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost) override;
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture) override;
|
||||
|
||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
|
||||
|
||||
@@ -121,14 +120,12 @@ public:
|
||||
|
||||
void AppendDeliverFenceMessage(uint64_t aDestHolderId,
|
||||
uint64_t aTransactionId,
|
||||
PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost);
|
||||
PTextureParent* aTexture);
|
||||
|
||||
static void AppendDeliverFenceMessage(base::ProcessId aChildProcessId,
|
||||
uint64_t aDestHolderId,
|
||||
uint64_t aTransactionId,
|
||||
PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost);
|
||||
PTextureParent* aTexture);
|
||||
|
||||
using CompositableParentManager::SendPendingAsyncMessages;
|
||||
static void SendPendingAsyncMessages(base::ProcessId aChildProcessId);
|
||||
|
||||
@@ -19,11 +19,12 @@ namespace mozilla {
|
||||
|
||||
namespace layout {
|
||||
class RenderFrameChild;
|
||||
class ShadowLayerForwarder;
|
||||
} // namespace layout
|
||||
|
||||
namespace layers {
|
||||
|
||||
class ShadowLayerForwarder;
|
||||
|
||||
class LayerTransactionChild : public PLayerTransactionChild
|
||||
, public AsyncTransactionTrackersHolder
|
||||
{
|
||||
|
||||
@@ -798,6 +798,25 @@ GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTransactionParent::RecvUpdateScrollOffset(
|
||||
const FrameMetrics::ViewID& aScrollID,
|
||||
const uint32_t& aScrollGeneration,
|
||||
const CSSPoint& aScrollOffset)
|
||||
{
|
||||
if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
controller->NotifyScrollUpdated(aScrollGeneration, aScrollOffset);
|
||||
mShadowLayersManager->ForceComposite(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
|
||||
const float& aX, const float& aY)
|
||||
@@ -983,8 +1002,7 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
|
||||
GetChildProcessId(),
|
||||
op.holderId(),
|
||||
op.transactionId(),
|
||||
op.textureParent(),
|
||||
compositable);
|
||||
op.textureParent());
|
||||
// Send message back via PImageBridge.
|
||||
ImageBridgeParent::ReplyRemoveTexture(
|
||||
GetChildProcessId(),
|
||||
@@ -1046,25 +1064,22 @@ bool LayerTransactionParent::IsSameProcess() const
|
||||
}
|
||||
|
||||
void
|
||||
LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost)
|
||||
LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture)
|
||||
{
|
||||
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
|
||||
if (!texture) {
|
||||
if (!texture || !texture->NeedsFenceHandle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a ReleaseFence of CompositorOGL.
|
||||
if (aCompositableHost && aCompositableHost->GetCompositor()) {
|
||||
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
}
|
||||
FenceHandle fence = texture->GetCompositorReleaseFence();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
}
|
||||
|
||||
// Send a ReleaseFence that is set by HwcComposer2D.
|
||||
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
|
||||
// Send a ReleaseFence that is set to TextureHost by HwcComposer2D.
|
||||
fence = texture->GetAndResetReleaseFenceHandle();
|
||||
if (fence.IsValid()) {
|
||||
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
|
||||
fence));
|
||||
|
||||
@@ -80,8 +80,7 @@ public:
|
||||
void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
|
||||
|
||||
// CompositableParentManager
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
|
||||
CompositableHost* aCompositableHost) override;
|
||||
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture) override;
|
||||
|
||||
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
|
||||
|
||||
@@ -131,6 +130,9 @@ protected:
|
||||
virtual bool RecvGetAnimationTransform(PLayerParent* aParent,
|
||||
MaybeTransform* aTransform)
|
||||
override;
|
||||
virtual bool RecvUpdateScrollOffset(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration,
|
||||
const CSSPoint& aScrollOffset) override;
|
||||
virtual bool RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aId,
|
||||
const float& aX, const float& aY) override;
|
||||
virtual bool RecvSetAsyncZoom(const FrameMetrics::ViewID& aId,
|
||||
|
||||
@@ -22,6 +22,7 @@ using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
|
||||
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
|
||||
using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
|
||||
using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::CSSPoint from "Units.h";
|
||||
|
||||
/**
|
||||
* The layers protocol is spoken between thread contexts that manage
|
||||
@@ -89,6 +90,10 @@ parent:
|
||||
// be void_t.
|
||||
sync GetAnimationTransform(PLayer layer) returns (MaybeTransform transform);
|
||||
|
||||
// Updates the scroll offset and generation counter on the APZC for the
|
||||
// given scroll id.
|
||||
sync UpdateScrollOffset(ViewID id, uint32_t generation, CSSPoint offset);
|
||||
|
||||
// The next time the layer tree is composited, add this async scroll offset in
|
||||
// CSS pixels for the given ViewID.
|
||||
// Useful for testing rendering of async scrolling.
|
||||
|
||||
@@ -259,6 +259,7 @@ UNIFIED_SOURCES += [
|
||||
'apz/src/AsyncPanZoomController.cpp',
|
||||
'apz/src/Axis.cpp',
|
||||
'apz/src/CheckerboardEvent.cpp',
|
||||
'apz/src/DragTracker.cpp',
|
||||
'apz/src/GestureEventListener.cpp',
|
||||
'apz/src/HitTestingTreeNode.cpp',
|
||||
'apz/src/InputBlockState.cpp',
|
||||
|
||||
@@ -629,6 +629,7 @@ void
|
||||
CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const Rect *aClipRectIn,
|
||||
const Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
Rect *aClipRectOut,
|
||||
Rect *aRenderBoundsOut)
|
||||
{
|
||||
@@ -878,8 +879,7 @@ CompositorOGL::GetShaderConfigFor(Effect *aEffect,
|
||||
}
|
||||
}
|
||||
config.SetColorMatrix(aColorMatrix);
|
||||
config.SetMask2D(aMask == MaskType::Mask2d);
|
||||
config.SetMask3D(aMask == MaskType::Mask3d);
|
||||
config.SetMask(aMask == MaskType::Mask);
|
||||
config.SetDEAA(aDEAAEnabled);
|
||||
config.SetCompositionOp(aOp);
|
||||
return config;
|
||||
@@ -1069,9 +1069,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
maskQuadTransform._41 = float(-bounds.x)/bounds.width;
|
||||
maskQuadTransform._42 = float(-bounds.y)/bounds.height;
|
||||
|
||||
maskType = effectMask->mIs3D
|
||||
? MaskType::Mask3d
|
||||
: MaskType::Mask2d;
|
||||
maskType = MaskType::Mask;
|
||||
} else {
|
||||
maskType = MaskType::MaskNone;
|
||||
}
|
||||
|
||||
@@ -401,6 +401,7 @@ private:
|
||||
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
const gfx::Rect *aClipRectIn,
|
||||
const gfx::Rect& aRenderBounds,
|
||||
bool aOpaque,
|
||||
gfx::Rect *aClipRectOut = nullptr,
|
||||
gfx::Rect *aRenderBoundsOut = nullptr) override;
|
||||
|
||||
|
||||
@@ -466,5 +466,15 @@ GrallocTextureHostOGL::BindTextureSource(CompositableTextureSourceRef& aTextureS
|
||||
return true;
|
||||
}
|
||||
|
||||
FenceHandle
|
||||
GrallocTextureHostOGL::GetCompositorReleaseFence()
|
||||
{
|
||||
if (!mCompositor) {
|
||||
return FenceHandle();
|
||||
}
|
||||
return mCompositor->GetReleaseFence();
|
||||
}
|
||||
|
||||
|
||||
} // namepsace layers
|
||||
} // namepsace mozilla
|
||||
|
||||
@@ -60,6 +60,17 @@ public:
|
||||
|
||||
gl::GLContext* GetGLContext() const { return mCompositor ? mCompositor->gl() : nullptr; }
|
||||
|
||||
virtual bool NeedsFenceHandle() override
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual FenceHandle GetCompositorReleaseFence() override;
|
||||
|
||||
private:
|
||||
void DestroyEGLImage();
|
||||
|
||||
|
||||
@@ -139,15 +139,9 @@ ShaderConfigOGL::SetBlur(bool aEnabled)
|
||||
}
|
||||
|
||||
void
|
||||
ShaderConfigOGL::SetMask2D(bool aEnabled)
|
||||
ShaderConfigOGL::SetMask(bool aEnabled)
|
||||
{
|
||||
SetFeature(ENABLE_MASK_2D, aEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
ShaderConfigOGL::SetMask3D(bool aEnabled)
|
||||
{
|
||||
SetFeature(ENABLE_MASK_3D, aEnabled);
|
||||
SetFeature(ENABLE_MASK, aEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -206,8 +200,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
vs << "varying vec2 vBackdropCoord;" << endl;
|
||||
}
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
if (aConfig.mFeatures & ENABLE_MASK) {
|
||||
vs << "uniform mat4 uMaskTransform;" << endl;
|
||||
vs << "varying vec3 vMaskCoord;" << endl;
|
||||
}
|
||||
@@ -232,8 +225,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
vs << " ssPos = uMatrixProj * ssPos;" << endl;
|
||||
vs << " ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D ||
|
||||
if (aConfig.mFeatures & ENABLE_MASK ||
|
||||
!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
|
||||
vs << " vec4 coordAdjusted;" << endl;
|
||||
vs << " coordAdjusted.xy = aCoord.xy;" << endl;
|
||||
@@ -278,14 +270,11 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
|
||||
vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
if (aConfig.mFeatures & ENABLE_MASK) {
|
||||
vs << " vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
|
||||
if (aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
// correct for perspective correct interpolation, see comment in D3D10 shader
|
||||
vs << " vMaskCoord.z = 1.0;" << endl;
|
||||
vs << " vMaskCoord *= finalPosition.w;" << endl;
|
||||
}
|
||||
// correct for perspective correct interpolation, see comment in D3D11 shader
|
||||
vs << " vMaskCoord.z = 1.0;" << endl;
|
||||
vs << " vMaskCoord *= finalPosition.w;" << endl;
|
||||
}
|
||||
vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
|
||||
vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
|
||||
@@ -376,8 +365,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||
fs << "uniform sampler2D uBackdropTexture;" << endl;
|
||||
}
|
||||
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
if (aConfig.mFeatures & ENABLE_MASK) {
|
||||
fs << "varying vec3 vMaskCoord;" << endl;
|
||||
fs << "uniform sampler2D uMaskTexture;" << endl;
|
||||
}
|
||||
@@ -512,13 +500,10 @@ For [0,1] instead of [0,255], and to 5 places:
|
||||
fs << " vec4 backdrop = texture2D(uBackdropTexture, vBackdropCoord);" << endl;
|
||||
fs << " color = mixAndBlend(backdrop, color);" << endl;
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
if (aConfig.mFeatures & ENABLE_MASK) {
|
||||
fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
|
||||
fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;
|
||||
fs << " color *= mask;" << endl;
|
||||
} else if (aConfig.mFeatures & ENABLE_MASK_2D) {
|
||||
fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, vMaskCoord.xy).r;" << endl;
|
||||
fs << " color *= mask;" << endl;
|
||||
} else {
|
||||
fs << " COLOR_PRECISION float mask = 1.0;" << endl;
|
||||
fs << " color *= mask;" << endl;
|
||||
@@ -542,8 +527,7 @@ For [0,1] instead of [0,255], and to 5 places:
|
||||
result.mTextureCount = 1;
|
||||
}
|
||||
}
|
||||
if (aConfig.mFeatures & ENABLE_MASK_2D ||
|
||||
aConfig.mFeatures & ENABLE_MASK_3D) {
|
||||
if (aConfig.mFeatures & ENABLE_MASK) {
|
||||
result.mTextureCount = 1;
|
||||
}
|
||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||
|
||||
@@ -37,10 +37,9 @@ enum ShaderFeatures {
|
||||
ENABLE_OPACITY=0x100,
|
||||
ENABLE_BLUR=0x200,
|
||||
ENABLE_COLOR_MATRIX=0x400,
|
||||
ENABLE_MASK_2D=0x800,
|
||||
ENABLE_MASK_3D=0x1000,
|
||||
ENABLE_NO_PREMUL_ALPHA=0x2000,
|
||||
ENABLE_DEAA=0x4000
|
||||
ENABLE_MASK=0x800,
|
||||
ENABLE_NO_PREMUL_ALPHA=0x1000,
|
||||
ENABLE_DEAA=0x2000
|
||||
};
|
||||
|
||||
class KnownUniform {
|
||||
@@ -223,8 +222,7 @@ public:
|
||||
void SetComponentAlpha(bool aEnabled);
|
||||
void SetColorMatrix(bool aEnabled);
|
||||
void SetBlur(bool aEnabled);
|
||||
void SetMask2D(bool aEnabled);
|
||||
void SetMask3D(bool aEnabled);
|
||||
void SetMask(bool aEnabled);
|
||||
void SetDEAA(bool aEnabled);
|
||||
void SetCompositionOp(gfx::CompositionOp aOp);
|
||||
void SetNoPremultipliedAlpha();
|
||||
|
||||
@@ -285,6 +285,8 @@ public:
|
||||
|
||||
protected:
|
||||
friend class nsICODecoder;
|
||||
friend class PalettedSurfaceSink;
|
||||
friend class SurfaceSink;
|
||||
|
||||
virtual ~Decoder();
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
|
||||
#include "Downscaler.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
Deinterlacer::Deinterlacer(const nsIntSize& aImageSize)
|
||||
: mImageSize(aImageSize)
|
||||
{
|
||||
CheckedInt<size_t> bufferSize = mImageSize.width;
|
||||
bufferSize *= mImageSize.height;
|
||||
bufferSize *= sizeof(uint32_t);
|
||||
|
||||
if (!bufferSize.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBuffer = MakeUniqueFallible<uint8_t[]>(bufferSize.value());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Deinterlacer::RowSize() const
|
||||
{
|
||||
return mImageSize.width * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
Deinterlacer::RowBuffer(uint32_t aRow)
|
||||
{
|
||||
uint32_t offset = aRow * RowSize();
|
||||
MOZ_ASSERT(IsValid(), "Deinterlacer in invalid state");
|
||||
MOZ_ASSERT(offset < mImageSize.width * mImageSize.height * sizeof(uint32_t),
|
||||
"Row is outside of image");
|
||||
return mBuffer.get() + offset;
|
||||
}
|
||||
|
||||
void
|
||||
Deinterlacer::PropagatePassToDownscaler(Downscaler& aDownscaler)
|
||||
{
|
||||
MOZ_ASSERT(IsValid(), "Deinterlacer in invalid state");
|
||||
for (int32_t row = 0 ; row < mImageSize.height ; ++row) {
|
||||
memcpy(aDownscaler.RowBuffer(), RowBuffer(row), RowSize());
|
||||
aDownscaler.CommitRow();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user