Bug 1824667 - Factor middle-cropping out of nsFileControlFrame. r=jfkthame,layout-reviewers

Factor a MiddleCroppingBlockFrame that does the double reflow shenanigans.

That should both be faster and easier to reason about. The only thing we need
to be careful about is to use the current inline coord from the line layout if
present to compute the real available isize.

Differential Revision: https://phabricator.services.mozilla.com/D173668
This commit is contained in:
Emilio Cobos Álvarez 2023-03-27 17:13:50 +00:00
Родитель 82828dba9e
Коммит 894fd5d4c3
7 изменённых файлов: 330 добавлений и 220 удалений

Просмотреть файл

@ -173,6 +173,7 @@ nsIFrame* NS_NewSVGFELeafFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
ComputedStyle* aStyle);
nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
#include "mozilla/dom/NodeInfo.h"
#include "prenv.h"
@ -3459,6 +3460,15 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
PseudoStyleType::fieldsetContent ||
aParentFrame->GetParent()->IsFieldSetFrame(),
"Unexpected parent for fieldset content anon box");
if (aElement.IsInNativeAnonymousSubtree() &&
aElement.NodeInfo()->NameAtom() == nsGkAtoms::label &&
aParentFrame->IsFileControlFrame()) {
static constexpr FrameConstructionData sFileLabelData(
NS_NewFileControlLabelFrame);
return &sFileLabelData;
}
static constexpr FrameConstructionDataByTag sHTMLData[] = {
SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,

Просмотреть файл

@ -21,11 +21,12 @@
#include "mozilla/dom/HTMLButtonElement.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/intl/Segmenter.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/TextEditor.h"
#include "MiddleCroppingBlockFrame.h"
#include "nsIFrame.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
@ -58,134 +59,6 @@ void nsFileControlFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
mMouseListener = new DnDListener(this);
}
bool nsFileControlFrame::CropTextToWidth(gfxContext& aRenderingContext,
const nsIFrame* aFrame, nscoord aWidth,
nsString& aText) {
if (aText.IsEmpty()) {
return false;
}
RefPtr<nsFontMetrics> fm =
nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
// see if the text will completely fit in the width given
if (const nscoord textWidth = nsLayoutUtils::AppUnitWidthOfStringBidi(
aText, aFrame, *fm, aRenderingContext);
textWidth <= aWidth) {
return false;
}
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
// see if the width is even smaller than the ellipsis
fm->SetTextRunRTL(false);
const nscoord ellipsisWidth =
nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm, drawTarget);
if (ellipsisWidth >= aWidth) {
aText = kEllipsis;
return true;
}
// determine how much of the string will fit in the max width
nscoord totalWidth = ellipsisWidth;
const Span text(aText);
intl::GraphemeClusterBreakIteratorUtf16 leftIter(text);
intl::GraphemeClusterBreakReverseIteratorUtf16 rightIter(text);
uint32_t leftPos = 0;
uint32_t rightPos = aText.Length();
nsAutoString leftString, rightString;
while (leftPos < rightPos) {
Maybe<uint32_t> pos = leftIter.Next();
Span chars = text.FromTo(leftPos, *pos);
nscoord charWidth =
nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget);
if (totalWidth + charWidth > aWidth) {
break;
}
leftString.Append(chars);
leftPos = *pos;
totalWidth += charWidth;
if (leftPos >= rightPos) {
break;
}
pos = rightIter.Next();
chars = text.FromTo(*pos, rightPos);
charWidth = nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget);
if (totalWidth + charWidth > aWidth) {
break;
}
rightString.Insert(chars, 0);
rightPos = *pos;
totalWidth += charWidth;
}
aText = leftString + kEllipsis + rightString;
return true;
}
void nsFileControlFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aMetrics,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
// Restore the uncropped filename.
nsAutoString filename;
HTMLInputElement::FromNode(mContent)->GetDisplayFileName(filename);
bool done = false;
while (true) {
UpdateDisplayedValue(filename, false); // update the text node
AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
LinesBegin()->MarkDirty();
nsBlockFrame::Reflow(aPresContext, aMetrics, aReflowInput, aStatus);
if (done) {
break;
}
nscoord lineISize = LinesBegin()->ISize();
const auto cbWM = aMetrics.GetWritingMode();
const auto wm = GetWritingMode();
nscoord iSize =
wm.IsOrthogonalTo(cbWM) ? aMetrics.BSize(cbWM) : aMetrics.ISize(cbWM);
auto bp = GetLogicalUsedBorderAndPadding(wm);
nscoord contentISize = iSize - bp.IStartEnd(wm);
if (lineISize > contentISize) {
// The filename overflows - crop it and reflow again (once).
// NOTE: the label frame might have bidi-continuations
auto* labelFrame = mTextContent->GetPrimaryFrame();
nscoord labelBP =
labelFrame->GetLogicalUsedBorderAndPadding(wm).IStartEnd(wm);
auto* lastLabelCont = labelFrame->LastContinuation();
if (lastLabelCont != labelFrame) {
labelBP +=
lastLabelCont->GetLogicalUsedBorderAndPadding(wm).IStartEnd(wm);
}
nscoord availableISizeForLabel = contentISize;
if (auto* buttonFrame = mBrowseFilesOrDirs->GetPrimaryFrame()) {
availableISizeForLabel -=
buttonFrame->ISize(wm) +
buttonFrame->GetLogicalUsedMargin(wm).IStartEnd(wm);
}
if (CropTextToWidth(*aReflowInput.mRenderingContext, labelFrame,
availableISizeForLabel - labelBP, filename)) {
nsBlockFrame::DidReflow(aPresContext, &aReflowInput);
aStatus.Reset();
labelFrame->MarkSubtreeDirty();
labelFrame->AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
mCachedMinISize = NS_INTRINSIC_ISIZE_UNKNOWN;
mCachedPrefISize = NS_INTRINSIC_ISIZE_UNKNOWN;
done = true;
continue;
}
}
break;
}
}
void nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) {
NS_ENSURE_TRUE_VOID(mContent);
@ -256,11 +129,6 @@ nsresult nsFileControlFrame::CreateAnonymousContent(
new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
mTextContent->AppendChildTo(text, false, IgnoreErrors());
// Update the displayed text to reflect the current element's value.
nsAutoString value;
fileContent->GetDisplayFileName(value);
UpdateDisplayedValue(value, false);
aElements.AppendElement(mTextContent);
// We should be able to interact with the element by doing drag and drop.
@ -489,30 +357,6 @@ bool nsFileControlFrame::DnDListener::CanDropTheseFiles(
return listLength <= 1 || aSupportsMultiple;
}
nscoord nsFileControlFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_MIN_INLINE_SIZE(this, result);
// Our min inline size is our pref inline size
result = GetPrefISize(aRenderingContext);
return result;
}
nscoord nsFileControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_PREF_INLINE_SIZE(this, result);
// Make sure we measure with the uncropped filename.
if (mCachedPrefISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
nsAutoString filename;
HTMLInputElement::FromNode(mContent)->GetDisplayFileName(filename);
UpdateDisplayedValue(filename, false);
}
result = nsBlockFrame::GetPrefISize(aRenderingContext);
return result;
}
void nsFileControlFrame::SyncDisabledState() {
if (mContent->AsElement()->State().HasState(ElementState::DISABLED)) {
mBrowseFilesOrDirs->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, u""_ns,
@ -534,29 +378,13 @@ nsresult nsFileControlFrame::GetFrameName(nsAString& aResult) const {
}
#endif
void nsFileControlFrame::UpdateDisplayedValue(const nsAString& aValue,
bool aNotify) {
auto* text = Text::FromNode(mTextContent->GetFirstChild());
uint32_t oldLength = aNotify ? 0 : text->TextLength();
text->SetText(aValue, aNotify);
if (!aNotify) {
// We can't notify during Reflow so we need to tell the text frame
// about the text content change we just did.
if (auto* textFrame = static_cast<nsTextFrame*>(text->GetPrimaryFrame())) {
textFrame->NotifyNativeAnonymousTextnodeChange(oldLength);
}
nsBlockFrame* label = do_QueryFrame(mTextContent->GetPrimaryFrame());
if (label && label->LinesBegin() != label->LinesEnd()) {
label->AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
label->LinesBegin()->MarkDirty();
}
}
}
nsresult nsFileControlFrame::SetFormProperty(nsAtom* aName,
const nsAString& aValue) {
if (nsGkAtoms::value == aName) {
UpdateDisplayedValue(aValue, true);
if (MiddleCroppingBlockFrame* f =
do_QueryFrame(mTextContent->GetPrimaryFrame())) {
f->UpdateDisplayedValueToUncroppedValue(true);
}
}
return NS_OK;
}
@ -572,7 +400,32 @@ a11y::AccType nsFileControlFrame::AccessibleType() {
}
#endif
////////////////////////////////////////////////////////////
// Mouse listener implementation
NS_IMPL_ISUPPORTS(nsFileControlFrame::MouseListener, nsIDOMEventListener)
class FileControlLabelFrame final : public MiddleCroppingBlockFrame {
public:
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(FileControlLabelFrame)
FileControlLabelFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
: MiddleCroppingBlockFrame(aStyle, aPresContext, kClassID) {}
HTMLInputElement& FileInput() const {
return *HTMLInputElement::FromNode(mContent->GetParent());
}
void GetUncroppedValue(nsAString& aValue) override {
return FileInput().GetDisplayFileName(aValue);
}
};
NS_QUERYFRAME_HEAD(FileControlLabelFrame)
NS_QUERYFRAME_ENTRY(FileControlLabelFrame)
NS_QUERYFRAME_TAIL_INHERITING(MiddleCroppingBlockFrame)
NS_IMPL_FRAMEARENA_HELPERS(FileControlLabelFrame)
nsIFrame* NS_NewFileControlLabelFrame(PresShell* aPresShell,
ComputedStyle* aStyle) {
return new (aPresShell)
FileControlLabelFrame(aStyle, aPresShell->GetPresContext());
}

Просмотреть файл

@ -14,13 +14,11 @@
#include "nsIAnonymousContentCreator.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
namespace mozilla::dom {
class FileList;
class BlobImpl;
class DataTransfer;
} // namespace dom
} // namespace mozilla
} // namespace mozilla::dom
class nsFileControlFrame final : public nsBlockFrame,
public nsIFormControlFrame,
@ -34,38 +32,29 @@ class nsFileControlFrame final : public nsBlockFrame,
explicit nsFileControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext);
virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
void Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) override;
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
// nsIFormControlFrame
virtual nsresult SetFormProperty(nsAtom* aName,
const nsAString& aValue) override;
virtual void SetFocus(bool aOn, bool aRepaint) override;
nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) override;
void SetFocus(bool aOn, bool aRepaint) override;
nscoord GetMinISize(gfxContext* aRenderingContext) override;
nscoord GetPrefISize(gfxContext* aRenderingContext) override;
virtual void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override;
nsresult GetFrameName(nsAString& aResult) const override;
#endif
void ElementStateChanged(mozilla::dom::ElementState aStates) override;
// nsIAnonymousContentCreator
virtual nsresult CreateAnonymousContent(
nsTArray<ContentInfo>& aElements) override;
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
#ifdef ACCESSIBILITY
virtual mozilla::a11y::AccType AccessibleType() override;
@ -150,23 +139,10 @@ class nsFileControlFrame final : public nsBlockFrame,
RefPtr<DnDListener> mMouseListener;
protected:
/**
* Crop aText to fit inside aWidth using the styles of aFrame.
* @return true if aText was modified
*/
static bool CropTextToWidth(gfxContext& aRenderingContext,
const nsIFrame* aFrame, nscoord aWidth,
nsString& aText);
/**
* Sync the disabled state of the content with anonymous children.
*/
void SyncDisabledState();
/**
* Updates the displayed value by using aValue.
*/
void UpdateDisplayedValue(const nsAString& aValue, bool aNotify);
};
#endif // nsFileControlFrame_h___

