зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1907868 - Optimize nsQueryFrame for all final frame types and ScrollContainerFrame. r=tnikkel,layout-reviewers,TYLin
Differential Revision: https://phabricator.services.mozilla.com/D216682
This commit is contained in:
Родитель
5249c141dd
Коммит
0f21b97fe0
|
@ -1261,12 +1261,7 @@ nsMapRuleToAttributesFunc HTMLSelectElement::GetAttributeMappingFunction()
|
|||
}
|
||||
|
||||
bool HTMLSelectElement::IsDisabledForEvents(WidgetEvent* aEvent) {
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
||||
nsIFrame* formFrame = nullptr;
|
||||
if (formControlFrame) {
|
||||
formFrame = do_QueryFrame(formControlFrame);
|
||||
}
|
||||
return IsElementDisabledForEvents(aEvent, formFrame);
|
||||
return IsElementDisabledForEvents(aEvent, GetPrimaryFrame());
|
||||
}
|
||||
|
||||
void HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||
|
@ -1479,10 +1474,8 @@ HTMLSelectElement::SubmitNamesValues(FormData* aFormData) {
|
|||
}
|
||||
|
||||
void HTMLSelectElement::DispatchContentReset() {
|
||||
if (nsIFormControlFrame* formControlFrame = GetFormControlFrame(false)) {
|
||||
if (nsListControlFrame* listFrame = do_QueryFrame(formControlFrame)) {
|
||||
listFrame->OnContentReset();
|
||||
}
|
||||
if (nsListControlFrame* listFrame = do_QueryFrame(GetPrimaryFrame())) {
|
||||
listFrame->OnContentReset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1630,8 +1623,7 @@ void HTMLSelectElement::SetUserInteracted(bool aInteracted) {
|
|||
void HTMLSelectElement::SetPreviewValue(const nsAString& aValue) {
|
||||
mPreviewValue = aValue;
|
||||
nsContentUtils::RemoveNewlines(mPreviewValue);
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
||||
nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
|
||||
nsComboboxControlFrame* comboFrame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (comboFrame) {
|
||||
comboFrame->RedisplaySelectedText();
|
||||
}
|
||||
|
|
|
@ -100,8 +100,7 @@ ScrollbarActivity::HandleEvent(dom::Event* aEvent) {
|
|||
// of our scroll frame) and we don't want those to activate us.
|
||||
nsIFrame* scrollFrame = do_QueryFrame(mScrollableFrame);
|
||||
MOZ_ASSERT(scrollFrame);
|
||||
ScrollContainerFrame* scrollContainerFrame =
|
||||
do_QueryFrame(mScrollableFrame);
|
||||
ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(scrollFrame);
|
||||
nsCOMPtr<nsIContent> targetContent =
|
||||
do_QueryInterface(aEvent->GetOriginalTarget());
|
||||
nsIFrame* targetFrame =
|
||||
|
|
|
@ -8124,8 +8124,7 @@ bool nsIFrame::IsImageFrameOrSubclass() const {
|
|||
|
||||
bool nsIFrame::IsScrollContainerOrSubclass() const {
|
||||
const bool result = IsScrollContainerFrame() || IsListControlFrame();
|
||||
MOZ_ASSERT(result ==
|
||||
!!static_cast<const ScrollContainerFrame*>(do_QueryFrame(this)));
|
||||
MOZ_ASSERT(result == !!QueryFrame(ScrollContainerFrame::kFrameIID));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
#include "nscore.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
// NOTE: the long lines in this file are intentional to make compiler error
|
||||
// messages more readable.
|
||||
namespace mozilla {
|
||||
class ScrollContainerFrame;
|
||||
}
|
||||
|
||||
#define NS_DECL_QUERYFRAME_TARGET(classname) \
|
||||
static const nsQueryFrame::FrameIID kFrameIID = \
|
||||
|
@ -85,18 +86,18 @@ class nsQueryFrame {
|
|||
|
||||
class nsIFrame;
|
||||
|
||||
template <class Source>
|
||||
template <typename Source>
|
||||
class do_QueryFrameHelper {
|
||||
public:
|
||||
explicit do_QueryFrameHelper(Source* s) : mRawPtr(s) {}
|
||||
|
||||
// The return and argument types here are arbitrarily selected so no
|
||||
// corresponding member function exists.
|
||||
typedef void (do_QueryFrameHelper::*MatchNullptr)(double, float);
|
||||
using MatchNullptr = void (*)(double, float);
|
||||
// Implicit constructor for nullptr, trick borrowed from already_AddRefed.
|
||||
MOZ_IMPLICIT do_QueryFrameHelper(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
|
||||
|
||||
template <class Dest>
|
||||
template <typename Dest>
|
||||
operator Dest*() {
|
||||
static_assert(std::is_same_v<std::remove_const_t<Dest>,
|
||||
typename Dest::Has_NS_DECL_QUERYFRAME_TARGET>,
|
||||
|
@ -104,40 +105,71 @@ class do_QueryFrameHelper {
|
|||
if (!mRawPtr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (Dest* f = FastQueryFrame<Source, Dest>::QueryFrame(mRawPtr)) {
|
||||
if constexpr (FastQueryFrame<Dest>::kSupported) {
|
||||
static_assert(
|
||||
std::is_base_of_v<nsIFrame, Source>,
|
||||
"We only support fast do_QueryFrame() where the source must be a "
|
||||
"derived class of nsIFrame. Consider a two-step do_QueryFrame() "
|
||||
"(once to nsIFrame, another to the target) if absolutely needed.");
|
||||
Dest* f = FastQueryFrame<Dest>::QueryFrame(mRawPtr);
|
||||
MOZ_ASSERT(
|
||||
f == reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID)),
|
||||
"fast and slow paths should give the same result");
|
||||
return f;
|
||||
}
|
||||
if constexpr (std::is_base_of_v<nsIFrame, Source> &&
|
||||
std::is_base_of_v<nsIFrame, Dest>) {
|
||||
// For non-final frames we can still optimize the virtual call some of the
|
||||
// time.
|
||||
if (nsQueryFrame::FrameIID(mRawPtr->mClass) == Dest::kFrameIID) {
|
||||
auto* f = static_cast<Dest*>(mRawPtr);
|
||||
MOZ_ASSERT(
|
||||
f == reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID)),
|
||||
"fast and slow paths should give the same result");
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return reinterpret_cast<Dest*>(mRawPtr->QueryFrame(Dest::kFrameIID));
|
||||
}
|
||||
|
||||
private:
|
||||
// For non-nsIFrame types there is no fast-path.
|
||||
template <class Src, class Dst, typename = void, typename = void>
|
||||
template <typename Dest, typename = void>
|
||||
struct FastQueryFrame {
|
||||
static Dst* QueryFrame(Src* aFrame) { return nullptr; }
|
||||
static constexpr bool kSupported = false;
|
||||
};
|
||||
|
||||
// Specialization for any nsIFrame type to any nsIFrame type -- if the source
|
||||
// instance's mClass matches kFrameIID of the destination type then
|
||||
// downcasting is safe.
|
||||
template <class Src, class Dst>
|
||||
struct FastQueryFrame<
|
||||
Src, Dst, std::enable_if_t<std::is_base_of<nsIFrame, Src>::value>,
|
||||
std::enable_if_t<std::is_base_of<nsIFrame, Dst>::value>> {
|
||||
static Dst* QueryFrame(Src* aFrame) {
|
||||
return nsQueryFrame::FrameIID(aFrame->mClass) == Dst::kFrameIID
|
||||
? reinterpret_cast<Dst*>(aFrame)
|
||||
// For final classes we can check the class id.
|
||||
template <typename Dest>
|
||||
struct FastQueryFrame<Dest, std::enable_if_t<std::is_final_v<Dest>, void>> {
|
||||
static constexpr bool kSupported = true;
|
||||
|
||||
template <typename Src>
|
||||
static Dest* QueryFrame(Src* aPtr) {
|
||||
return nsQueryFrame::FrameIID(aPtr->mClass) == Dest::kFrameIID
|
||||
? static_cast<Dest*>(aPtr)
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#define IMPL_FAST_QUERYFRAME(Dest_, Check_) \
|
||||
template <> \
|
||||
struct FastQueryFrame<Dest_, void> { \
|
||||
static constexpr bool kSupported = true; \
|
||||
template <typename Src> \
|
||||
static Dest_* QueryFrame(Src* aPtr) { \
|
||||
return aPtr->Check_() ? static_cast<Dest_*>(aPtr) : nullptr; \
|
||||
} \
|
||||
}
|
||||
|
||||
IMPL_FAST_QUERYFRAME(mozilla::ScrollContainerFrame,
|
||||
IsScrollContainerOrSubclass);
|
||||
|
||||
#undef IMPL_FAST_QUERYFRAME
|
||||
|
||||
Source* mRawPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
inline do_QueryFrameHelper<T> do_QueryFrame(T* s) {
|
||||
return do_QueryFrameHelper<T>(s);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ NS_IMPL_FRAMEARENA_HELPERS(SVGClipPathFrame)
|
|||
void SVGClipPathFrame::ApplyClipPath(gfxContext& aContext,
|
||||
nsIFrame* aClippedFrame,
|
||||
const gfxMatrix& aMatrix) {
|
||||
ISVGDisplayableFrame* singleClipPathChild = nullptr;
|
||||
nsIFrame* singleClipPathChild = nullptr;
|
||||
DebugOnly<bool> trivial = IsTrivial(&singleClipPathChild);
|
||||
MOZ_ASSERT(trivial, "Caller needs to use GetClipMask");
|
||||
|
||||
|
@ -297,7 +297,7 @@ bool SVGClipPathFrame::PointIsInsideClipPath(nsIFrame* aClippedFrame,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SVGClipPathFrame::IsTrivial(ISVGDisplayableFrame** aSingleChild) {
|
||||
bool SVGClipPathFrame::IsTrivial(nsIFrame** aSingleChild) {
|
||||
// If the clip path is clipped then it's non-trivial
|
||||
if (SVGObserverUtils::GetAndObserveClipPath(this, nullptr) ==
|
||||
SVGObserverUtils::eHasRefsAllValid) {
|
||||
|
@ -308,25 +308,25 @@ bool SVGClipPathFrame::IsTrivial(ISVGDisplayableFrame** aSingleChild) {
|
|||
*aSingleChild = nullptr;
|
||||
}
|
||||
|
||||
ISVGDisplayableFrame* foundChild = nullptr;
|
||||
|
||||
nsIFrame* foundChild = nullptr;
|
||||
for (auto* kid : mFrames) {
|
||||
ISVGDisplayableFrame* svgChild = do_QueryFrame(kid);
|
||||
if (svgChild) {
|
||||
// We consider a non-trivial clipPath to be one containing
|
||||
// either more than one svg child and/or a svg container
|
||||
if (foundChild || svgChild->IsDisplayContainer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// or where the child is itself clipped
|
||||
if (SVGObserverUtils::GetAndObserveClipPath(kid, nullptr) ==
|
||||
SVGObserverUtils::eHasRefsAllValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foundChild = svgChild;
|
||||
if (!svgChild) {
|
||||
continue;
|
||||
}
|
||||
// We consider a non-trivial clipPath to be one containing
|
||||
// either more than one svg child and/or a svg container
|
||||
if (foundChild || svgChild->IsDisplayContainer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// or where the child is itself clipped
|
||||
if (SVGObserverUtils::GetAndObserveClipPath(kid, nullptr) ==
|
||||
SVGObserverUtils::eHasRefsAllValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foundChild = kid;
|
||||
}
|
||||
if (aSingleChild) {
|
||||
*aSingleChild = foundChild;
|
||||
|
|
|
@ -109,7 +109,7 @@ class SVGClipPathFrame final : public SVGContainerFrame {
|
|||
// Check if this clipPath is made up of more than one geometry object.
|
||||
// If so, the clipping API in cairo isn't enough and we need to use
|
||||
// mask based clipping.
|
||||
bool IsTrivial(ISVGDisplayableFrame** aSingleChild = nullptr);
|
||||
bool IsTrivial(nsIFrame** aSingleChild = nullptr);
|
||||
|
||||
// nsIFrame interface:
|
||||
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||
|
|
|
@ -408,7 +408,12 @@ static bool UsesCustomScrollbarMediator(nsIFrame* scrollbarBox) {
|
|||
if (nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox)) {
|
||||
if (nsIScrollbarMediator* mediator =
|
||||
scrollbarFrame->GetScrollbarMediator()) {
|
||||
ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(mediator);
|
||||
// Note we can't queryframe from nsIScrollbarMediator to
|
||||
// ScrollContainerFrame directly due to an optimization in the queryframe
|
||||
// implementation for ScrollContainerFrame.
|
||||
nsIFrame* mediatorAsFrame = do_QueryFrame(mediator);
|
||||
ScrollContainerFrame* scrollContainerFrame =
|
||||
do_QueryFrame(mediatorAsFrame);
|
||||
// The scrollbar mediator is not the scroll container frame.
|
||||
// That means this scroll container frame has a custom scrollbar mediator.
|
||||
if (!scrollContainerFrame) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче