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 }