Bug 1360500 - Allow custom colors on find selection type selections. r=jaws, r=masayuki, r=smaug
This patch implements chrome-only Selection#setColors and
Selection#resetColors methods, and use it to set the background color of
the preferences search highlight.
MozReview-Commit-ID: 2U92aBCAyeh
--- a/browser/components/preferences/in-content/findInPage.js
+++ b/browser/components/preferences/in-content/findInPage.js
@@ -7,16 +7,17 @@
var gSearchResultsPane = {
findSelection: null,
searchResultsCategory: null,
searchInput: null,
init() {
let controller = this.getSelectionController();
this.findSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
+ this.findSelection.setColors("currentColor", "#ffe900", "currentColor", "#540ead");
this.searchResultsCategory = document.getElementById("category-search-results");
this.searchInput = document.getElementById("searchInput");
this.searchInput.hidden = !Services.prefs.getBoolPref("browser.preferences.search");
if (!this.searchInput.hidden) {
this.searchInput.addEventListener("command", this);
this.searchInput.addEventListener("focus", this);
}
--- a/dom/base/nsISelectionPrivate.idl
+++ b/dom/base/nsISelectionPrivate.idl
@@ -156,10 +156,40 @@ interface nsISelectionPrivate : nsISelec
in ScrollAxis aHorizontal);
/**
* Modifies the cursor Bidi level after a change in keyboard direction
* @param langRTL is PR_TRUE if the new language is right-to-left or
* PR_FALSE if the new language is left-to-right.
*/
[noscript] void selectionLanguageChange(in boolean langRTL);
+
+ /**
+ * setColors() sets custom colors for the selection.
+ * Currently, this is supported only when the selection type is SELECTION_FIND.
+ * Otherwise, throws an exception.
+ *
+ * @param aForegroundColor The foreground color of the selection.
+ * If this is "currentColor", foreground color
+ * isn't changed by this selection.
+ * @param aBackgroundColor The background color of the selection.
+ * If this is "transparent", background color is
+ * never painted.
+ * @param aAltForegroundColor The alternative foreground color of the
+ * selection.
+ * If aBackgroundColor doesn't have sufficient
+ * contrast with its around or foreground color
+ * if "currentColor" is specified, alternative
+ * colors are used if it have higher contrast.
+ * @param aAltBackgroundColor The alternative background color of the
+ * selection.
+ */
+ void setColors(in DOMString aForegroundColor,
+ in DOMString aBackgroundColor,
+ in DOMString aAltForegroundColor,
+ in DOMString aAltBackgroundColor);
+
+ /**
+ * resetColors() forget the customized colors which were set by setColors().
+ */
+ void resetColors();
};
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -85,9 +85,16 @@ partial interface Selection {
readonly attribute short type;
[ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,
boolean allowAdjacent);
[ChromeOnly,Throws]
void scrollIntoView(short aRegion, boolean aIsSynchronous, short aVPercent, short aHPercent);
+
+ [ChromeOnly,Throws]
+ void setColors(DOMString aForegroundColor, DOMString aBackgroundColor,
+ DOMString aAltForegroundColor, DOMString aAltBackgroundColor);
+
+ [ChromeOnly,Throws]
+ void resetColors();
};
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -25,16 +25,17 @@ class nsAutoScrollTimer;
class nsIContentIterator;
class nsIDocument;
class nsIEditor;
class nsIFrame;
class nsIHTMLEditor;
class nsFrameSelection;
class nsPIDOMWindowOuter;
struct SelectionDetails;
+struct SelectionCustomColors;
class nsCopySupport;
class nsHTMLCopyEncoder;
namespace mozilla {
class ErrorResult;
struct AutoPrepareFocusRange;
} // namespace mozilla
@@ -246,16 +247,22 @@ public:
bool aAllowAdjacent,
nsTArray<RefPtr<nsRange>>& aReturn,
mozilla::ErrorResult& aRv);
void ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
int16_t aVPercent, int16_t aHPercent,
mozilla::ErrorResult& aRv);
+ void SetColors(const nsAString& aForeColor, const nsAString& aBackColor,
+ const nsAString& aAltForeColor, const nsAString& aAltBackColor,
+ mozilla::ErrorResult& aRv);
+
+ void ResetColors(mozilla::ErrorResult& aRv);
+
// Non-JS callers should use the following methods.
void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
void CollapseToStart(mozilla::ErrorResult& aRv);
void CollapseToEnd(mozilla::ErrorResult& aRv);
void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv);
void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
@@ -279,16 +286,18 @@ private:
public:
SelectionType GetType() const { return mSelectionType; }
void SetType(SelectionType aSelectionType)
{
mSelectionType = aSelectionType;
}
+ SelectionCustomColors* GetCustomColors() const { return mCustomColors.get(); }
+
nsresult NotifySelectionListeners(bool aCalledByJS);
nsresult NotifySelectionListeners();
friend struct AutoUserInitiated;
struct MOZ_RAII AutoUserInitiated
{
explicit AutoUserInitiated(Selection* aSelection
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -413,19 +422,21 @@ private:
// O(log n) time, though this would require rebalancing and other overhead.
nsTArray<RangeData> mRanges;
RefPtr<nsRange> mAnchorFocusRange;
RefPtr<nsFrameSelection> mFrameSelection;
RefPtr<nsAutoScrollTimer> mAutoScrollTimer;
nsCOMArray<nsISelectionListener> mSelectionListeners;
nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
- CachedOffsetForFrame *mCachedOffsetForFrame;
+ CachedOffsetForFrame* mCachedOffsetForFrame;
nsDirection mDirection;
SelectionType mSelectionType;
+ UniquePtr<SelectionCustomColors> mCustomColors;
+
/**
* True if the current selection operation was initiated by user action.
* It determines whether we exclude -moz-user-select:none nodes or not,
* as well as whether selectstart events will be fired.
*/
bool mUserInitiated;
/**
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -40,16 +40,34 @@ struct SelectionDetails
#endif
int32_t mStart;
int32_t mEnd;
mozilla::SelectionType mSelectionType;
mozilla::TextRangeStyle mTextRangeStyle;
mozilla::UniquePtr<SelectionDetails> mNext;
};
+struct SelectionCustomColors
+{
+#ifdef NS_BUILD_REFCNT_LOGGING
+ SelectionCustomColors()
+ {
+ MOZ_COUNT_CTOR(SelectionCustomColors);
+ }
+ ~SelectionCustomColors()
+ {
+ MOZ_COUNT_DTOR(SelectionCustomColors);
+ }
+#endif
+ mozilla::Maybe<nscolor> mForegroundColor;
+ mozilla::Maybe<nscolor> mBackgroundColor;
+ mozilla::Maybe<nscolor> mAltForegroundColor;
+ mozilla::Maybe<nscolor> mAltBackgroundColor;
+};
+
class nsIPresShell;
/** PeekOffsetStruct is used to group various arguments (both input and output)
* that are passed to nsFrame::PeekOffset(). See below for the description of
* individual arguments.
*/
struct MOZ_STACK_CLASS nsPeekOffsetStruct
{
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -3485,27 +3485,29 @@ nsFrameSelection::DisconnectFromPresShel
// mozilla::dom::Selection implementation
// note: this can return a nil anchor node
Selection::Selection()
: mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mSelectionType(SelectionType::eNormal)
+ , mCustomColors(nullptr)
, mUserInitiated(false)
, mCalledByJS(false)
, mSelectionChangeBlockerCount(0)
{
}
Selection::Selection(nsFrameSelection* aList)
: mFrameSelection(aList)
, mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mSelectionType(SelectionType::eNormal)
+ , mCustomColors(nullptr)
, mUserInitiated(false)
, mCalledByJS(false)
, mSelectionChangeBlockerCount(0)
{
}
Selection::~Selection()
{
@@ -6816,16 +6818,112 @@ Selection::SelectionLanguageChange(bool
// The caret might have moved, so invalidate the desired position
// for future usages of up-arrow or down-arrow
frameSelection->InvalidateDesiredPos();
return NS_OK;
}
+NS_IMETHODIMP
+Selection::SetColors(const nsAString& aForegroundColor,
+ const nsAString& aBackgroundColor,
+ const nsAString& aAltForegroundColor,
+ const nsAString& aAltBackgroundColor)
+{
+ ErrorResult result;
+ SetColors(aForegroundColor, aBackgroundColor,
+ aAltForegroundColor, aAltBackgroundColor, result);
+ return result.StealNSResult();
+}
+
+void
+Selection::SetColors(const nsAString& aForegroundColor,
+ const nsAString& aBackgroundColor,
+ const nsAString& aAltForegroundColor,
+ const nsAString& aAltBackgroundColor,
+ ErrorResult& aRv)
+{
+ if (mSelectionType != SelectionType::eFind) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ mCustomColors.reset(new SelectionCustomColors);
+
+ NS_NAMED_LITERAL_STRING(currentColorStr, "currentColor");
+ NS_NAMED_LITERAL_STRING(transparentStr, "transparent");
+
+ if (!aForegroundColor.Equals(currentColorStr)) {
+ nscolor foregroundColor;
+ nsAttrValue aForegroundColorValue;
+ aForegroundColorValue.ParseColor(aForegroundColor);
+ if (!aForegroundColorValue.GetColorValue(foregroundColor)) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+ mCustomColors->mForegroundColor = Some(foregroundColor);
+ } else {
+ mCustomColors->mForegroundColor = Nothing();
+ }
+
+ if (!aBackgroundColor.Equals(transparentStr)) {
+ nscolor backgroundColor;
+ nsAttrValue aBackgroundColorValue;
+ aBackgroundColorValue.ParseColor(aBackgroundColor);
+ if (!aBackgroundColorValue.GetColorValue(backgroundColor)) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+ mCustomColors->mBackgroundColor = Some(backgroundColor);
+ } else {
+ mCustomColors->mBackgroundColor = Nothing();
+ }
+
+ if (!aAltForegroundColor.Equals(currentColorStr)) {
+ nscolor altForegroundColor;
+ nsAttrValue aAltForegroundColorValue;
+ aAltForegroundColorValue.ParseColor(aAltForegroundColor);
+ if (!aAltForegroundColorValue.GetColorValue(altForegroundColor)) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+ mCustomColors->mAltForegroundColor = Some(altForegroundColor);
+ } else {
+ mCustomColors->mAltForegroundColor = Nothing();
+ }
+
+ if (!aAltBackgroundColor.Equals(transparentStr)) {
+ nscolor altBackgroundColor;
+ nsAttrValue aAltBackgroundColorValue;
+ aAltBackgroundColorValue.ParseColor(aAltBackgroundColor);
+ if (!aAltBackgroundColorValue.GetColorValue(altBackgroundColor)) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return;
+ }
+ mCustomColors->mAltBackgroundColor = Some(altBackgroundColor);
+ } else {
+ mCustomColors->mAltBackgroundColor = Nothing();
+ }
+}
+
+NS_IMETHODIMP
+Selection::ResetColors()
+{
+ ErrorResult result;
+ ResetColors(result);
+ return result.StealNSResult();
+}
+
+void
+Selection::ResetColors(ErrorResult& aRv)
+{
+ mCustomColors = nullptr;
+}
+
NS_IMETHODIMP_(nsDirection)
Selection::GetSelectionDirection() {
return mDirection;
}
NS_IMETHODIMP_(void)
Selection::SetSelectionDirection(nsDirection aDirection) {
mDirection = aDirection;
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -3823,23 +3823,96 @@ nsTextPaintStyle::GetSelectionColors(nsc
void
nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
nscolor* aBackColor)
{
NS_ASSERTION(aForeColor, "aForeColor is null");
NS_ASSERTION(aBackColor, "aBackColor is null");
- nscolor backColor =
- LookAndFeel::GetColor(LookAndFeel::eColorID_TextHighlightBackground);
- nscolor foreColor =
- LookAndFeel::GetColor(LookAndFeel::eColorID_TextHighlightForeground);
- EnsureSufficientContrast(&foreColor, &backColor);
- *aForeColor = foreColor;
- *aBackColor = backColor;
+ 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::GetColor(LookAndFeel::eColorID_TextHighlightBackground);
+ nscolor foreColor =
+ LookAndFeel::GetColor(LookAndFeel::eColorID_TextHighlightForeground);
+ 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;
+ }
+
+ if (customColors->mBackgroundColor) {
+ // !mForegroundColor means "currentColor"; the current color of the text.
+ nscolor foreColor = GetTextColor();
+ nscolor backColor = *customColors->mBackgroundColor;
+
+ if (customColors->mAltBackgroundColor) {
+ int32_t foreLuminosityDifference =
+ NS_LUMINOSITY_DIFFERENCE(foreColor, backColor);
+
+ // The sufficient luminosity difference is based on the link color of
+ // about:preferences, so we don't invert the background color on these text.
+ // XXX: Make this more generic.
+ int32_t sufficientLuminosityDifference =
+ NS_LUMINOSITY_DIFFERENCE(NS_RGBA(23, 140, 229, 255), backColor);
+
+ if (foreLuminosityDifference < sufficientLuminosityDifference) {
+ backColor = *customColors->mAltBackgroundColor;
+ }
+ }
+
+ *aForeColor = foreColor;
+ *aBackColor = backColor;
+ return;
+ }
+
+ if (customColors->mForegroundColor) {
+ nscolor foreColor = *customColors->mForegroundColor;
+ // !mBackgroundColor means "transparent"; the current color of the background.
+ nscolor backColor = mFrameBackgroundColor;
+
+ if (customColors->mAltForegroundColor &&
+ EnsureSufficientContrast(&foreColor, &backColor)) {
+ foreColor = *customColors->mAltForegroundColor;
+ backColor = mFrameBackgroundColor;
+ }
+
+ *aForeColor = foreColor;
+ *aBackColor = backColor;
+ return;
+ }
+
+ // There are neither mForegroundColor nor mBackgroundColor.
+ *aForeColor = GetTextColor();
+ *aBackColor = NS_TRANSPARENT;
}
void
nsTextPaintStyle::GetURLSecondaryColor(nscolor* aForeColor)
{
NS_ASSERTION(aForeColor, "aForeColor is null");
nscolor textColor = GetTextColor();
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -6,16 +6,17 @@
#ifndef nsTextFrame_h__
#define nsTextFrame_h__
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
#include "nsFrame.h"
+#include "nsFrameSelection.h"
#include "nsSplittableFrame.h"
#include "nsLineBox.h"
#include "gfxSkipChars.h"
#include "gfxTextRun.h"
#include "nsDisplayList.h"
#include "JustificationUtils.h"
#include "RubyUtils.h"