tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsTextPaintStyle.cpp (23642B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsTextPaintStyle.h"
      8 
      9 #include "mozilla/LookAndFeel.h"
     10 #include "mozilla/RelativeLuminanceUtils.h"
     11 #include "nsCSSColorUtils.h"
     12 #include "nsCSSRendering.h"
     13 #include "nsFrameSelection.h"
     14 #include "nsLayoutUtils.h"
     15 #include "nsStyleConsts.h"
     16 #include "nsTextFrame.h"
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::dom;
     20 
     21 static nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB) {
     22  if (colorA == colorB) {
     23    nscolor res;
     24    res = NS_RGB(NS_GET_R(colorA) ^ 0xff, NS_GET_G(colorA) ^ 0xff,
     25                 NS_GET_B(colorA) ^ 0xff);
     26    return res;
     27  }
     28  return colorA;
     29 }
     30 
     31 nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
     32    : mFrame(aFrame),
     33      mPresContext(aFrame->PresContext()),
     34      mInitCommonColors(false),
     35      mInitSelectionColorsAndShadow(false),
     36      mResolveColors(true),
     37      mInitTargetTextPseudoStyle(false),
     38      mSelectionTextColor(NS_RGBA(0, 0, 0, 0)),
     39      mSelectionBGColor(NS_RGBA(0, 0, 0, 0)),
     40      mSufficientContrast(0),
     41      mFrameBackgroundColor(NS_RGBA(0, 0, 0, 0)),
     42      mSystemFieldForegroundColor(NS_RGBA(0, 0, 0, 0)),
     43      mSystemFieldBackgroundColor(NS_RGBA(0, 0, 0, 0)) {}
     44 
     45 bool nsTextPaintStyle::EnsureSufficientContrast(nscolor* aForeColor,
     46                                                nscolor* aBackColor) {
     47  InitCommonColors();
     48 
     49  const bool sameAsForeground = *aForeColor == NS_SAME_AS_FOREGROUND_COLOR;
     50  if (sameAsForeground) {
     51    *aForeColor = GetTextColor();
     52  }
     53 
     54  // If the combination of selection background color and frame background color
     55  // has sufficient contrast, don't exchange the selection colors.
     56  //
     57  // Note we use a different threshold here: mSufficientContrast is for contrast
     58  // between text and background colors, but since we're diffing two
     59  // backgrounds, we don't need that much contrast.  We match the heuristic from
     60  // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE_BG and use 20% of mSufficientContrast.
     61  const int32_t minLuminosityDifferenceForBackground = mSufficientContrast / 5;
     62  const int32_t backLuminosityDifference =
     63      NS_LUMINOSITY_DIFFERENCE(*aBackColor, mFrameBackgroundColor);
     64  if (backLuminosityDifference >= minLuminosityDifferenceForBackground) {
     65    return false;
     66  }
     67 
     68  // Otherwise, we should use the higher-contrast color for the selection
     69  // background color.
     70  //
     71  // For NS_SAME_AS_FOREGROUND_COLOR we only do this if the background is
     72  // totally indistinguishable, that is, if the luminosity difference is 0.
     73  if (sameAsForeground && backLuminosityDifference) {
     74    return false;
     75  }
     76 
     77  int32_t foreLuminosityDifference =
     78      NS_LUMINOSITY_DIFFERENCE(*aForeColor, mFrameBackgroundColor);
     79  if (backLuminosityDifference < foreLuminosityDifference) {
     80    std::swap(*aForeColor, *aBackColor);
     81    // Ensure foreground color is opaque to guarantee contrast.
     82    *aForeColor = NS_RGB(NS_GET_R(*aForeColor), NS_GET_G(*aForeColor),
     83                         NS_GET_B(*aForeColor));
     84    return true;
     85  }
     86  return false;
     87 }
     88 
     89 nscolor nsTextPaintStyle::GetTextColor() {
     90  if (mFrame->IsInSVGTextSubtree()) {
     91    if (!mResolveColors) {
     92      return NS_SAME_AS_FOREGROUND_COLOR;
     93    }
     94 
     95    const nsStyleSVG* style = mFrame->StyleSVG();
     96    switch (style->mFill.kind.tag) {
     97      case StyleSVGPaintKind::Tag::None:
     98        return NS_RGBA(0, 0, 0, 0);
     99      case StyleSVGPaintKind::Tag::Color:
    100        return nsLayoutUtils::GetTextColor(mFrame, &nsStyleSVG::mFill);
    101      default:
    102        NS_ERROR("cannot resolve SVG paint to nscolor");
    103        return NS_RGBA(0, 0, 0, 255);
    104    }
    105  }
    106 
    107  return nsLayoutUtils::GetTextColor(mFrame,
    108                                     &nsStyleText::mWebkitTextFillColor);
    109 }
    110 
    111 bool nsTextPaintStyle::GetSelectionColors(nscolor* aForeColor,
    112                                          nscolor* aBackColor) {
    113  NS_ASSERTION(aForeColor, "aForeColor is null");
    114  NS_ASSERTION(aBackColor, "aBackColor is null");
    115 
    116  if (!InitSelectionColorsAndShadow()) {
    117    return false;
    118  }
    119 
    120  *aForeColor = mSelectionTextColor;
    121  *aBackColor = mSelectionBGColor;
    122  return true;
    123 }
    124 
    125 void nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
    126                                          nscolor* aBackColor) {
    127  NS_ASSERTION(aForeColor, "aForeColor is null");
    128  NS_ASSERTION(aBackColor, "aBackColor is null");
    129 
    130  const nsFrameSelection* frameSelection = mFrame->GetConstFrameSelection();
    131  const Selection* selection =
    132      frameSelection->GetSelection(SelectionType::eFind);
    133  const SelectionCustomColors* customColors = nullptr;
    134  if (selection) {
    135    customColors = selection->GetCustomColors();
    136  }
    137 
    138  if (!customColors) {
    139    nscolor backColor = LookAndFeel::Color(
    140        LookAndFeel::ColorID::TextHighlightBackground, mFrame);
    141    nscolor foreColor = LookAndFeel::Color(
    142        LookAndFeel::ColorID::TextHighlightForeground, mFrame);
    143    EnsureSufficientContrast(&foreColor, &backColor);
    144    *aForeColor = foreColor;
    145    *aBackColor = backColor;
    146    return;
    147  }
    148 
    149  if (customColors->mForegroundColor && customColors->mBackgroundColor) {
    150    nscolor foreColor = *customColors->mForegroundColor;
    151    nscolor backColor = *customColors->mBackgroundColor;
    152 
    153    if (EnsureSufficientContrast(&foreColor, &backColor) &&
    154        customColors->mAltForegroundColor &&
    155        customColors->mAltBackgroundColor) {
    156      foreColor = *customColors->mAltForegroundColor;
    157      backColor = *customColors->mAltBackgroundColor;
    158    }
    159 
    160    *aForeColor = foreColor;
    161    *aBackColor = backColor;
    162    return;
    163  }
    164 
    165  InitCommonColors();
    166 
    167  if (customColors->mBackgroundColor) {
    168    // !mForegroundColor means "currentColor"; the current color of the text.
    169    nscolor foreColor = GetTextColor();
    170    nscolor backColor = *customColors->mBackgroundColor;
    171 
    172    int32_t luminosityDifference =
    173        NS_LUMINOSITY_DIFFERENCE(foreColor, backColor);
    174 
    175    if (mSufficientContrast > luminosityDifference &&
    176        customColors->mAltBackgroundColor) {
    177      int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
    178          foreColor, *customColors->mAltBackgroundColor);
    179 
    180      if (luminosityDifference < altLuminosityDifference) {
    181        backColor = *customColors->mAltBackgroundColor;
    182      }
    183    }
    184 
    185    *aForeColor = foreColor;
    186    *aBackColor = backColor;
    187    return;
    188  }
    189 
    190  if (customColors->mForegroundColor) {
    191    nscolor foreColor = *customColors->mForegroundColor;
    192    // !mBackgroundColor means "transparent"; the current color of the
    193    // background.
    194 
    195    int32_t luminosityDifference =
    196        NS_LUMINOSITY_DIFFERENCE(foreColor, mFrameBackgroundColor);
    197 
    198    if (mSufficientContrast > luminosityDifference &&
    199        customColors->mAltForegroundColor) {
    200      int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
    201          *customColors->mForegroundColor, mFrameBackgroundColor);
    202 
    203      if (luminosityDifference < altLuminosityDifference) {
    204        foreColor = *customColors->mAltForegroundColor;
    205      }
    206    }
    207 
    208    *aForeColor = foreColor;
    209    *aBackColor = NS_TRANSPARENT;
    210    return;
    211  }
    212 
    213  // There are neither mForegroundColor nor mBackgroundColor.
    214  *aForeColor = GetTextColor();
    215  *aBackColor = NS_TRANSPARENT;
    216 }
    217 
    218 void nsTextPaintStyle::GetTargetTextColors(nscolor* aForeColor,
    219                                           nscolor* aBackColor) {
    220  NS_ASSERTION(aForeColor, "aForeColor is null");
    221  NS_ASSERTION(aBackColor, "aBackColor is null");
    222  InitCommonColors();
    223  InitTargetTextPseudoStyle();
    224 
    225  if (mTargetTextPseudoStyle) {
    226    *aForeColor = mTargetTextPseudoStyle->GetVisitedDependentColor(
    227        &nsStyleText::mWebkitTextFillColor);
    228    *aBackColor = mTargetTextPseudoStyle->GetVisitedDependentColor(
    229        &nsStyleBackground::mBackgroundColor);
    230    return;
    231  }
    232 
    233  const auto darkSchemeBackground = LookAndFeel::Color(
    234      LookAndFeel::ColorID::TargetTextBackground,
    235      LookAndFeel::ColorScheme::Dark, LookAndFeel::UseStandins::No);
    236  const auto lightSchemeBackground = LookAndFeel::Color(
    237      LookAndFeel::ColorID::TargetTextBackground,
    238      LookAndFeel::ColorScheme::Light, LookAndFeel::UseStandins::No);
    239  const auto lightSchemeForeground = LookAndFeel::Color(
    240      LookAndFeel::ColorID::TargetTextForeground,
    241      LookAndFeel::ColorScheme::Light, LookAndFeel::UseStandins::No);
    242  const auto darkSchemeForeground = LookAndFeel::Color(
    243      LookAndFeel::ColorID::TargetTextForeground,
    244      LookAndFeel::ColorScheme::Dark, LookAndFeel::UseStandins::No);
    245  const float ratioLightScheme = RelativeLuminanceUtils::ContrastRatio(
    246      lightSchemeBackground, mFrameBackgroundColor);
    247  const float ratioDarkScheme = RelativeLuminanceUtils::ContrastRatio(
    248      darkSchemeBackground, mFrameBackgroundColor);
    249 
    250  *aBackColor = ratioLightScheme > ratioDarkScheme ? lightSchemeBackground
    251                                                   : darkSchemeBackground;
    252  *aForeColor = ratioLightScheme > ratioDarkScheme ? lightSchemeForeground
    253                                                   : darkSchemeForeground;
    254 }
    255 
    256 bool nsTextPaintStyle::GetCustomHighlightTextColor(nsAtom* aHighlightName,
    257                                                   nscolor* aForeColor) {
    258  NS_ASSERTION(aForeColor, "aForeColor is null");
    259 
    260  // non-existing highlights will be stored as `aHighlightName->nullptr`,
    261  // so subsequent calls only need a hashtable lookup and don't have
    262  // to enter the style engine.
    263  RefPtr<ComputedStyle> highlightStyle =
    264      mCustomHighlightPseudoStyles.LookupOrInsertWith(
    265          aHighlightName, [this, &aHighlightName] {
    266            return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
    267          });
    268  if (!highlightStyle) {
    269    // highlight `aHighlightName` doesn't exist or has no style rules.
    270    return false;
    271  }
    272 
    273  *aForeColor = highlightStyle->GetVisitedDependentColor(
    274      &nsStyleText::mWebkitTextFillColor);
    275 
    276  return highlightStyle->HasAuthorSpecifiedTextColor();
    277 }
    278 
    279 bool nsTextPaintStyle::GetCustomHighlightBackgroundColor(nsAtom* aHighlightName,
    280                                                         nscolor* aBackColor) {
    281  NS_ASSERTION(aBackColor, "aBackColor is null");
    282  // non-existing highlights will be stored as `aHighlightName->nullptr`,
    283  // so subsequent calls only need a hashtable lookup and don't have
    284  // to enter the style engine.
    285  RefPtr<ComputedStyle> highlightStyle =
    286      mCustomHighlightPseudoStyles.LookupOrInsertWith(
    287          aHighlightName, [this, &aHighlightName] {
    288            return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
    289          });
    290  if (!highlightStyle) {
    291    // highlight `aHighlightName` doesn't exist or has no style rules.
    292    return false;
    293  }
    294 
    295  *aBackColor = highlightStyle->GetVisitedDependentColor(
    296      &nsStyleBackground::mBackgroundColor);
    297  return NS_GET_A(*aBackColor) != 0;
    298 }
    299 
    300 RefPtr<ComputedStyle> nsTextPaintStyle::GetComputedStyleForSelectionPseudo(
    301    SelectionType aSelectionType, nsAtom* aHighlightName) {
    302  switch (aSelectionType) {
    303    case SelectionType::eNormal:
    304      InitSelectionColorsAndShadow();
    305      return mSelectionPseudoStyle;
    306    case SelectionType::eTargetText:
    307      InitTargetTextPseudoStyle();
    308      return mTargetTextPseudoStyle;
    309    case SelectionType::eHighlight: {
    310      return mCustomHighlightPseudoStyles.LookupOrInsertWith(
    311          aHighlightName, [this, &aHighlightName] {
    312            return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
    313          });
    314    }
    315    default:
    316      MOZ_ASSERT_UNREACHABLE("Wrong selection type");
    317      return nullptr;
    318  }
    319 }
    320 
    321 void nsTextPaintStyle::GetURLSecondaryColor(nscolor* aForeColor) {
    322  NS_ASSERTION(aForeColor, "aForeColor is null");
    323 
    324  const nscolor textColor = GetTextColor();
    325  *aForeColor = NS_RGBA(NS_GET_R(textColor), NS_GET_G(textColor),
    326                        NS_GET_B(textColor), 127);
    327 }
    328 
    329 void nsTextPaintStyle::GetIMESelectionColors(SelectionStyleIndex aIndex,
    330                                             nscolor* aForeColor,
    331                                             nscolor* aBackColor) {
    332  NS_ASSERTION(aForeColor, "aForeColor is null");
    333  NS_ASSERTION(aBackColor, "aBackColor is null");
    334 
    335  nsSelectionStyle* selectionStyle = SelectionStyle(aIndex);
    336  *aForeColor = selectionStyle->mTextColor;
    337  *aBackColor = selectionStyle->mBGColor;
    338 }
    339 
    340 bool nsTextPaintStyle::GetSelectionUnderlineForPaint(
    341    SelectionStyleIndex aIndex, nscolor* aLineColor, float* aRelativeSize,
    342    StyleTextDecorationStyle* aStyle) {
    343  NS_ASSERTION(aLineColor, "aLineColor is null");
    344  NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
    345 
    346  nsSelectionStyle* selectionStyle = SelectionStyle(aIndex);
    347  if (selectionStyle->mUnderlineStyle == StyleTextDecorationStyle::None ||
    348      selectionStyle->mUnderlineColor == NS_TRANSPARENT ||
    349      selectionStyle->mUnderlineRelativeSize <= 0.0f) {
    350    return false;
    351  }
    352 
    353  *aLineColor = selectionStyle->mUnderlineColor;
    354  *aRelativeSize = selectionStyle->mUnderlineRelativeSize;
    355  *aStyle = selectionStyle->mUnderlineStyle;
    356  return true;
    357 }
    358 
    359 void nsTextPaintStyle::InitCommonColors() {
    360  if (mInitCommonColors) {
    361    return;
    362  }
    363 
    364  auto bgColor = nsCSSRendering::FindEffectiveBackgroundColor(mFrame);
    365  mFrameBackgroundColor = bgColor.mColor;
    366 
    367  mSystemFieldForegroundColor =
    368      LookAndFeel::Color(LookAndFeel::ColorID::Fieldtext, mFrame);
    369  mSystemFieldBackgroundColor =
    370      LookAndFeel::Color(LookAndFeel::ColorID::Field, mFrame);
    371 
    372  if (bgColor.mIsThemed) {
    373    // Assume a native widget has sufficient contrast always
    374    mSufficientContrast = 0;
    375    mInitCommonColors = true;
    376    return;
    377  }
    378 
    379  nscolor defaultWindowBackgroundColor =
    380      LookAndFeel::Color(LookAndFeel::ColorID::Window, mFrame);
    381  nscolor selectionTextColor =
    382      LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
    383  nscolor selectionBGColor =
    384      LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
    385 
    386  mSufficientContrast = std::min(
    387      std::min(NS_SUFFICIENT_LUMINOSITY_DIFFERENCE,
    388               NS_LUMINOSITY_DIFFERENCE(selectionTextColor, selectionBGColor)),
    389      NS_LUMINOSITY_DIFFERENCE(defaultWindowBackgroundColor, selectionBGColor));
    390 
    391  mInitCommonColors = true;
    392 }
    393 
    394 nscolor nsTextPaintStyle::GetSystemFieldForegroundColor() {
    395  InitCommonColors();
    396  return mSystemFieldForegroundColor;
    397 }
    398 
    399 nscolor nsTextPaintStyle::GetSystemFieldBackgroundColor() {
    400  InitCommonColors();
    401  return mSystemFieldBackgroundColor;
    402 }
    403 
    404 bool nsTextPaintStyle::InitSelectionColorsAndShadow() {
    405  if (mInitSelectionColorsAndShadow) {
    406    return true;
    407  }
    408 
    409  int16_t selectionFlags;
    410  const int16_t selectionStatus = mFrame->GetSelectionStatus(&selectionFlags);
    411  if (!(selectionFlags & nsISelectionDisplay::DISPLAY_TEXT) ||
    412      selectionStatus < nsISelectionController::SELECTION_ON) {
    413    // Not displaying the normal selection.
    414    // We're not caching this fact, so every call to GetSelectionColors
    415    // will come through here. We could avoid this, but it's not really worth
    416    // it.
    417    return false;
    418  }
    419 
    420  mInitSelectionColorsAndShadow = true;
    421 
    422  // Use ::selection pseudo class if applicable.
    423  if (RefPtr<ComputedStyle> style =
    424          mFrame->ComputeSelectionStyle(selectionStatus)) {
    425    mSelectionBGColor =
    426        style->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
    427    mSelectionTextColor =
    428        style->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
    429    mSelectionPseudoStyle = std::move(style);
    430    return true;
    431  }
    432 
    433  mSelectionTextColor =
    434      LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
    435 
    436  nscolor selectionBGColor =
    437      LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
    438 
    439  switch (selectionStatus) {
    440    case nsISelectionController::SELECTION_ATTENTION: {
    441      mSelectionTextColor = LookAndFeel::Color(
    442          LookAndFeel::ColorID::TextSelectAttentionForeground, mFrame);
    443      mSelectionBGColor = LookAndFeel::Color(
    444          LookAndFeel::ColorID::TextSelectAttentionBackground, mFrame);
    445      mSelectionBGColor =
    446          EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
    447      break;
    448    }
    449    case nsISelectionController::SELECTION_ON: {
    450      mSelectionBGColor = selectionBGColor;
    451      break;
    452    }
    453    default: {
    454      mSelectionBGColor = LookAndFeel::Color(
    455          LookAndFeel::ColorID::TextSelectDisabledBackground, mFrame);
    456      mSelectionBGColor =
    457          EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
    458      break;
    459    }
    460  }
    461 
    462  if (mResolveColors) {
    463    EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
    464  }
    465  return true;
    466 }
    467 
    468 void nsTextPaintStyle::InitTargetTextPseudoStyle() {
    469  if (mInitTargetTextPseudoStyle) {
    470    return;
    471  }
    472  mInitTargetTextPseudoStyle = true;
    473  mTargetTextPseudoStyle = mFrame->ComputeTargetTextStyle();
    474 }
    475 
    476 nsTextPaintStyle::nsSelectionStyle* nsTextPaintStyle::SelectionStyle(
    477    SelectionStyleIndex aIndex) {
    478  Maybe<nsSelectionStyle>& selectionStyle = mSelectionStyle[aIndex];
    479  if (!selectionStyle) {
    480    selectionStyle.emplace(InitSelectionStyle(aIndex));
    481  }
    482  return selectionStyle.ptr();
    483 }
    484 
    485 struct StyleIDs {
    486  LookAndFeel::ColorID mForeground, mBackground, mLine;
    487  LookAndFeel::IntID mLineStyle;
    488  LookAndFeel::FloatID mLineRelativeSize;
    489 };
    490 EnumeratedArray<nsTextPaintStyle::SelectionStyleIndex, StyleIDs,
    491                size_t(nsTextPaintStyle::SelectionStyleIndex::Count)>
    492    SelectionStyleIDs = {
    493        StyleIDs{LookAndFeel::ColorID::IMERawInputForeground,
    494                 LookAndFeel::ColorID::IMERawInputBackground,
    495                 LookAndFeel::ColorID::IMERawInputUnderline,
    496                 LookAndFeel::IntID::IMERawInputUnderlineStyle,
    497                 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
    498        StyleIDs{LookAndFeel::ColorID::IMESelectedRawTextForeground,
    499                 LookAndFeel::ColorID::IMESelectedRawTextBackground,
    500                 LookAndFeel::ColorID::IMESelectedRawTextUnderline,
    501                 LookAndFeel::IntID::IMESelectedRawTextUnderlineStyle,
    502                 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
    503        StyleIDs{LookAndFeel::ColorID::IMEConvertedTextForeground,
    504                 LookAndFeel::ColorID::IMEConvertedTextBackground,
    505                 LookAndFeel::ColorID::IMEConvertedTextUnderline,
    506                 LookAndFeel::IntID::IMEConvertedTextUnderlineStyle,
    507                 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
    508        StyleIDs{LookAndFeel::ColorID::IMESelectedConvertedTextForeground,
    509                 LookAndFeel::ColorID::IMESelectedConvertedTextBackground,
    510                 LookAndFeel::ColorID::IMESelectedConvertedTextUnderline,
    511                 LookAndFeel::IntID::IMESelectedConvertedTextUnderline,
    512                 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
    513        StyleIDs{LookAndFeel::ColorID::End, LookAndFeel::ColorID::End,
    514                 LookAndFeel::ColorID::SpellCheckerUnderline,
    515                 LookAndFeel::IntID::SpellCheckerUnderlineStyle,
    516                 LookAndFeel::FloatID::SpellCheckerUnderlineRelativeSize}};
    517 
    518 nsTextPaintStyle::nsSelectionStyle nsTextPaintStyle::InitSelectionStyle(
    519    SelectionStyleIndex aIndex) {
    520  const StyleIDs& styleIDs = SelectionStyleIDs[aIndex];
    521 
    522  nscolor foreColor, backColor;
    523  if (styleIDs.mForeground == LookAndFeel::ColorID::End) {
    524    foreColor = NS_SAME_AS_FOREGROUND_COLOR;
    525  } else {
    526    foreColor = LookAndFeel::Color(styleIDs.mForeground, mFrame);
    527  }
    528  if (styleIDs.mBackground == LookAndFeel::ColorID::End) {
    529    backColor = NS_TRANSPARENT;
    530  } else {
    531    backColor = LookAndFeel::Color(styleIDs.mBackground, mFrame);
    532  }
    533 
    534  // Convert special color to actual color
    535  NS_ASSERTION(foreColor != NS_TRANSPARENT,
    536               "foreColor cannot be NS_TRANSPARENT");
    537  NS_ASSERTION(backColor != NS_SAME_AS_FOREGROUND_COLOR,
    538               "backColor cannot be NS_SAME_AS_FOREGROUND_COLOR");
    539  NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
    540               "backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
    541 
    542  if (mResolveColors) {
    543    foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
    544 
    545    if (NS_GET_A(backColor) > 0) {
    546      EnsureSufficientContrast(&foreColor, &backColor);
    547    }
    548  }
    549 
    550  nscolor lineColor;
    551  float relativeSize;
    552  StyleTextDecorationStyle lineStyle;
    553  GetSelectionUnderline(mFrame, aIndex, &lineColor, &relativeSize, &lineStyle);
    554 
    555  if (mResolveColors) {
    556    lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
    557  }
    558 
    559  return nsSelectionStyle{foreColor, backColor, lineColor, lineStyle,
    560                          relativeSize};
    561 }
    562 
    563 /* static */
    564 bool nsTextPaintStyle::GetSelectionUnderline(nsIFrame* aFrame,
    565                                             SelectionStyleIndex aIndex,
    566                                             nscolor* aLineColor,
    567                                             float* aRelativeSize,
    568                                             StyleTextDecorationStyle* aStyle) {
    569  NS_ASSERTION(aFrame, "aFrame is null");
    570  NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
    571  NS_ASSERTION(aStyle, "aStyle is null");
    572 
    573  const StyleIDs& styleIDs = SelectionStyleIDs[aIndex];
    574 
    575  nscolor color = LookAndFeel::Color(styleIDs.mLine, aFrame);
    576  const int32_t lineStyle = LookAndFeel::GetInt(styleIDs.mLineStyle);
    577  auto style = static_cast<StyleTextDecorationStyle>(lineStyle);
    578  if (lineStyle > static_cast<int32_t>(StyleTextDecorationStyle::Sentinel)) {
    579    NS_ERROR("Invalid underline style value is specified");
    580    style = StyleTextDecorationStyle::Solid;
    581  }
    582  float size = LookAndFeel::GetFloat(styleIDs.mLineRelativeSize);
    583 
    584  NS_ASSERTION(size, "selection underline relative size must be larger than 0");
    585 
    586  if (aLineColor) {
    587    *aLineColor = color;
    588  }
    589  *aRelativeSize = size;
    590  *aStyle = style;
    591 
    592  return style != StyleTextDecorationStyle::None && color != NS_TRANSPARENT &&
    593         size > 0.0f;
    594 }
    595 
    596 bool nsTextPaintStyle::GetSelectionShadow(
    597    Span<const StyleSimpleShadow>* aShadows) {
    598  if (!InitSelectionColorsAndShadow()) {
    599    return false;
    600  }
    601 
    602  if (mSelectionPseudoStyle) {
    603    *aShadows = mSelectionPseudoStyle->StyleText()->mTextShadow.AsSpan();
    604    return true;
    605  }
    606 
    607  return false;
    608 }
    609 
    610 inline nscolor Get40PercentColor(nscolor aForeColor, nscolor aBackColor) {
    611  nscolor foreColor = NS_RGBA(NS_GET_R(aForeColor), NS_GET_G(aForeColor),
    612                              NS_GET_B(aForeColor), (uint8_t)(255 * 0.4f));
    613  // Don't use true alpha color for readability.
    614  return NS_ComposeColors(aBackColor, foreColor);
    615 }
    616 
    617 nscolor nsTextPaintStyle::GetResolvedForeColor(nscolor aColor,
    618                                               nscolor aDefaultForeColor,
    619                                               nscolor aBackColor) {
    620  if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
    621    return aDefaultForeColor;
    622  }
    623 
    624  if (aColor != NS_40PERCENT_FOREGROUND_COLOR) {
    625    return aColor;
    626  }
    627 
    628  // Get actual background color
    629  nscolor actualBGColor = aBackColor;
    630  if (actualBGColor == NS_TRANSPARENT) {
    631    InitCommonColors();
    632    actualBGColor = mFrameBackgroundColor;
    633  }
    634  return Get40PercentColor(aDefaultForeColor, actualBGColor);
    635 }
    636 
    637 nscolor nsTextPaintStyle::GetWebkitTextStrokeColor() {
    638  if (mFrame->IsInSVGTextSubtree()) {
    639    return 0;
    640  }
    641  return mFrame->StyleText()->mWebkitTextStrokeColor.CalcColor(mFrame);
    642 }
    643 
    644 float nsTextPaintStyle::GetWebkitTextStrokeWidth() {
    645  if (mFrame->IsInSVGTextSubtree()) {
    646    return 0.0f;
    647  }
    648  nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
    649  return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
    650 }