summaryrefslogtreecommitdiffstats
path: root/accessible/base/TextLeafRange.h
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/base/TextLeafRange.h')
-rw-r--r--accessible/base/TextLeafRange.h360
1 files changed, 360 insertions, 0 deletions
diff --git a/accessible/base/TextLeafRange.h b/accessible/base/TextLeafRange.h
new file mode 100644
index 0000000000..23fea2ecfb
--- /dev/null
+++ b/accessible/base/TextLeafRange.h
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 mozilla_a11y_TextLeafRange_h__
+#define mozilla_a11y_TextLeafRange_h__
+
+#include <stdint.h>
+
+#include "AccAttributes.h"
+#include "nsDirection.h"
+#include "nsIAccessibleText.h"
+
+class nsRange;
+
+namespace mozilla {
+namespace dom {
+class Document;
+}
+
+namespace a11y {
+class Accessible;
+class LocalAccessible;
+
+/**
+ * Represents a point within accessible text.
+ * This is stored as a leaf Accessible and an offset into that Accessible.
+ * For an empty Accessible, the offset will always be 0.
+ * This will eventually replace TextPoint. Unlike TextPoint, this does not
+ * use HyperTextAccessible offsets.
+ */
+class TextLeafPoint final {
+ public:
+ TextLeafPoint(Accessible* aAcc, int32_t aOffset);
+
+ /**
+ * Constructs an invalid TextPoint (mAcc is null).
+ * A TextLeafPoint in this state will evaluate to false.
+ * mAcc can be set later. Alternatively, this can be used to indicate an error
+ * (e.g. if a requested point couldn't be found).
+ */
+ TextLeafPoint() : mAcc(nullptr), mOffset(0) {}
+
+ /**
+ * Construct a TextLeafPoint representing the caret.
+ * The actual offset used for the caret differs depending on whether the
+ * caret is at the end of a line and the query being made. Thus, mOffset on
+ * the returned TextLeafPoint is not a valid offset.
+ */
+ static TextLeafPoint GetCaret(Accessible* aAcc) {
+ return TextLeafPoint(aAcc, nsIAccessibleText::TEXT_OFFSET_CARET);
+ }
+
+ Accessible* mAcc;
+ int32_t mOffset;
+
+ bool operator==(const TextLeafPoint& aPoint) const {
+ return mAcc == aPoint.mAcc && mOffset == aPoint.mOffset;
+ }
+
+ bool operator!=(const TextLeafPoint& aPoint) const {
+ return !(*this == aPoint);
+ }
+
+ bool operator<(const TextLeafPoint& aPoint) const;
+
+ bool operator<=(const TextLeafPoint& aPoint) const;
+
+ /**
+ * A valid TextLeafPoint evaluates to true. An invalid TextLeafPoint
+ * evaluates to false.
+ */
+ explicit operator bool() const { return !!mAcc; }
+
+ bool IsCaret() const {
+ return mOffset == nsIAccessibleText::TEXT_OFFSET_CARET;
+ }
+
+ bool IsCaretAtEndOfLine() const;
+
+ /**
+ * Get a TextLeafPoint at the actual caret offset.
+ * This should only be called on a TextLeafPoint created with GetCaret.
+ * If aAdjustAtEndOfLine is true, the point will be adjusted if the caret is
+ * at the end of a line so that word and line boundaries can be calculated
+ * correctly.
+ */
+ TextLeafPoint ActualizeCaret(bool aAdjustAtEndOfLine = true) const;
+
+ enum class BoundaryFlags : uint32_t {
+ eDefaultBoundaryFlags = 0,
+ // Return point unchanged if it is at the given boundary type.
+ eIncludeOrigin = 1 << 0,
+ // If current point is in editable, return point within samme editable.
+ eStopInEditable = 1 << 1,
+ // Skip over list items in searches and don't consider them line or
+ // paragraph starts.
+ eIgnoreListItemMarker = 1 << 2,
+ };
+
+ /**
+ * Find a boundary (word start, line start, etc.) in a specific direction.
+ * If no boundary is found, the start/end of the document is returned
+ * (depending on the direction).
+ */
+ TextLeafPoint FindBoundary(
+ AccessibleTextBoundary aBoundaryType, nsDirection aDirection,
+ BoundaryFlags aFlags = BoundaryFlags::eDefaultBoundaryFlags) const;
+
+ /**
+ * These two functions find a line start boundary within the same
+ * LocalAccessible as this. That is, they do not cross Accessibles. If no
+ * boundary is found, an invalid TextLeafPoint is returned.
+ * These are used by FindBoundary. Most callers will want FindBoundary
+ * instead.
+ */
+ TextLeafPoint FindPrevLineStartSameLocalAcc(bool aIncludeOrigin) const;
+ TextLeafPoint FindNextLineStartSameLocalAcc(bool aIncludeOrigin) const;
+
+ /**
+ * These two functions find a word start boundary within the same
+ * Accessible as this. That is, they do not cross Accessibles. If no
+ * boundary is found, an invalid TextLeafPoint is returned.
+ * These are used by FindBoundary. Most callers will want FindBoundary
+ * instead.
+ */
+ TextLeafPoint FindPrevWordStartSameAcc(bool aIncludeOrigin) const;
+ TextLeafPoint FindNextWordStartSameAcc(bool aIncludeOrigin) const;
+
+ /**
+ * Get the text attributes at this point.
+ * If aIncludeDefaults is true, default attributes on the HyperTextAccessible
+ * will be included.
+ */
+ already_AddRefed<AccAttributes> GetTextAttributes(
+ bool aIncludeDefaults = true) const;
+
+ /**
+ * Get Get the text attributes at this point in a LocalAccessible.
+ * This is used by GetTextAttributes. Most callers will want GetTextAttributes
+ * instead.
+ */
+ already_AddRefed<AccAttributes> GetTextAttributesLocalAcc(
+ bool aIncludeDefaults = true) const;
+
+ /**
+ * Get the offsets of all spelling errors in a given LocalAccessible. This
+ * should only be used when pushing the cache. Most callers will want
+ * FindTextAttrsStart instead.
+ */
+ static nsTArray<int32_t> GetSpellingErrorOffsets(LocalAccessible* aAcc);
+
+ /**
+ * Queue a cache update for a spelling error in a given DOM range.
+ */
+ static void UpdateCachedSpellingError(dom::Document* aDocument,
+ const nsRange& aRange);
+
+ /**
+ * Find the start of a run of text attributes in a specific direction.
+ * A text attributes run is a span of text where the attributes are the same.
+ * If no boundary is found, the start/end of the container is returned
+ * (depending on the direction).
+ * If aIncludeorigin is true and this is at a boundary, this will be
+ * returned unchanged.
+ */
+ TextLeafPoint FindTextAttrsStart(nsDirection aDirection,
+ bool aIncludeOrigin = false) const;
+
+ /**
+ * Returns a rect (in dev pixels) describing position and size of
+ * the character at mOffset in mAcc. This rect is screen-relative.
+ * This function only works on remote accessibles, and assumes caching
+ * is enabled.
+ */
+ LayoutDeviceIntRect CharBounds();
+
+ /**
+ * Returns true if the given point (in screen coords) is contained
+ * in the char bounds of the current TextLeafPoint. Returns false otherwise.
+ * If the current point is an empty container, we use the acc's bounds instead
+ * of char bounds. Because this depends on CharBounds, this function only
+ * works on remote accessibles, and assumes caching is enabled.
+ */
+ bool ContainsPoint(int32_t aX, int32_t aY);
+
+ bool IsLineFeedChar() const { return GetChar() == '\n'; }
+
+ bool IsSpace() const;
+
+ bool IsParagraphStart(bool aIgnoreListItemMarker = false) const {
+ return mOffset == 0 &&
+ FindParagraphSameAcc(eDirPrevious, true, aIgnoreListItemMarker);
+ }
+
+ /**
+ * Translate given TextLeafPoint into a DOM point.
+ */
+ MOZ_CAN_RUN_SCRIPT std::pair<nsIContent*, int32_t> ToDOMPoint(
+ bool aIncludeGenerated = true) const;
+
+ private:
+ bool IsEmptyLastLine() const;
+
+ bool IsDocEdge(nsDirection aDirection) const;
+
+ bool IsLeafAfterListItemMarker() const;
+
+ char16_t GetChar() const;
+
+ TextLeafPoint FindLineStartSameRemoteAcc(nsDirection aDirection,
+ bool aIncludeOrigin) const;
+
+ /**
+ * Helper which just calls the appropriate function based on whether mAcc
+ *is local or remote.
+ */
+ TextLeafPoint FindLineStartSameAcc(nsDirection aDirection,
+ bool aIncludeOrigin,
+ bool aIgnoreListItemMarker = false) const;
+
+ TextLeafPoint FindLineEnd(nsDirection aDirection, BoundaryFlags aFlags) const;
+ TextLeafPoint FindWordEnd(nsDirection aDirection, BoundaryFlags aFlags) const;
+
+ TextLeafPoint FindParagraphSameAcc(nsDirection aDirection,
+ bool aIncludeOrigin,
+ bool aIgnoreListItemMarker = false) const;
+
+ bool IsInSpellingError() const;
+
+ /**
+ * Find a spelling error boundary in the same Accessible. This function
+ * searches for either start or end points, since either means a change in
+ * text attributes.
+ */
+ TextLeafPoint FindSpellingErrorSameAcc(nsDirection aDirection,
+ bool aIncludeOrigin) const;
+
+ // Return the point immediately succeeding or preceding this leaf depending
+ // on given direction.
+ TextLeafPoint NeighborLeafPoint(nsDirection aDirection, bool aIsEditable,
+ bool aIgnoreListItemMarker) const;
+
+ /**
+ * This function assumes mAcc is a LocalAccessible.
+ * It iterates the continuations of mAcc's primary frame until it locates
+ * the continuation containing mOffset (a rendered offset). It then uses
+ * GetScreenRectInAppUnits to compute screen coords for the frame, resizing
+ * such that the resulting rect contains only one character.
+ */
+ LayoutDeviceIntRect ComputeBoundsFromFrame() const;
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextLeafPoint::BoundaryFlags)
+
+/**
+ * Represents a range of accessible text.
+ * This will eventually replace TextRange.
+ */
+class TextLeafRange final {
+ public:
+ TextLeafRange(const TextLeafPoint& aStart, const TextLeafPoint& aEnd)
+ : mStart(aStart), mEnd(aEnd) {}
+ explicit TextLeafRange(const TextLeafPoint& aStart)
+ : mStart(aStart), mEnd(aStart) {}
+ explicit TextLeafRange() {}
+
+ /**
+ * A valid TextLeafRange evaluates to true. An invalid TextLeafRange
+ * evaluates to false.
+ */
+ explicit operator bool() const { return !!mStart && !!mEnd; }
+
+ bool operator!=(const TextLeafRange& aOther) const {
+ return mEnd != aOther.mEnd || mStart != aOther.mStart;
+ }
+
+ bool operator==(const TextLeafRange& aOther) const {
+ return mEnd == aOther.mEnd && mStart == aOther.mStart;
+ }
+
+ TextLeafPoint Start() const { return mStart; }
+ void SetStart(const TextLeafPoint& aStart) { mStart = aStart; }
+ TextLeafPoint End() const { return mEnd; }
+ void SetEnd(const TextLeafPoint& aEnd) { mEnd = aEnd; }
+
+ bool Crop(Accessible* aContainer);
+
+ /**
+ * Returns a union rect (in dev pixels) of all character bounds in this range.
+ * This rect is screen-relative and inclusive of mEnd. This function only
+ * works on remote accessibles, and assumes caching is enabled.
+ */
+ LayoutDeviceIntRect Bounds() const;
+
+ /**
+ * Set range as DOM selection.
+ * aSelectionNum is the selection index to use. If aSelectionNum is
+ * out of bounds for current selection ranges, or is -1, a new selection
+ * range is created.
+ */
+ MOZ_CAN_RUN_SCRIPT bool SetSelection(int32_t aSelectionNum) const;
+
+ MOZ_CAN_RUN_SCRIPT void ScrollIntoView(uint32_t aScrollType) const;
+
+ private:
+ TextLeafPoint mStart;
+ TextLeafPoint mEnd;
+
+ public:
+ /**
+ * A TextLeafRange iterator will iterate through single leaf segments of the
+ * given range.
+ */
+
+ class Iterator {
+ public:
+ Iterator(Iterator&& aOther)
+ : mRange(aOther.mRange),
+ mSegmentStart(aOther.mSegmentStart),
+ mSegmentEnd(aOther.mSegmentEnd) {}
+
+ static Iterator BeginIterator(const TextLeafRange& aRange);
+
+ static Iterator EndIterator(const TextLeafRange& aRange);
+
+ Iterator& operator++();
+
+ bool operator!=(const Iterator& aOther) const {
+ return mRange != aOther.mRange || mSegmentStart != aOther.mSegmentStart ||
+ mSegmentEnd != aOther.mSegmentEnd;
+ }
+
+ TextLeafRange operator*() {
+ return TextLeafRange(mSegmentStart, mSegmentEnd);
+ }
+
+ private:
+ explicit Iterator(const TextLeafRange& aRange) : mRange(aRange) {}
+
+ Iterator() = delete;
+ Iterator(const Iterator&) = delete;
+ Iterator& operator=(const Iterator&) = delete;
+ Iterator& operator=(const Iterator&&) = delete;
+
+ const TextLeafRange& mRange;
+ TextLeafPoint mSegmentStart;
+ TextLeafPoint mSegmentEnd;
+ };
+
+ Iterator begin() const { return Iterator::BeginIterator(*this); }
+ Iterator end() const { return Iterator::EndIterator(*this); }
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif