mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1110039 - Part 2.2 - Add AccessibleCaret. r=roc
See AccessibleCaret.h for the class description. Technical difference between AccessibleCaret and Touch/SelectionCarets: The anonymous dom element containing a caret image will be created by AccessibleCaret by using the API landed in bug 1020244 instead of being created by nsCanvasFrame.
This commit is contained in:
parent
7116f8917d
commit
206548e5fb
269
layout/base/AccessibleCaret.cpp
Normal file
269
layout/base/AccessibleCaret.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
/* -*- 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 "AccessibleCaret.h"
|
||||
|
||||
#include "AccessibleCaretLogger.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCanvasFrame.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsDOMTokenList.h"
|
||||
#include "nsIFrame.h"
|
||||
|
||||
namespace mozilla {
|
||||
using namespace dom;
|
||||
|
||||
#undef AC_LOG
|
||||
#define AC_LOG(message, ...) \
|
||||
AC_LOG_BASE("AccessibleCaret (%p): " message, this, ##__VA_ARGS__);
|
||||
|
||||
#undef AC_LOGV
|
||||
#define AC_LOGV(message, ...) \
|
||||
AC_LOGV_BASE("AccessibleCaret (%p): " message, this, ##__VA_ARGS__);
|
||||
|
||||
NS_IMPL_ISUPPORTS(AccessibleCaret::DummyTouchListener, nsIDOMEventListener)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of AccessibleCaret methods
|
||||
|
||||
AccessibleCaret::AccessibleCaret(nsIPresShell* aPresShell)
|
||||
: mPresShell(aPresShell)
|
||||
{
|
||||
// Check all resources required.
|
||||
MOZ_ASSERT(mPresShell);
|
||||
MOZ_ASSERT(RootFrame());
|
||||
MOZ_ASSERT(mPresShell->GetDocument());
|
||||
MOZ_ASSERT(mPresShell->GetCanvasFrame());
|
||||
MOZ_ASSERT(mPresShell->GetCanvasFrame()->GetCustomContentContainer());
|
||||
|
||||
InjectCaretElement(mPresShell->GetDocument());
|
||||
}
|
||||
|
||||
AccessibleCaret::~AccessibleCaret()
|
||||
{
|
||||
RemoveCaretElement(mPresShell->GetDocument());
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::SetAppearance(Appearance aAppearance)
|
||||
{
|
||||
if (mAppearance == aAppearance) {
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
CaretElement()->ClassList()->Remove(AppearanceString(mAppearance), rv);
|
||||
MOZ_ASSERT(!rv.Failed(), "Remove old appearance failed!");
|
||||
|
||||
CaretElement()->ClassList()->Add(AppearanceString(aAppearance), rv);
|
||||
MOZ_ASSERT(!rv.Failed(), "Add new appearance failed!");
|
||||
|
||||
mAppearance = aAppearance;
|
||||
|
||||
// Need to reset rect since the cached rect will be compared in SetPosition.
|
||||
if (mAppearance == Appearance::None) {
|
||||
mImaginaryCaretRect = nsRect();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::SetSelectionBarEnabled(bool aEnabled)
|
||||
{
|
||||
if (mSelectionBarEnabled == aEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AC_LOG("%s, enabled %d", __FUNCTION__, aEnabled);
|
||||
|
||||
ErrorResult rv;
|
||||
CaretElement()->ClassList()->Toggle(NS_LITERAL_STRING("no-bar"),
|
||||
Optional<bool>(!aEnabled), rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
mSelectionBarEnabled = aEnabled;
|
||||
}
|
||||
|
||||
/* static */ nsString
|
||||
AccessibleCaret::AppearanceString(Appearance aAppearance)
|
||||
{
|
||||
nsAutoString string;
|
||||
switch (aAppearance) {
|
||||
case Appearance::None:
|
||||
case Appearance::NormalNotShown:
|
||||
string = NS_LITERAL_STRING("none");
|
||||
break;
|
||||
case Appearance::Normal:
|
||||
string = NS_LITERAL_STRING("normal");
|
||||
break;
|
||||
case Appearance::Right:
|
||||
string = NS_LITERAL_STRING("right");
|
||||
break;
|
||||
case Appearance::Left:
|
||||
string = NS_LITERAL_STRING("left");
|
||||
break;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
bool
|
||||
AccessibleCaret::Intersects(const AccessibleCaret& aCaret) const
|
||||
{
|
||||
MOZ_ASSERT(mPresShell == aCaret.mPresShell);
|
||||
|
||||
if (!IsVisuallyVisible() || !aCaret.IsVisuallyVisible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRect rect = nsLayoutUtils::GetRectRelativeToFrame(CaretElement(), RootFrame());
|
||||
nsRect rhsRect = nsLayoutUtils::GetRectRelativeToFrame(aCaret.CaretElement(), RootFrame());
|
||||
return rect.Intersects(rhsRect);
|
||||
}
|
||||
|
||||
bool
|
||||
AccessibleCaret::Contains(const nsPoint& aPoint) const
|
||||
{
|
||||
if (!IsVisuallyVisible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRect rect =
|
||||
nsLayoutUtils::GetRectRelativeToFrame(CaretImageElement(), RootFrame());
|
||||
|
||||
return rect.Contains(aPoint);
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::InjectCaretElement(nsIDocument* aDocument)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<Element> element = CreateCaretElement(aDocument);
|
||||
mCaretElementHolder = aDocument->InsertAnonymousContent(*element, rv);
|
||||
|
||||
MOZ_ASSERT(!rv.Failed(), "Insert anonymous content should not fail!");
|
||||
MOZ_ASSERT(mCaretElementHolder.get(), "We must have anonymous content!");
|
||||
|
||||
// InsertAnonymousContent will clone the element to make an AnonymousContent.
|
||||
// Since event listeners are not being cloned when cloning a node, we need to
|
||||
// add the listener here.
|
||||
CaretElement()->AddEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
AccessibleCaret::CreateCaretElement(nsIDocument* aDocument) const
|
||||
{
|
||||
// Content structure of AccessibleCaret
|
||||
// <div class="moz-accessiblecaret"> <- CaretElement()
|
||||
// <div class="image"> <- CaretImageElement()
|
||||
// <div class="bar"> <- SelectionBarElement()
|
||||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<Element> parent = aDocument->CreateHTMLElement(nsGkAtoms::div);
|
||||
parent->ClassList()->Add(NS_LITERAL_STRING("moz-accessiblecaret"), rv);
|
||||
parent->ClassList()->Add(NS_LITERAL_STRING("none"), rv);
|
||||
parent->ClassList()->Add(NS_LITERAL_STRING("no-bar"), rv);
|
||||
|
||||
nsCOMPtr<Element> image = aDocument->CreateHTMLElement(nsGkAtoms::div);
|
||||
image->ClassList()->Add(NS_LITERAL_STRING("image"), rv);
|
||||
parent->AppendChildTo(image, false);
|
||||
|
||||
nsCOMPtr<Element> bar = aDocument->CreateHTMLElement(nsGkAtoms::div);
|
||||
bar->ClassList()->Add(NS_LITERAL_STRING("bar"), rv);
|
||||
parent->AppendChildTo(bar, false);
|
||||
|
||||
return parent.forget();
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::RemoveCaretElement(nsIDocument* aDocument)
|
||||
{
|
||||
CaretElement()->RemoveEventListener(NS_LITERAL_STRING("touchstart"),
|
||||
mDummyTouchListener, false);
|
||||
|
||||
ErrorResult rv;
|
||||
aDocument->RemoveAnonymousContent(*mCaretElementHolder, rv);
|
||||
// It's OK rv is failed since nsCanvasFrame might not exists now.
|
||||
}
|
||||
|
||||
AccessibleCaret::PositionChangedResult
|
||||
AccessibleCaret::SetPosition(nsIFrame* aFrame, int32_t aOffset)
|
||||
{
|
||||
if (!CustomContentContainerFrame()) {
|
||||
return PositionChangedResult::NotChanged;
|
||||
}
|
||||
|
||||
nsRect imaginaryCaretRectInFrame =
|
||||
nsCaret::GetGeometryForFrame(aFrame, aOffset, nullptr);
|
||||
|
||||
imaginaryCaretRectInFrame =
|
||||
nsLayoutUtils::ClampRectToScrollFrames(aFrame, imaginaryCaretRectInFrame);
|
||||
|
||||
if (imaginaryCaretRectInFrame.IsEmpty()) {
|
||||
// Don't bother to set the caret position since it's invisible.
|
||||
return PositionChangedResult::Invisible;
|
||||
}
|
||||
|
||||
nsRect imaginaryCaretRect = imaginaryCaretRectInFrame;
|
||||
nsLayoutUtils::TransformRect(aFrame, RootFrame(), imaginaryCaretRect);
|
||||
|
||||
if (imaginaryCaretRect.IsEqualEdges(mImaginaryCaretRect)) {
|
||||
return PositionChangedResult::NotChanged;
|
||||
}
|
||||
|
||||
mImaginaryCaretRect = imaginaryCaretRect;
|
||||
|
||||
// SetCaretElementPosition() and SetSelectionBarElementPosition() require the
|
||||
// input rect relative to container frame.
|
||||
nsRect imaginaryCaretRectInContainerFrame = imaginaryCaretRectInFrame;
|
||||
nsLayoutUtils::TransformRect(aFrame, CustomContentContainerFrame(),
|
||||
imaginaryCaretRectInContainerFrame);
|
||||
SetCaretElementPosition(imaginaryCaretRectInContainerFrame);
|
||||
SetSelectionBarElementPosition(imaginaryCaretRectInContainerFrame);
|
||||
|
||||
return PositionChangedResult::Changed;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
AccessibleCaret::CustomContentContainerFrame() const
|
||||
{
|
||||
nsCanvasFrame* canvasFrame = mPresShell->GetCanvasFrame();
|
||||
Element* container = canvasFrame->GetCustomContentContainer();
|
||||
nsIFrame* containerFrame = container->GetPrimaryFrame();
|
||||
return containerFrame;
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::SetCaretElementPosition(const nsRect& aRect)
|
||||
{
|
||||
nsPoint position = CaretElementPosition(aRect);
|
||||
nsAutoString styleStr;
|
||||
styleStr.AppendPrintf("left: %dpx; top: %dpx;",
|
||||
nsPresContext::AppUnitsToIntCSSPixels(position.x),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(position.y));
|
||||
|
||||
ErrorResult rv;
|
||||
CaretElement()->SetAttribute(NS_LITERAL_STRING("style"), styleStr, rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
AC_LOG("Set caret style: %s", NS_ConvertUTF16toUTF8(styleStr).get());
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaret::SetSelectionBarElementPosition(const nsRect& aRect)
|
||||
{
|
||||
int32_t height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
|
||||
nsAutoString barStyleStr;
|
||||
barStyleStr.AppendPrintf("margin-top: -%dpx; height: %dpx;",
|
||||
height, height);
|
||||
|
||||
ErrorResult rv;
|
||||
SelectionBarElement()->SetAttribute(NS_LITERAL_STRING("style"), barStyleStr, rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
|
||||
AC_LOG("Set bar style: %s", NS_ConvertUTF16toUTF8(barStyleStr).get());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
209
layout/base/AccessibleCaret.h
Normal file
209
layout/base/AccessibleCaret.h
Normal file
@ -0,0 +1,209 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef AccessibleCaret_h__
|
||||
#define AccessibleCaret_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/AnonymousContent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISupportsBase.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
class nsIPresShell;
|
||||
struct nsPoint;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Upon the creation of AccessibleCaret, it will insert DOM Element as an
|
||||
// anonymous content containing the caret image. The caret appearance and
|
||||
// position can be controlled by SetAppearance() and SetPosition().
|
||||
//
|
||||
// All the rect or point are relative to root frame except being specified
|
||||
// explicitly.
|
||||
//
|
||||
// None of the methods in AccessibleCaret will flush layout or style. To ensure
|
||||
// that SetPosition() works correctly, the caller must make sure the layout is
|
||||
// up to date.
|
||||
//
|
||||
class AccessibleCaret final
|
||||
{
|
||||
public:
|
||||
explicit AccessibleCaret(nsIPresShell* aPresShell);
|
||||
~AccessibleCaret();
|
||||
|
||||
// This enumeration representing the visibility and visual style of an
|
||||
// AccessibleCaret.
|
||||
//
|
||||
// Use SetAppearance() to change the appearance, and use GetAppearance() to
|
||||
// get the current appearance.
|
||||
enum class Appearance : uint8_t {
|
||||
// Do not display the caret at all.
|
||||
None,
|
||||
|
||||
// Display the caret in default style.
|
||||
Normal,
|
||||
|
||||
// The caret should be displayed logically but it is kept invisible to the
|
||||
// user. This enum is the only difference between "logically visible" and
|
||||
// "visually visible". It can be used for reasons such as:
|
||||
// 1. Out of scroll port.
|
||||
// 2. For UX requirement such as hide a caret in an empty text area.
|
||||
NormalNotShown,
|
||||
|
||||
// Display the caret which is tilted to the left.
|
||||
Left,
|
||||
|
||||
// Display the caret which is tilted to the right.
|
||||
Right
|
||||
};
|
||||
|
||||
Appearance GetAppearance() const
|
||||
{
|
||||
return mAppearance;
|
||||
}
|
||||
|
||||
void SetAppearance(Appearance aAppearance);
|
||||
|
||||
// Return true if current appearance is either Normal, NormalNotShown, Left,
|
||||
// or Right.
|
||||
bool IsLogicallyVisible() const
|
||||
{
|
||||
return mAppearance != Appearance::None;
|
||||
}
|
||||
|
||||
// Return true if current appearance is either Normal, Left, or Right.
|
||||
bool IsVisuallyVisible() const
|
||||
{
|
||||
return (mAppearance != Appearance::None) &&
|
||||
(mAppearance != Appearance::NormalNotShown);
|
||||
}
|
||||
|
||||
// Set true to enable the "Text Selection Bar" described in "Text Selection
|
||||
// Visual Spec" in bug 921965.
|
||||
void SetSelectionBarEnabled(bool aEnabled);
|
||||
|
||||
// This enumeration representing the result returned by SetPosition().
|
||||
enum class PositionChangedResult : uint8_t {
|
||||
// Position is not changed.
|
||||
NotChanged,
|
||||
|
||||
// Position is changed.
|
||||
Changed,
|
||||
|
||||
// Position is out of scroll port.
|
||||
Invisible
|
||||
};
|
||||
PositionChangedResult SetPosition(nsIFrame* aFrame, int32_t aOffset);
|
||||
|
||||
// Does two AccessibleCarets overlap?
|
||||
bool Intersects(const AccessibleCaret& aCaret) const;
|
||||
|
||||
// Is the point within the caret's rect? The point should be relative to root
|
||||
// frame.
|
||||
bool Contains(const nsPoint& aPoint) const;
|
||||
|
||||
// The geometry center of the imaginary caret (nsCaret) to which this
|
||||
// AccessibleCaret is attached. It is needed when dragging the caret.
|
||||
nsPoint LogicalPosition() const
|
||||
{
|
||||
return mImaginaryCaretRect.Center();
|
||||
}
|
||||
|
||||
// Element for 'Intersects' test. Container of image and bar elements.
|
||||
dom::Element* CaretElement() const
|
||||
{
|
||||
return mCaretElementHolder->GetContentNode();
|
||||
}
|
||||
|
||||
private:
|
||||
// Argument aRect should be relative to CustomContentContainerFrame().
|
||||
void SetCaretElementPosition(const nsRect& aRect);
|
||||
void SetSelectionBarElementPosition(const nsRect& aRect);
|
||||
|
||||
// Element which contains the caret image for 'Contains' test.
|
||||
dom::Element* CaretImageElement() const
|
||||
{
|
||||
return CaretElement()->GetFirstElementChild();
|
||||
}
|
||||
|
||||
// Element which represents the text selection bar.
|
||||
dom::Element* SelectionBarElement() const
|
||||
{
|
||||
return CaretElement()->GetLastElementChild();
|
||||
}
|
||||
|
||||
nsIFrame* RootFrame() const
|
||||
{
|
||||
return mPresShell->GetRootFrame();
|
||||
}
|
||||
|
||||
nsIFrame* CustomContentContainerFrame() const;
|
||||
|
||||
// Transform Appearance to CSS class name in ua.css.
|
||||
static nsString AppearanceString(Appearance aAppearance);
|
||||
|
||||
already_AddRefed<dom::Element> CreateCaretElement(nsIDocument* aDocument) const;
|
||||
|
||||
// Inject caret element into custom content container.
|
||||
void InjectCaretElement(nsIDocument* aDocument);
|
||||
|
||||
// Remove caret element from custom content container.
|
||||
void RemoveCaretElement(nsIDocument* aDocument);
|
||||
|
||||
// The bottom-center of the imaginary caret to which this AccessibleCaret is
|
||||
// attached.
|
||||
static nsPoint CaretElementPosition(const nsRect& aRect)
|
||||
{
|
||||
return aRect.TopLeft() + nsPoint(aRect.width / 2, aRect.height);
|
||||
}
|
||||
|
||||
class DummyTouchListener final : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~DummyTouchListener() {};
|
||||
};
|
||||
|
||||
// Member variables
|
||||
Appearance mAppearance = Appearance::None;
|
||||
|
||||
bool mSelectionBarEnabled = false;
|
||||
|
||||
// AccessibleCaretManager owns us. When it's destroyed by
|
||||
// AccessibleCaretEventHub::Terminate() which is called in
|
||||
// PresShell::Destroy(), it frees us automatically. No need to worry we
|
||||
// outlive mPresShell.
|
||||
nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr;
|
||||
|
||||
nsRefPtr<dom::AnonymousContent> mCaretElementHolder;
|
||||
|
||||
// mImaginaryCaretRect is relative to root frame.
|
||||
nsRect mImaginaryCaretRect;
|
||||
|
||||
// A no-op touch-start listener which prevents APZ from panning when dragging
|
||||
// the caret.
|
||||
nsRefPtr<DummyTouchListener> mDummyTouchListener{new DummyTouchListener()};
|
||||
|
||||
}; // class AccessibleCaret
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // AccessibleCaret_h__
|
@ -314,6 +314,100 @@ parsererror|sourcetext {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret,
|
||||
div:-moz-native-anonymous.moz-accessiblecaret > div.image,
|
||||
div:-moz-native-anonymous.moz-accessiblecaret > div.bar {
|
||||
position: absolute;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret {
|
||||
width: 44px;
|
||||
height: 47px;
|
||||
margin-left: -23px;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret > div.image {
|
||||
background-position: center center;
|
||||
background-size: 100% 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
/* Override this property in moz-custom-content-container to make dummy touch
|
||||
* listener work. */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret > div.bar {
|
||||
margin-left: 49%;
|
||||
width: 2px;
|
||||
background-color: #008aa0;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.no-bar > div.bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.normal > div.image {
|
||||
background-image: url("resource://gre/res/text_caret.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.left > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left.png");
|
||||
margin-left: -39%;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.right > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right.png");
|
||||
margin-left: 41%;
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.normal > div.image {
|
||||
background-image: url("resource://gre/res/text_caret@1.5x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.left > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@1.5x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.right > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@1.5x.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.normal > div.image {
|
||||
background-image: url("resource://gre/res/text_caret@2x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.left > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@2x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.right > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 2.25dppx) {
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.normal > div.image {
|
||||
background-image: url("resource://gre/res/text_caret@2.25x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.left > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_left@2.25x.png");
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-accessiblecaret.right > div.image {
|
||||
background-image: url("resource://gre/res/text_caret_tilt_right@2.25x.png");
|
||||
}
|
||||
}
|
||||
|
||||
div:-moz-native-anonymous.moz-touchcaret,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-left,
|
||||
div:-moz-native-anonymous.moz-selectioncaret-right {
|
||||
|
Loading…
Reference in New Issue
Block a user