forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			574 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			574 lines
		
	
	
	
		
			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 "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::GetCustomHighlightColors(const nsAtom* aHighlightName,
 | |
|                                                 nscolor* aForeColor,
 | |
|                                                 nscolor* aBackColor) {
 | |
|   NS_ASSERTION(aForeColor, "aForeColor is null");
 | |
|   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;
 | |
|   }
 | |
|   // this is just copied from here:
 | |
|   // `InitSelectionColorsAndShadow()`.
 | |
|   *aBackColor = highlightStyle->GetVisitedDependentColor(
 | |
|       &nsStyleBackground::mBackgroundColor);
 | |
|   *aForeColor = highlightStyle->GetVisitedDependentColor(
 | |
|       &nsStyleText::mWebkitTextFillColor);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| }
 | 