Просмотреть файл

@ -23,7 +23,8 @@ FRAME_CLASSES = [
Frame("nsContinuingTextFrame", "Text", LEAF),
Frame("nsDateTimeControlFrame", "DateTimeControl", NOT_LEAF),
Frame("nsFieldSetFrame", "FieldSet", NOT_LEAF),
Frame("nsFileControlFrame", "Block", LEAF),
Frame("nsFileControlFrame", "FileControl", LEAF),
Frame("FileControlLabelFrame", "Block", NOT_LEAF),
Frame("nsFirstLetterFrame", "Letter", NOT_LEAF),
Frame("nsFirstLineFrame", "Line", NOT_LEAF),
Frame("nsFlexContainerFrame", "FlexContainer", NOT_LEAF),
@ -130,6 +131,7 @@ FRAME_CLASSES = [
Frame("ViewportFrame", "Viewport", NOT_LEAF),
Frame("WBRFrame", "Wbr", LEAF),
# Non-concrete classes (for FrameIID use)
AbstractFrame("MiddleCroppingBlockFrame"),
AbstractFrame("nsContainerFrame"),
AbstractFrame("nsLeafFrame"),
AbstractFrame("nsMathMLContainerFrame"),

Просмотреть файл

@ -0,0 +1,205 @@
/* -*- 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 "MiddleCroppingBlockFrame.h"
#include "nsTextFrame.h"
#include "nsLayoutUtils.h"
#include "nsTextNode.h"
#include "nsLineLayout.h"
#include "mozilla/dom/Document.h"
#include "mozilla/intl/Segmenter.h"
#include "mozilla/ReflowInput.h"
#include "mozilla/ReflowOutput.h"
namespace mozilla {
NS_QUERYFRAME_HEAD(MiddleCroppingBlockFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
NS_QUERYFRAME_ENTRY(MiddleCroppingBlockFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
MiddleCroppingBlockFrame::MiddleCroppingBlockFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext,
ClassID aClassID)
: nsBlockFrame(aStyle, aPresContext, aClassID) {}
MiddleCroppingBlockFrame::~MiddleCroppingBlockFrame() = default;
void MiddleCroppingBlockFrame::UpdateDisplayedValue(const nsAString& aValue,
bool aNotify) {
auto* text = mTextNode.get();
uint32_t oldLength = aNotify ? 0 : text->TextLength();
text->SetText(aValue, aNotify);
if (!aNotify) {
// We can't notify during Reflow so we need to tell the text frame about the
// text content change we just did.
if (auto* textFrame = static_cast<nsTextFrame*>(text->GetPrimaryFrame())) {
textFrame->NotifyNativeAnonymousTextnodeChange(oldLength);
}
if (LinesBegin() != LinesEnd()) {
AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
LinesBegin()->MarkDirty();
}
}
}
void MiddleCroppingBlockFrame::UpdateDisplayedValueToUncroppedValue(
bool aNotify) {
nsAutoString value;
GetUncroppedValue(value);
UpdateDisplayedValue(value, aNotify);
}
nscoord MiddleCroppingBlockFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_MIN_INLINE_SIZE(this, result);
// Our min inline size is our pref inline size
result = GetPrefISize(aRenderingContext);
return result;
}
nscoord MiddleCroppingBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_PREF_INLINE_SIZE(this, result);
// Make sure we measure with the uncropped value.
if (mCachedPrefISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
UpdateDisplayedValueToUncroppedValue(false);
}
result = nsBlockFrame::GetPrefISize(aRenderingContext);
return result;
}
bool MiddleCroppingBlockFrame::CropTextToWidth(gfxContext& aRenderingContext,
nscoord aWidth,
nsString& aText) const {
if (aText.IsEmpty()) {
return false;
}
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
// see if the text will completely fit in the width given
if (nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this, *fm,
aRenderingContext) <= aWidth) {
return false;
}
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
// see if the width is even smaller than the ellipsis
fm->SetTextRunRTL(false);
const nscoord ellipsisWidth =
nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm, drawTarget);
if (ellipsisWidth >= aWidth) {
aText = kEllipsis;
return true;
}
// determine how much of the string will fit in the max width
nscoord totalWidth = ellipsisWidth;
const Span text(aText);
intl::GraphemeClusterBreakIteratorUtf16 leftIter(text);
intl::GraphemeClusterBreakReverseIteratorUtf16 rightIter(text);
uint32_t leftPos = 0;
uint32_t rightPos = aText.Length();
nsAutoString leftString, rightString;
while (leftPos < rightPos) {
Maybe<uint32_t> pos = leftIter.Next();
Span chars = text.FromTo(leftPos, *pos);
nscoord charWidth =
nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget);
if (totalWidth + charWidth > aWidth) {
break;
}
leftString.Append(chars);
leftPos = *pos;
totalWidth += charWidth;
if (leftPos >= rightPos) {
break;
}
pos = rightIter.Next();
chars = text.FromTo(*pos, rightPos);
charWidth = nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget);
if (totalWidth + charWidth > aWidth) {
break;
}
rightString.Insert(chars, 0);
rightPos = *pos;
totalWidth += charWidth;
}
aText = leftString + kEllipsis + rightString;
return true;
}
void MiddleCroppingBlockFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
// Restore the uncropped value.
nsAutoString value;
GetUncroppedValue(value);
bool done = false;
while (true) {
UpdateDisplayedValue(value, false); // update the text node
AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
LinesBegin()->MarkDirty();
nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
if (done) {
break;
}
nscoord currentICoord = aReflowInput.mLineLayout
? aReflowInput.mLineLayout->GetCurrentICoord()
: 0;
nscoord availSize = aReflowInput.AvailableISize() - currentICoord;
if (LinesBegin()->ISize() > availSize) {
// The value overflows - crop it and reflow again (once).
if (CropTextToWidth(*aReflowInput.mRenderingContext, availSize, value)) {
nsBlockFrame::DidReflow(aPresContext, &aReflowInput);
aStatus.Reset();
MarkSubtreeDirty();
AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
mCachedMinISize = NS_INTRINSIC_ISIZE_UNKNOWN;
mCachedPrefISize = NS_INTRINSIC_ISIZE_UNKNOWN;
done = true;
continue;
}
}
break;
}
}
nsresult MiddleCroppingBlockFrame::CreateAnonymousContent(
nsTArray<ContentInfo>& aContent) {
auto* doc = PresContext()->Document();
mTextNode = new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
// Update the displayed text to reflect the current element's value.
UpdateDisplayedValueToUncroppedValue(false);
aContent.AppendElement(mTextNode);
return NS_OK;
}
void MiddleCroppingBlockFrame::AppendAnonymousContentTo(
nsTArray<nsIContent*>& aContent, uint32_t aFilter) {
aContent.AppendElement(mTextNode);
}
void MiddleCroppingBlockFrame::DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) {
aPostDestroyData.AddAnonymousContent(mTextNode.forget());
nsBlockFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- 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 mozilla_MiddleCroppingBlockFrame_h
#define mozilla_MiddleCroppingBlockFrame_h
#include "nsBlockFrame.h"
#include "nsIAnonymousContentCreator.h"
#include "nsQueryFrame.h"
namespace mozilla {
// A block frame that implements a simplistic version of middle-cropping. Note
// that this is not fully l10n aware or complex-writing-system-friendly, so it's
// generally mostly useful for filenames / urls / etc.
class MiddleCroppingBlockFrame : public nsBlockFrame,
public nsIAnonymousContentCreator {
public:
virtual void GetUncroppedValue(nsAString&) = 0;
void UpdateDisplayedValueToUncroppedValue(bool aNotify);
NS_DECL_QUERYFRAME_TARGET(MiddleCroppingBlockFrame)
NS_DECL_QUERYFRAME
NS_DECL_ABSTRACT_FRAME(MiddleCroppingBlockFrame)
protected:
MiddleCroppingBlockFrame(ComputedStyle*, nsPresContext*, ClassID);
~MiddleCroppingBlockFrame();
void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&,
nsReflowStatus&) override;
nscoord GetMinISize(gfxContext*) override;
nscoord GetPrefISize(gfxContext*) override;
/**
* Crop aText to fit inside aWidth using the styles of aFrame.
* @return true if aText was modified
*/
bool CropTextToWidth(gfxContext& aRenderingContext, nscoord aWidth,
nsString& aText) const;
nsresult CreateAnonymousContent(nsTArray<ContentInfo>&) override;
void AppendAnonymousContentTo(nsTArray<nsIContent*>&,
uint32_t aFilter) override;
/**
* Updates the displayed value by using aValue.
*/
void UpdateDisplayedValue(const nsAString& aValue, bool aNotify);
void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
RefPtr<dom::Text> mTextNode;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -165,6 +165,7 @@ UNIFIED_SOURCES += [
"CSSAlignUtils.cpp",
"CSSOrderAwareFrameIterator.cpp",
"MathMLTextRunFactory.cpp",
"MiddleCroppingBlockFrame.cpp",
"nsAbsoluteContainingBlock.cpp",
"nsBackdropFrame.cpp",
"nsBlockFrame.cpp",