зеркало из https://github.com/mozilla/gecko-dev.git
593 строки
20 KiB
C++
593 строки
20 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 "nsTextPaintStyle.h"
|
|
|
|
#include "nsCSSColorUtils.h"
|
|
#include "nsCSSRendering.h"
|
|
#include "nsFrameSelection.h"
|
|
#include "nsLayoutUtils.h"
|
|
#include "nsTextFrame.h"
|
|
#include "nsStyleConsts.h"
|
|
|
|
#include "mozilla/LookAndFeel.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
static nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB) {
|
|
if (colorA == colorB) {
|
|
nscolor res;
|
|
res = NS_RGB(NS_GET_R(colorA) ^ 0xff, NS_GET_G(colorA) ^ 0xff,
|
|
NS_GET_B(colorA) ^ 0xff);
|
|
return res;
|
|
}
|
|
return colorA;
|
|
}
|
|
|
|
nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
|
|
: mFrame(aFrame),
|
|
mPresContext(aFrame->PresContext()),
|
|
mInitCommonColors(false),
|
|
mInitSelectionColorsAndShadow(false),
|
|
mResolveColors(true),
|
|
mSelectionTextColor(NS_RGBA(0, 0, 0, 0)),
|
|
mSelectionBGColor(NS_RGBA(0, 0, 0, 0)),
|
|
mSufficientContrast(0),
|
|
mFrameBackgroundColor(NS_RGBA(0, 0, 0, 0)),
|
|
mSystemFieldForegroundColor(NS_RGBA(0, 0, 0, 0)),
|
|
mSystemFieldBackgroundColor(NS_RGBA(0, 0, 0, 0)) {
|
|
for (uint32_t i = 0; i < ArrayLength(mSelectionStyle); i++)
|
|
mSelectionStyle[i].mInit = false;
|
|
}
|
|
|
|
bool nsTextPaintStyle::EnsureSufficientContrast(nscolor* aForeColor,
|
|
nscolor* aBackColor) {
|
|
InitCommonColors();
|
|
|
|
const bool sameAsForeground = *aForeColor == NS_SAME_AS_FOREGROUND_COLOR;
|
|
if (sameAsForeground) {
|
|
*aForeColor = GetTextColor();
|
|
}
|
|
|
|
// If the combination of selection background color and frame background color
|
|
// has sufficient contrast, don't exchange the selection colors.
|
|
//
|
|
// Note we use a different threshold here: mSufficientContrast is for contrast
|
|
// between text and background colors, but since we're diffing two
|
|
// backgrounds, we don't need that much contrast. We match the heuristic from
|
|
// NS_SUFFICIENT_LUMINOSITY_DIFFERENCE_BG and use 20% of mSufficientContrast.
|
|
const int32_t minLuminosityDifferenceForBackground = mSufficientContrast / 5;
|
|
const int32_t backLuminosityDifference =
|
|
NS_LUMINOSITY_DIFFERENCE(*aBackColor, mFrameBackgroundColor);
|
|
if (backLuminosityDifference >= minLuminosityDifferenceForBackground) {
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, we should use the higher-contrast color for the selection
|
|
// background color.
|
|
//
|
|
// For NS_SAME_AS_FOREGROUND_COLOR we only do this if the background is
|
|
// totally indistinguishable, that is, if the luminosity difference is 0.
|
|
if (sameAsForeground && backLuminosityDifference) {
|
|
return false;
|
|
}
|
|
|
|
int32_t foreLuminosityDifference =
|
|
NS_LUMINOSITY_DIFFERENCE(*aForeColor, mFrameBackgroundColor);
|
|
if (backLuminosityDifference < foreLuminosityDifference) {
|
|
std::swap(*aForeColor, *aBackColor);
|
|
// Ensure foreground color is opaque to guarantee contrast.
|
|
*aForeColor = NS_RGB(NS_GET_R(*aForeColor), NS_GET_G(*aForeColor),
|
|
NS_GET_B(*aForeColor));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
nscolor nsTextPaintStyle::GetTextColor() {
|
|
if (mFrame->IsInSVGTextSubtree()) {
|
|
if (!mResolveColors) {
|
|
return NS_SAME_AS_FOREGROUND_COLOR;
|
|
}
|
|
|
|
const nsStyleSVG* style = mFrame->StyleSVG();
|
|
switch (style->mFill.kind.tag) {
|
|
case StyleSVGPaintKind::Tag::None:
|
|
return NS_RGBA(0, 0, 0, 0);
|
|
case StyleSVGPaintKind::Tag::Color:
|
|
return nsLayoutUtils::GetColor(mFrame, &nsStyleSVG::mFill);
|
|
default:
|
|
NS_ERROR("cannot resolve SVG paint to nscolor");
|
|
return NS_RGBA(0, 0, 0, 255);
|
|
}
|
|
}
|
|
|
|
return nsLayoutUtils::GetColor(mFrame, &nsStyleText::mWebkitTextFillColor);
|
|
}
|
|
|
|
bool nsTextPaintStyle::GetSelectionColors(nscolor* aForeColor,
|
|
nscolor* aBackColor) {
|
|
NS_ASSERTION(aForeColor, "aForeColor is null");
|
|
NS_ASSERTION(aBackColor, "aBackColor is null");
|
|
|
|
if (!InitSelectionColorsAndShadow()) {
|
|
return false;
|
|
}
|
|
|
|
*aForeColor = mSelectionTextColor;
|
|
*aBackColor = mSelectionBGColor;
|
|
return true;
|
|
}
|
|
|
|
void nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
|
|
nscolor* aBackColor) {
|
|
NS_ASSERTION(aForeColor, "aForeColor is null");
|
|
NS_ASSERTION(aBackColor, "aBackColor is null");
|
|
|
|
const nsFrameSelection* frameSelection = mFrame->GetConstFrameSelection();
|
|
const Selection* selection =
|
|
frameSelection->GetSelection(SelectionType::eFind);
|
|
const SelectionCustomColors* customColors = nullptr;
|
|
if (selection) {
|
|
customColors = selection->GetCustomColors();
|
|
}
|
|
|
|
if (!customColors) {
|
|
nscolor backColor = LookAndFeel::Color(
|
|
LookAndFeel::ColorID::TextHighlightBackground, mFrame);
|
|
nscolor foreColor = LookAndFeel::Color(
|
|
LookAndFeel::ColorID::TextHighlightForeground, mFrame);
|
|
EnsureSufficientContrast(&foreColor, &backColor);
|
|
*aForeColor = foreColor;
|
|
*aBackColor = backColor;
|
|
return;
|
|
}
|
|
|
|
if (customColors->mForegroundColor && customColors->mBackgroundColor) {
|
|
nscolor foreColor = *customColors->mForegroundColor;
|
|
nscolor backColor = *customColors->mBackgroundColor;
|
|
|
|
if (EnsureSufficientContrast(&foreColor, &backColor) &&
|
|
customColors->mAltForegroundColor &&
|
|
customColors->mAltBackgroundColor) {
|
|
foreColor = *customColors->mAltForegroundColor;
|
|
backColor = *customColors->mAltBackgroundColor;
|
|
}
|
|
|
|
*aForeColor = foreColor;
|
|
*aBackColor = backColor;
|
|
return;
|
|
}
|
|
|
|
InitCommonColors();
|
|
|
|
if (customColors->mBackgroundColor) {
|
|
// !mForegroundColor means "currentColor"; the current color of the text.
|
|
nscolor foreColor = GetTextColor();
|
|
nscolor backColor = *customColors->mBackgroundColor;
|
|
|
|
int32_t luminosityDifference =
|
|
NS_LUMINOSITY_DIFFERENCE(foreColor, backColor);
|
|
|
|
if (mSufficientContrast > luminosityDifference &&
|
|
customColors->mAltBackgroundColor) {
|
|
int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
|
|
foreColor, *customColors->mAltBackgroundColor);
|
|
|
|
if (luminosityDifference < altLuminosityDifference) {
|
|
backColor = *customColors->mAltBackgroundColor;
|
|
}
|
|
}
|
|
|
|
*aForeColor = foreColor;
|
|
*aBackColor = backColor;
|
|
return;
|
|
}
|
|
|
|
if (customColors->mForegroundColor) {
|
|
nscolor foreColor = *customColors->mForegroundColor;
|
|
// !mBackgroundColor means "transparent"; the current color of the
|
|
// background.
|
|
|
|
int32_t luminosityDifference =
|
|
NS_LUMINOSITY_DIFFERENCE(foreColor, mFrameBackgroundColor);
|
|
|
|
if (mSufficientContrast > luminosityDifference &&
|
|
customColors->mAltForegroundColor) {
|
|
int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
|
|
*customColors->mForegroundColor, mFrameBackgroundColor);
|
|
|
|
if (luminosityDifference < altLuminosityDifference) {
|
|
foreColor = *customColors->mAltForegroundColor;
|
|
}
|
|
}
|
|
|
|
*aForeColor = foreColor;
|
|
*aBackColor = NS_TRANSPARENT;
|
|
return;
|
|
}
|
|
|
|
// There are neither mForegroundColor nor mBackgroundColor.
|
|
*aForeColor = GetTextColor();
|
|
*aBackColor = NS_TRANSPARENT;
|
|
}
|
|
|
|
bool nsTextPaintStyle::GetCustomHighlightTextColor(const nsAtom* aHighlightName,
|
|
nscolor* aForeColor) {
|
|
NS_ASSERTION(aForeColor, "aForeColor is null");
|
|
|
|
// non-existing highlights will be stored as `aHighlightName->nullptr`,
|
|
// so subsequent calls only need a hashtable lookup and don't have
|
|
// to enter the style engine.
|
|
RefPtr<ComputedStyle> highlightStyle =
|
|
mCustomHighlightPseudoStyles.LookupOrInsertWith(
|
|
aHighlightName, [this, &aHighlightName] {
|
|
return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
|
|
});
|
|
if (!highlightStyle) {
|
|
// highlight `aHighlightName` doesn't exist or has no style rules.
|
|
return false;
|
|
}
|
|
|
|
*aForeColor = highlightStyle->GetVisitedDependentColor(
|
|
&nsStyleText::mWebkitTextFillColor);
|
|
|
|
return highlightStyle->HasAuthorSpecifiedTextColor();
|
|
}
|
|
|
|
bool nsTextPaintStyle::GetCustomHighlightBackgroundColor(
|
|
const nsAtom* aHighlightName, nscolor* aBackColor) {
|
|
NS_ASSERTION(aBackColor, "aBackColor is null");
|
|
// non-existing highlights will be stored as `aHighlightName->nullptr`,
|
|
// so subsequent calls only need a hashtable lookup and don't have
|
|
// to enter the style engine.
|
|
RefPtr<ComputedStyle> highlightStyle =
|
|
mCustomHighlightPseudoStyles.LookupOrInsertWith(
|
|
aHighlightName, [this, &aHighlightName] {
|
|
return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
|
|
});
|
|
if (!highlightStyle) {
|
|
// highlight `aHighlightName` doesn't exist or has no style rules.
|
|
return false;
|
|
}
|
|
|
|
*aBackColor = highlightStyle->GetVisitedDependentColor(
|
|
&nsStyleBackground::mBackgroundColor);
|
|
return NS_GET_A(*aBackColor) != 0;
|
|
}
|
|
|
|
void nsTextPaintStyle::GetURLSecondaryColor(nscolor* aForeColor) {
|
|
NS_ASSERTION(aForeColor, "aForeColor is null");
|
|
|
|
nscolor textColor = GetTextColor();
|
|
textColor = NS_RGBA(NS_GET_R(textColor), NS_GET_G(textColor),
|
|
NS_GET_B(textColor), (uint8_t)(255 * 0.5f));
|
|
// Don't use true alpha color for readability.
|
|
InitCommonColors();
|
|
*aForeColor = NS_ComposeColors(mFrameBackgroundColor, textColor);
|
|
}
|
|
|
|
void nsTextPaintStyle::GetIMESelectionColors(int32_t aIndex,
|
|
nscolor* aForeColor,
|
|
nscolor* aBackColor) {
|
|
NS_ASSERTION(aForeColor, "aForeColor is null");
|
|
NS_ASSERTION(aBackColor, "aBackColor is null");
|
|
NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
|
|
|
|
nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
|
|
*aForeColor = selectionStyle->mTextColor;
|
|
*aBackColor = selectionStyle->mBGColor;
|
|
}
|
|
|
|
bool nsTextPaintStyle::GetSelectionUnderlineForPaint(
|
|
int32_t aIndex, nscolor* aLineColor, float* aRelativeSize,
|
|
StyleTextDecorationStyle* aStyle) {
|
|
NS_ASSERTION(aLineColor, "aLineColor is null");
|
|
NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
|
|
NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
|
|
|
|
nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
|
|
if (selectionStyle->mUnderlineStyle == StyleTextDecorationStyle::None ||
|
|
selectionStyle->mUnderlineColor == NS_TRANSPARENT ||
|
|
selectionStyle->mUnderlineRelativeSize <= 0.0f)
|
|
return false;
|
|
|
|
*aLineColor = selectionStyle->mUnderlineColor;
|
|
*aRelativeSize = selectionStyle->mUnderlineRelativeSize;
|
|
*aStyle = selectionStyle->mUnderlineStyle;
|
|
return true;
|
|
}
|
|
|
|
void nsTextPaintStyle::InitCommonColors() {
|
|
if (mInitCommonColors) {
|
|
return;
|
|
}
|
|
|
|
auto bgColor = nsCSSRendering::FindEffectiveBackgroundColor(mFrame);
|
|
mFrameBackgroundColor = bgColor.mColor;
|
|
|
|
mSystemFieldForegroundColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Fieldtext, mFrame);
|
|
mSystemFieldBackgroundColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Field, mFrame);
|
|
|
|
if (bgColor.mIsThemed) {
|
|
// Assume a native widget has sufficient contrast always
|
|
mSufficientContrast = 0;
|
|
mInitCommonColors = true;
|
|
return;
|
|
}
|
|
|
|
nscolor defaultWindowBackgroundColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Window, mFrame);
|
|
nscolor selectionTextColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
|
|
nscolor selectionBGColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
|
|
|
|
mSufficientContrast = std::min(
|
|
std::min(NS_SUFFICIENT_LUMINOSITY_DIFFERENCE,
|
|
NS_LUMINOSITY_DIFFERENCE(selectionTextColor, selectionBGColor)),
|
|
NS_LUMINOSITY_DIFFERENCE(defaultWindowBackgroundColor, selectionBGColor));
|
|
|
|
mInitCommonColors = true;
|
|
}
|
|
|
|
nscolor nsTextPaintStyle::GetSystemFieldForegroundColor() {
|
|
InitCommonColors();
|
|
return mSystemFieldForegroundColor;
|
|
}
|
|
|
|
nscolor nsTextPaintStyle::GetSystemFieldBackgroundColor() {
|
|
InitCommonColors();
|
|
return mSystemFieldBackgroundColor;
|
|
}
|
|
|
|
bool nsTextPaintStyle::InitSelectionColorsAndShadow() {
|
|
if (mInitSelectionColorsAndShadow) {
|
|
return true;
|
|
}
|
|
|
|
int16_t selectionFlags;
|
|
const int16_t selectionStatus = mFrame->GetSelectionStatus(&selectionFlags);
|
|
if (!(selectionFlags & nsISelectionDisplay::DISPLAY_TEXT) ||
|
|
selectionStatus < nsISelectionController::SELECTION_ON) {
|
|
// Not displaying the normal selection.
|
|
// We're not caching this fact, so every call to GetSelectionColors
|
|
// will come through here. We could avoid this, but it's not really worth
|
|
// it.
|
|
return false;
|
|
}
|
|
|
|
mInitSelectionColorsAndShadow = true;
|
|
|
|
// Use ::selection pseudo class if applicable.
|
|
if (RefPtr<ComputedStyle> style =
|
|
mFrame->ComputeSelectionStyle(selectionStatus)) {
|
|
mSelectionBGColor =
|
|
style->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
|
|
mSelectionTextColor =
|
|
style->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
|
|
mSelectionPseudoStyle = std::move(style);
|
|
return true;
|
|
}
|
|
|
|
mSelectionTextColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
|
|
|
|
nscolor selectionBGColor =
|
|
LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
|
|
|
|
switch (selectionStatus) {
|
|
case nsISelectionController::SELECTION_ATTENTION: {
|
|
mSelectionTextColor = LookAndFeel::Color(
|
|
LookAndFeel::ColorID::TextSelectAttentionForeground, mFrame);
|
|
mSelectionBGColor = LookAndFeel::Color(
|
|
LookAndFeel::ColorID::TextSelectAttentionBackground, mFrame);
|
|
mSelectionBGColor =
|
|
EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
|
|
break;
|
|
}
|
|
case nsISelectionController::SELECTION_ON: {
|
|
mSelectionBGColor = selectionBGColor;
|
|
break;
|
|
}
|
|
default: {
|
|
mSelectionBGColor = LookAndFeel::Color(
|
|
LookAndFeel::ColorID::TextSelectDisabledBackground, mFrame);
|
|
mSelectionBGColor =
|
|
EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mResolveColors) {
|
|
EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
nsTextPaintStyle::nsSelectionStyle* nsTextPaintStyle::GetSelectionStyle(
|
|
int32_t aIndex) {
|
|
InitSelectionStyle(aIndex);
|
|
return &mSelectionStyle[aIndex];
|
|
}
|
|
|
|
struct StyleIDs {
|
|
LookAndFeel::ColorID mForeground, mBackground, mLine;
|
|
LookAndFeel::IntID mLineStyle;
|
|
LookAndFeel::FloatID mLineRelativeSize;
|
|
};
|
|
static StyleIDs SelectionStyleIDs[] = {
|
|
{LookAndFeel::ColorID::IMERawInputForeground,
|
|
LookAndFeel::ColorID::IMERawInputBackground,
|
|
LookAndFeel::ColorID::IMERawInputUnderline,
|
|
LookAndFeel::IntID::IMERawInputUnderlineStyle,
|
|
LookAndFeel::FloatID::IMEUnderlineRelativeSize},
|
|
{LookAndFeel::ColorID::IMESelectedRawTextForeground,
|
|
LookAndFeel::ColorID::IMESelectedRawTextBackground,
|
|
LookAndFeel::ColorID::IMESelectedRawTextUnderline,
|
|
LookAndFeel::IntID::IMESelectedRawTextUnderlineStyle,
|
|
LookAndFeel::FloatID::IMEUnderlineRelativeSize},
|
|
{LookAndFeel::ColorID::IMEConvertedTextForeground,
|
|
LookAndFeel::ColorID::IMEConvertedTextBackground,
|
|
LookAndFeel::ColorID::IMEConvertedTextUnderline,
|
|
LookAndFeel::IntID::IMEConvertedTextUnderlineStyle,
|
|
LookAndFeel::FloatID::IMEUnderlineRelativeSize},
|
|
{LookAndFeel::ColorID::IMESelectedConvertedTextForeground,
|
|
LookAndFeel::ColorID::IMESelectedConvertedTextBackground,
|
|
LookAndFeel::ColorID::IMESelectedConvertedTextUnderline,
|
|
LookAndFeel::IntID::IMESelectedConvertedTextUnderline,
|
|
LookAndFeel::FloatID::IMEUnderlineRelativeSize},
|
|
{LookAndFeel::ColorID::End, LookAndFeel::ColorID::End,
|
|
LookAndFeel::ColorID::SpellCheckerUnderline,
|
|
LookAndFeel::IntID::SpellCheckerUnderlineStyle,
|
|
LookAndFeel::FloatID::SpellCheckerUnderlineRelativeSize}};
|
|
|
|
void nsTextPaintStyle::InitSelectionStyle(int32_t aIndex) {
|
|
NS_ASSERTION(aIndex >= 0 && aIndex < 5, "aIndex is invalid");
|
|
nsSelectionStyle* selectionStyle = &mSelectionStyle[aIndex];
|
|
if (selectionStyle->mInit) {
|
|
return;
|
|
}
|
|
|
|
StyleIDs* styleIDs = &SelectionStyleIDs[aIndex];
|
|
|
|
nscolor foreColor, backColor;
|
|
if (styleIDs->mForeground == LookAndFeel::ColorID::End) {
|
|
foreColor = NS_SAME_AS_FOREGROUND_COLOR;
|
|
} else {
|
|
foreColor = LookAndFeel::Color(styleIDs->mForeground, mFrame);
|
|
}
|
|
if (styleIDs->mBackground == LookAndFeel::ColorID::End) {
|
|
backColor = NS_TRANSPARENT;
|
|
} else {
|
|
backColor = LookAndFeel::Color(styleIDs->mBackground, mFrame);
|
|
}
|
|
|
|
// Convert special color to actual color
|
|
NS_ASSERTION(foreColor != NS_TRANSPARENT,
|
|
"foreColor cannot be NS_TRANSPARENT");
|
|
NS_ASSERTION(backColor != NS_SAME_AS_FOREGROUND_COLOR,
|
|
"backColor cannot be NS_SAME_AS_FOREGROUND_COLOR");
|
|
NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
|
|
"backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
|
|
|
|
if (mResolveColors) {
|
|
foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
|
|
|
|
if (NS_GET_A(backColor) > 0) {
|
|
EnsureSufficientContrast(&foreColor, &backColor);
|
|
}
|
|
}
|
|
|
|
nscolor lineColor;
|
|
float relativeSize;
|
|
StyleTextDecorationStyle lineStyle;
|
|
GetSelectionUnderline(mFrame, aIndex, &lineColor, &relativeSize, &lineStyle);
|
|
|
|
if (mResolveColors) {
|
|
lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
|
|
}
|
|
|
|
selectionStyle->mTextColor = foreColor;
|
|
selectionStyle->mBGColor = backColor;
|
|
selectionStyle->mUnderlineColor = lineColor;
|
|
selectionStyle->mUnderlineStyle = lineStyle;
|
|
selectionStyle->mUnderlineRelativeSize = relativeSize;
|
|
selectionStyle->mInit = true;
|
|
}
|
|
|
|
/* static */
|
|
bool nsTextPaintStyle::GetSelectionUnderline(nsIFrame* aFrame, int32_t aIndex,
|
|
nscolor* aLineColor,
|
|
float* aRelativeSize,
|
|
StyleTextDecorationStyle* aStyle) {
|
|
NS_ASSERTION(aFrame, "aFrame is null");
|
|
NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
|
|
NS_ASSERTION(aStyle, "aStyle is null");
|
|
NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
|
|
|
|
StyleIDs& styleID = SelectionStyleIDs[aIndex];
|
|
|
|
nscolor color = LookAndFeel::Color(styleID.mLine, aFrame);
|
|
const int32_t lineStyle = LookAndFeel::GetInt(styleID.mLineStyle);
|
|
auto style = static_cast<StyleTextDecorationStyle>(lineStyle);
|
|
if (lineStyle > static_cast<int32_t>(StyleTextDecorationStyle::Sentinel)) {
|
|
NS_ERROR("Invalid underline style value is specified");
|
|
style = StyleTextDecorationStyle::Solid;
|
|
}
|
|
float size = LookAndFeel::GetFloat(styleID.mLineRelativeSize);
|
|
|
|
NS_ASSERTION(size, "selection underline relative size must be larger than 0");
|
|
|
|
if (aLineColor) {
|
|
*aLineColor = color;
|
|
}
|
|
*aRelativeSize = size;
|
|
*aStyle = style;
|
|
|
|
return style != StyleTextDecorationStyle::None && color != NS_TRANSPARENT &&
|
|
size > 0.0f;
|
|
}
|
|
|
|
bool nsTextPaintStyle::GetSelectionShadow(
|
|
Span<const StyleSimpleShadow>* aShadows) {
|
|
if (!InitSelectionColorsAndShadow()) {
|
|
return false;
|
|
}
|
|
|
|
if (mSelectionPseudoStyle) {
|
|
*aShadows = mSelectionPseudoStyle->StyleText()->mTextShadow.AsSpan();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline nscolor Get40PercentColor(nscolor aForeColor, nscolor aBackColor) {
|
|
nscolor foreColor = NS_RGBA(NS_GET_R(aForeColor), NS_GET_G(aForeColor),
|
|
NS_GET_B(aForeColor), (uint8_t)(255 * 0.4f));
|
|
// Don't use true alpha color for readability.
|
|
return NS_ComposeColors(aBackColor, foreColor);
|
|
}
|
|
|
|
nscolor nsTextPaintStyle::GetResolvedForeColor(nscolor aColor,
|
|
nscolor aDefaultForeColor,
|
|
nscolor aBackColor) {
|
|
if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
|
|
return aDefaultForeColor;
|
|
}
|
|
|
|
if (aColor != NS_40PERCENT_FOREGROUND_COLOR) {
|
|
return aColor;
|
|
}
|
|
|
|
// Get actual background color
|
|
nscolor actualBGColor = aBackColor;
|
|
if (actualBGColor == NS_TRANSPARENT) {
|
|
InitCommonColors();
|
|
actualBGColor = mFrameBackgroundColor;
|
|
}
|
|
return Get40PercentColor(aDefaultForeColor, actualBGColor);
|
|
}
|
|
|
|
nscolor nsTextPaintStyle::GetWebkitTextStrokeColor() {
|
|
if (mFrame->IsInSVGTextSubtree()) {
|
|
return 0;
|
|
}
|
|
return mFrame->StyleText()->mWebkitTextStrokeColor.CalcColor(mFrame);
|
|
}
|
|
|
|
float nsTextPaintStyle::GetWebkitTextStrokeWidth() {
|
|
if (mFrame->IsInSVGTextSubtree()) {
|
|
return 0.0f;
|
|
}
|
|
nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
|
|
return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
|
|
}
|