... if the group had hit test flags set. This is more of a workaround than a proper fix. The general idea is that if we hadn't made the item active, its bound would have included in the group's hit tested bounds. Making the item active reduces the area that is covered by hit test items and we don't want that. *** fixup Differential Revision: https://phabricator.services.mozilla.com/D143755
136 lines
4.7 KiB
C++
136 lines
4.7 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "HitTestInfoManager.h"
|
|
#include "HitTestInfo.h"
|
|
|
|
#include "nsDisplayList.h"
|
|
|
|
#define DEBUG_HITTEST_INFO 0
|
|
#if DEBUG_HITTEST_INFO
|
|
# define HITTEST_INFO_LOG(...) printf_stderr(__VA_ARGS__)
|
|
#else
|
|
# define HITTEST_INFO_LOG(...)
|
|
#endif
|
|
|
|
namespace mozilla::layers {
|
|
|
|
using ViewID = ScrollableLayerGuid::ViewID;
|
|
|
|
/**
|
|
* TODO(miko): This used to be a performance bottle-neck, but it does not show
|
|
* up in profiles anymore, see bugs 1424637 and 1424968.
|
|
* A better way of doing this would be to store current app units per dev pixel
|
|
* in wr::DisplayListBuilder, and update it whenever display items that separate
|
|
* presshell boundaries are encountered.
|
|
*/
|
|
static int32_t GetAppUnitsFromDisplayItem(nsDisplayItem* aItem) {
|
|
nsIFrame* frame = aItem->Frame();
|
|
MOZ_ASSERT(frame);
|
|
return frame->PresContext()->AppUnitsPerDevPixel();
|
|
}
|
|
|
|
static void CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
|
|
nsDisplayItem* aItem, const nsRect& aArea,
|
|
const gfx::CompositorHitTestInfo& aFlags,
|
|
const ViewID& aViewId) {
|
|
const Maybe<SideBits> sideBits =
|
|
aBuilder.GetContainingFixedPosSideBits(aItem->GetActiveScrolledRoot());
|
|
|
|
const LayoutDeviceRect devRect =
|
|
LayoutDeviceRect::FromAppUnits(aArea, GetAppUnitsFromDisplayItem(aItem));
|
|
const wr::LayoutRect rect = wr::ToLayoutRect(devRect);
|
|
|
|
aBuilder.PushHitTest(rect, rect, !aItem->BackfaceIsHidden(), aViewId, aFlags,
|
|
sideBits.valueOr(SideBits::eNone));
|
|
}
|
|
|
|
HitTestInfoManager::HitTestInfoManager()
|
|
: mArea(nsRect()),
|
|
mFlags(gfx::CompositorHitTestInvisibleToHit),
|
|
mViewId(ScrollableLayerGuid::NULL_SCROLL_ID),
|
|
mSpaceAndClipChain(wr::InvalidScrollNodeWithChain()) {}
|
|
|
|
void HitTestInfoManager::Reset() {
|
|
mArea = nsRect();
|
|
mFlags = gfx::CompositorHitTestInvisibleToHit;
|
|
mViewId = ScrollableLayerGuid::NULL_SCROLL_ID;
|
|
mSpaceAndClipChain = wr::InvalidScrollNodeWithChain();
|
|
|
|
HITTEST_INFO_LOG("* HitTestInfoManager::Reset\n");
|
|
}
|
|
|
|
bool HitTestInfoManager::ProcessItem(
|
|
nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
|
|
nsDisplayListBuilder* aDisplayListBuilder) {
|
|
MOZ_ASSERT(aItem);
|
|
|
|
HITTEST_INFO_LOG("* HitTestInfoManager::ProcessItem(%d, %s, has=%d)\n",
|
|
getpid(), aItem->Frame()->ListTag().get(),
|
|
aItem->HasHitTestInfo());
|
|
|
|
if (MOZ_UNLIKELY(aItem->GetType() == DisplayItemType::TYPE_REMOTE)) {
|
|
// Remote frames might contain hit-test-info items inside (but those
|
|
// aren't processed by this process of course), so we can't optimize out the
|
|
// next hit-test info item because it might be on top of the iframe.
|
|
Reset();
|
|
}
|
|
|
|
if (!aItem->HasHitTestInfo()) {
|
|
return false;
|
|
}
|
|
|
|
const HitTestInfo& hitTestInfo = aItem->GetHitTestInfo();
|
|
const nsRect& area = hitTestInfo.Area();
|
|
const gfx::CompositorHitTestInfo& flags = hitTestInfo.Info();
|
|
|
|
if (flags == gfx::CompositorHitTestInvisibleToHit || area.IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
const auto viewId =
|
|
hitTestInfo.GetViewId(aBuilder, aItem->GetActiveScrolledRoot());
|
|
const auto spaceAndClipChain = aBuilder.CurrentSpaceAndClipChain();
|
|
|
|
if (!Update(area, flags, viewId, spaceAndClipChain)) {
|
|
// The previous hit test information is still valid.
|
|
return false;
|
|
}
|
|
|
|
HITTEST_INFO_LOG("+ [%d, %d, %d, %d]: flags: 0x%x, viewId: %lu\n", area.x,
|
|
area.y, area.width, area.height, flags.serialize(), viewId);
|
|
|
|
CreateWebRenderCommands(aBuilder, aItem, area, flags, viewId);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Updates the current hit testing information if necessary.
|
|
* Returns true if the hit testing information was changed.
|
|
*/
|
|
bool HitTestInfoManager::Update(const nsRect& aArea,
|
|
const gfx::CompositorHitTestInfo& aFlags,
|
|
const ViewID& aViewId,
|
|
const wr::WrSpaceAndClipChain& aSpaceAndClip) {
|
|
if (mViewId == aViewId && mFlags == aFlags && mArea.Contains(aArea) &&
|
|
mSpaceAndClipChain == aSpaceAndClip) {
|
|
// The previous hit testing information can be reused.
|
|
HITTEST_INFO_LOG("s [%d, %d, %d, %d]: flags: 0x%x, viewId: %lu\n", aArea.x,
|
|
aArea.y, aArea.width, aArea.height, aFlags.serialize(),
|
|
aViewId);
|
|
return false;
|
|
}
|
|
|
|
mArea = aArea;
|
|
mFlags = aFlags;
|
|
mViewId = aViewId;
|
|
mSpaceAndClipChain = aSpaceAndClip;
|
|
return true;
|
|
}
|
|
|
|
} // namespace mozilla::layers
|