Bug 1710324 - Tweak dark background detection so that it works for XUL use cases. r=mstange

Two changes:

 * Make it work across document boundaries, so that it works on e.g., the
   bookmarks sidebar.

 * Don't bail out if there's no scrollable frame, as XUL <tree>s use raw
   <scrollbar> elements without any scrollframe (gnarly). In that case, just
   use the target frame, but make sure to skip over themed elements (like the
   scrollbars themselves) so that we can find the right background.

The logic to check the canvas frame background etcetera was simpler in
FindNonTransparentBackgroundFrame. The only caller other than the
scrollbar darkening code is nsTextFrame, which should find a non-canvas frame
before anyways, but it doesn't hurt there.

Differential Revision: https://phabricator.services.mozilla.com/D114697
This commit is contained in:
Emilio Cobos Álvarez 2021-05-11 13:57:18 +00:00
parent e7b4dad575
commit 4d41ec19c2
4 changed files with 69 additions and 70 deletions

View File

@ -4038,12 +4038,12 @@ void nsTextPaintStyle::InitCommonColors() {
return;
}
nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(mFrame);
NS_ASSERTION(bgFrame, "Cannot find NonTransparentBackgroundFrame.");
nscolor bgColor =
bgFrame->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
auto bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(mFrame);
nscolor defaultBgColor = mPresContext->DefaultBackgroundColor();
nscolor bgColor = bgFrame.mFrame ? bgFrame.mFrame->GetVisitedDependentColor(
&nsStyleBackground::mBackgroundColor)
: defaultBgColor;
mFrameBackgroundColor = NS_ComposeColors(defaultBgColor, bgColor);
mSystemFieldForegroundColor =
@ -4051,7 +4051,7 @@ void nsTextPaintStyle::InitCommonColors() {
mSystemFieldBackgroundColor =
LookAndFeel::Color(LookAndFeel::ColorID::Field, mFrame);
if (bgFrame->IsThemed()) {
if (bgFrame.mIsThemed) {
// Assume a native widget has sufficient contrast always
mSufficientContrast = 0;
mInitCommonColors = true;

View File

@ -1123,38 +1123,34 @@ void nsImageRenderer::ComputeObjectAnchorPoint(const Position& aPos,
aImageSize.height, &aTopLeft->y, &aAnchorPoint->y);
}
nsIFrame* nsCSSRendering::FindNonTransparentBackgroundFrame(
nsIFrame* aFrame, bool aStartAtParent /*= false*/) {
auto nsCSSRendering::FindNonTransparentBackgroundFrame(nsIFrame* aFrame,
bool aStopAtThemed)
-> NonTransparentBackgroundFrame {
NS_ASSERTION(aFrame,
"Cannot find NonTransparentBackgroundFrame in a null frame");
nsIFrame* frame = nullptr;
if (aStartAtParent) {
frame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
}
if (!frame) {
frame = aFrame;
}
while (frame) {
// No need to call GetVisitedDependentColor because it always uses
// this alpha component anyway.
if (NS_GET_A(frame->StyleBackground()->BackgroundColor(frame)) > 0) {
break;
for (nsIFrame* frame = aFrame; frame;
frame = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(frame)) {
// No need to call GetVisitedDependentColor because it always uses this
// alpha component anyway.
if (NS_GET_A(frame->StyleBackground()->BackgroundColor(frame))) {
return {frame, false, false};
}
if (frame->IsThemed()) {
break;
if (aStopAtThemed && frame->IsThemed()) {
return {frame, true, false};
}
nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
if (!parent) {
break;
if (IsCanvasFrame(frame)) {
nsIFrame* bgFrame = nullptr;
if (FindBackgroundFrame(frame, &bgFrame) &&
NS_GET_A(bgFrame->StyleBackground()->BackgroundColor(bgFrame))) {
return {bgFrame, false, true};
}
}
frame = parent;
}
return frame;
return {};
}
// Returns true if aFrame is a canvas frame.

View File

@ -331,16 +331,18 @@ struct nsCSSRendering {
}
/**
* Find a frame which draws a non-transparent background,
* for various table-related and HR-related backwards-compatibility hacks.
* This function will also stop if it finds themed frame which might draw
* background.
*
* Be very hesitant if you're considering calling this function -- it's
* usually not what you want.
* Find a frame which draws a non-transparent background, for various contrast
* checks. Note that this only accounts for background-color and might stop at
* themed frames (depending on the argument), so it might not be what you
* want.
*/
static nsIFrame* FindNonTransparentBackgroundFrame(
nsIFrame* aFrame, bool aStartAtParent = false);
struct NonTransparentBackgroundFrame {
nsIFrame* mFrame = nullptr;
bool mIsThemed = false;
bool mIsForCanvas = false;
};
static NonTransparentBackgroundFrame FindNonTransparentBackgroundFrame(
nsIFrame* aFrame, bool aStopAtThemed = true);
/**
* Determine the background color to draw taking into account print settings.

View File

@ -612,47 +612,48 @@ static nsIFrame* GetBodyFrame(nsIFrame* aCanvasFrame) {
return body->GetPrimaryFrame();
}
static const ComputedStyle* GetBackgroundStyle(nsIFrame* aFrame) {
if (nsCSSRendering::IsCanvasFrame(aFrame)) {
/* static */
bool nsNativeTheme::IsDarkBackground(nsIFrame* aFrame) {
// Try to find the scrolled frame. Note that for stuff like xul <tree> there
// might be none.
{
nsIFrame* frame = aFrame;
nsIScrollableFrame* scrollFrame = nullptr;
while (!scrollFrame && frame) {
scrollFrame = frame->GetScrollTargetFrame();
frame = frame->GetParent();
}
if (scrollFrame) {
aFrame = scrollFrame->GetScrolledFrame();
} else {
// Leave aFrame untouched.
}
}
auto backgroundFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(
aFrame, /* aStopAtThemed = */ false);
if (!backgroundFrame.mFrame) {
return false;
}
nscolor color = backgroundFrame.mFrame->StyleBackground()->BackgroundColor(
backgroundFrame.mFrame);
if (backgroundFrame.mIsForCanvas) {
// For canvas frames, prefer to look at the body first, because the body
// background color is most likely what will be visible as the background
// color of the page, even if the html element has a different background
// color which prevents that of the body frame to propagate to the viewport.
if (nsIFrame* bodyFrame = GetBodyFrame(aFrame)) {
if (!bodyFrame->StyleBackground()->IsTransparent(bodyFrame->Style())) {
return bodyFrame->Style();
nscolor bodyColor =
bodyFrame->StyleBackground()->BackgroundColor(bodyFrame);
if (NS_GET_A(bodyColor)) {
color = bodyColor;
}
}
}
ComputedStyle* bgSC = nullptr;
if (nsCSSRendering::FindBackground(aFrame, &bgSC) &&
!bgSC->StyleBackground()->IsTransparent(bgSC)) {
return bgSC;
}
nsIFrame* backgroundFrame =
nsCSSRendering::FindNonTransparentBackgroundFrame(aFrame, true);
if (!backgroundFrame) {
return nullptr;
}
return backgroundFrame->Style();
}
/* static */
bool nsNativeTheme::IsDarkBackground(nsIFrame* aFrame) {
nsIScrollableFrame* scrollFrame = nullptr;
while (!scrollFrame && aFrame) {
scrollFrame = aFrame->GetScrollTargetFrame();
aFrame = aFrame->GetParent();
}
if (!scrollFrame) {
return false;
}
if (const auto* style = GetBackgroundStyle(scrollFrame->GetScrolledFrame())) {
return IsDarkColor(style->StyleBackground()->BackgroundColor(style));
}
return false;
return IsDarkColor(color);
}
/*static*/