mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
de8073afbb
TextComposition should update its composition start offset after every DOM event dispatch with first clause's selection type if there is composition string. MozReview-Commit-ID: HFkePci1PhU --HG-- extra : rebase_source : c7af075115505b52e48d8bbd5f2dd1d9001fe36e
315 lines
8.1 KiB
C++
315 lines
8.1 KiB
C++
/* -*- 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 <stdint.h>
|
|
|
|
#include "mozilla/EventForwards.h"
|
|
|
|
#include "nsColor.h"
|
|
#include "nsISelectionController.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
|
|
******************************************************************************/
|
|
|
|
enum class TextRangeType : RawTextRangeType
|
|
{
|
|
eUninitialized = 0x00,
|
|
eCaret = 0x01,
|
|
eRawClause = nsITextInputProcessor::ATTR_RAW_CLAUSE,
|
|
eSelectedRawClause = nsITextInputProcessor::ATTR_SELECTED_RAW_CLAUSE,
|
|
eConvertedClause = nsITextInputProcessor::ATTR_CONVERTED_CLAUSE,
|
|
eSelectedClause = nsITextInputProcessor::ATTR_SELECTED_CLAUSE
|
|
};
|
|
|
|
bool IsValidRawTextRangeValue(RawTextRangeType aRawTextRangeValue);
|
|
RawTextRangeType ToRawTextRangeType(TextRangeType aTextRangeType);
|
|
TextRangeType ToTextRangeType(RawTextRangeType aRawTextRangeType);
|
|
const char* ToChar(TextRangeType aTextRangeType);
|
|
SelectionType ToSelectionType(TextRangeType aTextRangeType);
|
|
|
|
inline RawSelectionType ToRawSelectionType(TextRangeType aTextRangeType)
|
|
{
|
|
return ToRawSelectionType(ToSelectionType(aTextRangeType));
|
|
}
|
|
|
|
struct TextRange
|
|
{
|
|
TextRange()
|
|
: mStartOffset(0)
|
|
, mEndOffset(0)
|
|
, mRangeType(TextRangeType::eUninitialized)
|
|
{
|
|
}
|
|
|
|
uint32_t mStartOffset;
|
|
// XXX Storing end offset makes the initializing code very complicated.
|
|
// We should replace it with mLength.
|
|
uint32_t mEndOffset;
|
|
|
|
TextRangeStyle mRangeStyle;
|
|
|
|
TextRangeType mRangeType;
|
|
|
|
uint32_t Length() const { return mEndOffset - mStartOffset; }
|
|
|
|
bool IsClause() const
|
|
{
|
|
return mRangeType != TextRangeType::eCaret;
|
|
}
|
|
|
|
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 AutoTArray<TextRange, 10>
|
|
{
|
|
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 == TextRangeType::eSelectedRawClause ||
|
|
range.mRangeType == TextRangeType::eSelectedClause) {
|
|
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 == TextRangeType::eCaret) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HasClauses() const
|
|
{
|
|
for (const TextRange& range : *this) {
|
|
if (range.IsClause()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32_t GetCaretPosition() const
|
|
{
|
|
for (const TextRange& range : *this) {
|
|
if (range.mRangeType == TextRangeType::eCaret) {
|
|
return range.mStartOffset;
|
|
}
|
|
}
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
const TextRange* GetFirstClause() const
|
|
{
|
|
for (const TextRange& range : *this) {
|
|
// Look for the range of a clause whose start offset is 0 because the
|
|
// first clause's start offset is always 0.
|
|
if (range.IsClause() && !range.mStartOffset) {
|
|
return ⦥
|
|
}
|
|
}
|
|
MOZ_ASSERT(!HasClauses());
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_TextRage_h_
|