/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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_TextRage_h_ #define mozilla_TextRage_h_ #include #include "nsAutoPtr.h" #include "nsColor.h" #include "nsITextInputProcessor.h" #include "nsStyleConsts.h" #include "nsTArray.h" namespace mozilla { /****************************************************************************** * mozilla::TextRangeStyle ******************************************************************************/ struct TextRangeStyle { enum { LINESTYLE_NONE = NS_STYLE_TEXT_DECORATION_STYLE_NONE, LINESTYLE_SOLID = NS_STYLE_TEXT_DECORATION_STYLE_SOLID, LINESTYLE_DOTTED = NS_STYLE_TEXT_DECORATION_STYLE_DOTTED, LINESTYLE_DASHED = NS_STYLE_TEXT_DECORATION_STYLE_DASHED, LINESTYLE_DOUBLE = NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE, LINESTYLE_WAVY = NS_STYLE_TEXT_DECORATION_STYLE_WAVY }; enum { DEFINED_NONE = 0x00, DEFINED_LINESTYLE = 0x01, DEFINED_FOREGROUND_COLOR = 0x02, DEFINED_BACKGROUND_COLOR = 0x04, DEFINED_UNDERLINE_COLOR = 0x08 }; // Initialize all members, because TextRange instances may be compared by // memcomp. TextRangeStyle() { Clear(); } void Clear() { mDefinedStyles = DEFINED_NONE; mLineStyle = LINESTYLE_NONE; mIsBoldLine = false; mForegroundColor = mBackgroundColor = mUnderlineColor = NS_RGBA(0, 0, 0, 0); } bool IsDefined() const { return mDefinedStyles != DEFINED_NONE; } bool IsLineStyleDefined() const { return (mDefinedStyles & DEFINED_LINESTYLE) != 0; } bool IsForegroundColorDefined() const { return (mDefinedStyles & DEFINED_FOREGROUND_COLOR) != 0; } bool IsBackgroundColorDefined() const { return (mDefinedStyles & DEFINED_BACKGROUND_COLOR) != 0; } bool IsUnderlineColorDefined() const { return (mDefinedStyles & DEFINED_UNDERLINE_COLOR) != 0; } bool IsNoChangeStyle() const { return !IsForegroundColorDefined() && !IsBackgroundColorDefined() && IsLineStyleDefined() && mLineStyle == LINESTYLE_NONE; } bool Equals(const TextRangeStyle& aOther) const { if (mDefinedStyles != aOther.mDefinedStyles) return false; if (IsLineStyleDefined() && (mLineStyle != aOther.mLineStyle || !mIsBoldLine != !aOther.mIsBoldLine)) return false; if (IsForegroundColorDefined() && (mForegroundColor != aOther.mForegroundColor)) return false; if (IsBackgroundColorDefined() && (mBackgroundColor != aOther.mBackgroundColor)) return false; if (IsUnderlineColorDefined() && (mUnderlineColor != aOther.mUnderlineColor)) return false; return true; } bool operator !=(const TextRangeStyle &aOther) const { return !Equals(aOther); } bool operator ==(const TextRangeStyle &aOther) const { return Equals(aOther); } uint8_t mDefinedStyles; uint8_t mLineStyle; // DEFINED_LINESTYLE bool mIsBoldLine; // DEFINED_LINESTYLE nscolor mForegroundColor; // DEFINED_FOREGROUND_COLOR nscolor mBackgroundColor; // DEFINED_BACKGROUND_COLOR nscolor mUnderlineColor; // DEFINED_UNDERLINE_COLOR }; /****************************************************************************** * mozilla::TextRange ******************************************************************************/ // XXX NS_TEXTRANGE_* should be moved into TextRange as an typed enum. enum { NS_TEXTRANGE_UNDEFINED = 0x00, NS_TEXTRANGE_CARETPOSITION = 0x01, NS_TEXTRANGE_RAWINPUT = nsITextInputProcessor::ATTR_RAW_CLAUSE, NS_TEXTRANGE_SELECTEDRAWTEXT = nsITextInputProcessor::ATTR_SELECTED_RAW_CLAUSE, NS_TEXTRANGE_CONVERTEDTEXT = nsITextInputProcessor::ATTR_CONVERTED_CLAUSE, NS_TEXTRANGE_SELECTEDCONVERTEDTEXT = nsITextInputProcessor::ATTR_SELECTED_CLAUSE }; struct TextRange { TextRange() : mStartOffset(0), mEndOffset(0), mRangeType(NS_TEXTRANGE_UNDEFINED) { } uint32_t mStartOffset; // XXX Storing end offset makes the initializing code very complicated. // We should replace it with mLength. uint32_t mEndOffset; uint32_t mRangeType; TextRangeStyle mRangeStyle; uint32_t Length() const { return mEndOffset - mStartOffset; } bool IsClause() const { MOZ_ASSERT(mRangeType >= NS_TEXTRANGE_CARETPOSITION && mRangeType <= NS_TEXTRANGE_SELECTEDCONVERTEDTEXT, "Invalid range type"); return mRangeType != NS_TEXTRANGE_CARETPOSITION; } bool Equals(const TextRange& aOther) const { return mStartOffset == aOther.mStartOffset && mEndOffset == aOther.mEndOffset && mRangeType == aOther.mRangeType && mRangeStyle == aOther.mRangeStyle; } void RemoveCharacter(uint32_t aOffset) { if (mStartOffset > aOffset) { --mStartOffset; --mEndOffset; } else if (mEndOffset > aOffset) { --mEndOffset; } } }; /****************************************************************************** * mozilla::TextRangeArray ******************************************************************************/ class TextRangeArray final : public nsAutoTArray { friend class WidgetCompositionEvent; ~TextRangeArray() {} NS_INLINE_DECL_REFCOUNTING(TextRangeArray) const TextRange* GetTargetClause() const { for (uint32_t i = 0; i < Length(); ++i) { const TextRange& range = ElementAt(i); if (range.mRangeType == NS_TEXTRANGE_SELECTEDRAWTEXT || range.mRangeType == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT) { return ⦥ } } return nullptr; } // Returns target clause offset. If there are selected clauses, this returns // the first selected clause offset. Otherwise, 0. uint32_t TargetClauseOffset() const { const TextRange* range = GetTargetClause(); return range ? range->mStartOffset : 0; } // Returns target clause length. If there are selected clauses, this returns // the first selected clause length. Otherwise, UINT32_MAX. uint32_t TargetClauseLength() const { const TextRange* range = GetTargetClause(); return range ? range->Length() : UINT32_MAX; } public: bool IsComposing() const { for (uint32_t i = 0; i < Length(); ++i) { if (ElementAt(i).IsClause()) { return true; } } return false; } bool Equals(const TextRangeArray& aOther) const { size_t len = Length(); if (len != aOther.Length()) { return false; } for (size_t i = 0; i < len; i++) { if (!ElementAt(i).Equals(aOther.ElementAt(i))) { return false; } } return true; } void RemoveCharacter(uint32_t aOffset) { for (size_t i = 0, len = Length(); i < len; i++) { ElementAt(i).RemoveCharacter(aOffset); } } bool HasCaret() const { for (const TextRange& range : *this) { if (range.mRangeType == NS_TEXTRANGE_CARETPOSITION) { return true; } } return false; } uint32_t GetCaretPosition() const { for (const TextRange& range : *this) { if (range.mRangeType == NS_TEXTRANGE_CARETPOSITION) { return range.mStartOffset; } } return UINT32_MAX; } }; } // namespace mozilla #endif // mozilla_TextRage_h_