diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /editor/libeditor/TypeInState.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'editor/libeditor/TypeInState.cpp')
-rw-r--r-- | editor/libeditor/TypeInState.cpp | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/editor/libeditor/TypeInState.cpp b/editor/libeditor/TypeInState.cpp new file mode 100644 index 000000000..ce43e5e4d --- /dev/null +++ b/editor/libeditor/TypeInState.cpp @@ -0,0 +1,397 @@ +/* -*- 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/. */ + +#include "TypeInState.h" + +#include <stddef.h> + +#include "nsError.h" +#include "mozilla/EditorBase.h" +#include "mozilla/mozalloc.h" +#include "mozilla/dom/Selection.h" +#include "nsAString.h" +#include "nsDebug.h" +#include "nsGkAtoms.h" +#include "nsIDOMNode.h" +#include "nsISupportsBase.h" +#include "nsISupportsImpl.h" +#include "nsReadableUtils.h" +#include "nsStringFwd.h" + +class nsIAtom; +class nsIDOMDocument; + +namespace mozilla { + +using namespace dom; + +/******************************************************************** + * mozilla::TypeInState + *******************************************************************/ + +NS_IMPL_CYCLE_COLLECTION(TypeInState, mLastSelectionContainer) +NS_IMPL_CYCLE_COLLECTING_ADDREF(TypeInState) +NS_IMPL_CYCLE_COLLECTING_RELEASE(TypeInState) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TypeInState) + NS_INTERFACE_MAP_ENTRY(nsISelectionListener) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +TypeInState::TypeInState() + : mRelativeFontSize(0) + , mLastSelectionOffset(0) +{ + Reset(); +} + +TypeInState::~TypeInState() +{ + // Call Reset() to release any data that may be in + // mClearedArray and mSetArray. + + Reset(); +} + +nsresult +TypeInState::UpdateSelState(Selection* aSelection) +{ + NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER); + + if (!aSelection->Collapsed()) { + return NS_OK; + } + + return EditorBase::GetStartNodeAndOffset( + aSelection, getter_AddRefs(mLastSelectionContainer), + &mLastSelectionOffset); +} + + +NS_IMETHODIMP +TypeInState::NotifySelectionChanged(nsIDOMDocument* aDOMDocument, + nsISelection* aSelection, + int16_t aReason) +{ + // XXX: Selection currently generates bogus selection changed notifications + // XXX: (bug 140303). It can notify us when the selection hasn't actually + // XXX: changed, and it notifies us more than once for the same change. + // XXX: + // XXX: The following code attempts to work around the bogus notifications, + // XXX: and should probably be removed once bug 140303 is fixed. + // XXX: + // XXX: This code temporarily fixes the problem where clicking the mouse in + // XXX: the same location clears the type-in-state. + RefPtr<Selection> selection = + aSelection ? aSelection->AsSelection() : nullptr; + + if (aSelection) { + int32_t rangeCount = selection->RangeCount(); + + if (selection->Collapsed() && rangeCount) { + nsCOMPtr<nsIDOMNode> selNode; + int32_t selOffset = 0; + + nsresult rv = + EditorBase::GetStartNodeAndOffset(selection, getter_AddRefs(selNode), + &selOffset); + + NS_ENSURE_SUCCESS(rv, rv); + + if (selNode && + selNode == mLastSelectionContainer && + selOffset == mLastSelectionOffset) { + // We got a bogus selection changed notification! + return NS_OK; + } + + mLastSelectionContainer = selNode; + mLastSelectionOffset = selOffset; + } else { + mLastSelectionContainer = nullptr; + mLastSelectionOffset = 0; + } + } + + Reset(); + return NS_OK; +} + +void +TypeInState::Reset() +{ + for (size_t i = 0, n = mClearedArray.Length(); i < n; i++) { + delete mClearedArray[i]; + } + mClearedArray.Clear(); + for (size_t i = 0, n = mSetArray.Length(); i < n; i++) { + delete mSetArray[i]; + } + mSetArray.Clear(); +} + + +void +TypeInState::SetProp(nsIAtom* aProp, + const nsAString& aAttr, + const nsAString& aValue) +{ + // special case for big/small, these nest + if (nsGkAtoms::big == aProp) { + mRelativeFontSize++; + return; + } + if (nsGkAtoms::small == aProp) { + mRelativeFontSize--; + return; + } + + int32_t index; + if (IsPropSet(aProp, aAttr, nullptr, index)) { + // if it's already set, update the value + mSetArray[index]->value = aValue; + return; + } + + // Make a new propitem and add it to the list of set properties. + mSetArray.AppendElement(new PropItem(aProp, aAttr, aValue)); + + // remove it from the list of cleared properties, if we have a match + RemovePropFromClearedList(aProp, aAttr); +} + + +void +TypeInState::ClearAllProps() +{ + // null prop means "all" props + ClearProp(nullptr, EmptyString()); +} + +void +TypeInState::ClearProp(nsIAtom* aProp, + const nsAString& aAttr) +{ + // if it's already cleared we are done + if (IsPropCleared(aProp, aAttr)) { + return; + } + + // make a new propitem + PropItem* item = new PropItem(aProp, aAttr, EmptyString()); + + // remove it from the list of set properties, if we have a match + RemovePropFromSetList(aProp, aAttr); + + // add it to the list of cleared properties + mClearedArray.AppendElement(item); +} + + +/** + * TakeClearProperty() hands back next property item on the clear list. + * Caller assumes ownership of PropItem and must delete it. + */ +PropItem* +TypeInState::TakeClearProperty() +{ + size_t count = mClearedArray.Length(); + if (!count) { + return nullptr; + } + + --count; // indices are zero based + PropItem* propItem = mClearedArray[count]; + mClearedArray.RemoveElementAt(count); + return propItem; +} + +/** + * TakeSetProperty() hands back next poroperty item on the set list. + * Caller assumes ownership of PropItem and must delete it. + */ +PropItem* +TypeInState::TakeSetProperty() +{ + size_t count = mSetArray.Length(); + if (!count) { + return nullptr; + } + count--; // indices are zero based + PropItem* propItem = mSetArray[count]; + mSetArray.RemoveElementAt(count); + return propItem; +} + +/** + * TakeRelativeFontSize() hands back relative font value, which is then + * cleared out. + */ +int32_t +TypeInState::TakeRelativeFontSize() +{ + int32_t relSize = mRelativeFontSize; + mRelativeFontSize = 0; + return relSize; +} + +void +TypeInState::GetTypingState(bool& isSet, + bool& theSetting, + nsIAtom* aProp) +{ + GetTypingState(isSet, theSetting, aProp, EmptyString(), nullptr); +} + +void +TypeInState::GetTypingState(bool& isSet, + bool& theSetting, + nsIAtom* aProp, + const nsString& aAttr, + nsString* aValue) +{ + if (IsPropSet(aProp, aAttr, aValue)) { + isSet = true; + theSetting = true; + } else if (IsPropCleared(aProp, aAttr)) { + isSet = true; + theSetting = false; + } else { + isSet = false; + } +} + +void +TypeInState::RemovePropFromSetList(nsIAtom* aProp, + const nsAString& aAttr) +{ + int32_t index; + if (!aProp) { + // clear _all_ props + for (size_t i = 0, n = mSetArray.Length(); i < n; i++) { + delete mSetArray[i]; + } + mSetArray.Clear(); + mRelativeFontSize=0; + } else if (FindPropInList(aProp, aAttr, nullptr, mSetArray, index)) { + delete mSetArray[index]; + mSetArray.RemoveElementAt(index); + } +} + +void +TypeInState::RemovePropFromClearedList(nsIAtom* aProp, + const nsAString& aAttr) +{ + int32_t index; + if (FindPropInList(aProp, aAttr, nullptr, mClearedArray, index)) { + delete mClearedArray[index]; + mClearedArray.RemoveElementAt(index); + } +} + +bool +TypeInState::IsPropSet(nsIAtom* aProp, + const nsAString& aAttr, + nsAString* outValue) +{ + int32_t i; + return IsPropSet(aProp, aAttr, outValue, i); +} + +bool +TypeInState::IsPropSet(nsIAtom* aProp, + const nsAString& aAttr, + nsAString* outValue, + int32_t& outIndex) +{ + // linear search. list should be short. + size_t count = mSetArray.Length(); + for (size_t i = 0; i < count; i++) { + PropItem *item = mSetArray[i]; + if (item->tag == aProp && item->attr == aAttr) { + if (outValue) { + *outValue = item->value; + } + outIndex = i; + return true; + } + } + return false; +} + + +bool +TypeInState::IsPropCleared(nsIAtom* aProp, + const nsAString& aAttr) +{ + int32_t i; + return IsPropCleared(aProp, aAttr, i); +} + + +bool +TypeInState::IsPropCleared(nsIAtom* aProp, + const nsAString& aAttr, + int32_t& outIndex) +{ + if (FindPropInList(aProp, aAttr, nullptr, mClearedArray, outIndex)) { + return true; + } + if (FindPropInList(0, EmptyString(), nullptr, mClearedArray, outIndex)) { + // special case for all props cleared + outIndex = -1; + return true; + } + return false; +} + +bool +TypeInState::FindPropInList(nsIAtom* aProp, + const nsAString& aAttr, + nsAString* outValue, + nsTArray<PropItem*>& aList, + int32_t& outIndex) +{ + // linear search. list should be short. + size_t count = aList.Length(); + for (size_t i = 0; i < count; i++) { + PropItem *item = aList[i]; + if (item->tag == aProp && item->attr == aAttr) { + if (outValue) { + *outValue = item->value; + } + outIndex = i; + return true; + } + } + return false; +} + +/******************************************************************** + * mozilla::PropItem: helper struct for mozilla::TypeInState + *******************************************************************/ + +PropItem::PropItem() + : tag(nullptr) +{ + MOZ_COUNT_CTOR(PropItem); +} + +PropItem::PropItem(nsIAtom* aTag, + const nsAString& aAttr, + const nsAString &aValue) + : tag(aTag) + , attr(aAttr) + , value(aValue) +{ + MOZ_COUNT_CTOR(PropItem); +} + +PropItem::~PropItem() +{ + MOZ_COUNT_DTOR(PropItem); +} + +} // namespace mozilla |