1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/DebugOnly.h"
9 #include "nsFontMetrics.h"
10 #include "nsTextControlFrame.h"
11 #include "nsIPlaintextEditor.h"
13 #include "nsGenericHTMLElement.h"
14 #include "nsIEditor.h"
15 #include "nsIEditorIMESupport.h"
16 #include "nsIPhonetic.h"
17 #include "nsTextFragment.h"
18 #include "nsIDOMHTMLTextAreaElement.h"
19 #include "nsNameSpaceManager.h"
20 #include "nsFormControlFrame.h" //for registering accesskeys
22 #include "nsIContent.h"
23 #include "nsPresContext.h"
24 #include "nsRenderingContext.h"
25 #include "nsGkAtoms.h"
26 #include "nsLayoutUtils.h"
27 #include "nsIDOMElement.h"
28 #include "nsIDOMHTMLElement.h"
29 #include "nsIPresShell.h"
32 #include "nsIDOMNodeList.h" //for selection setting helper func
33 #include "nsIDOMRange.h" //for selection setting helper func
34 #include "nsPIDOMWindow.h" //needed for notify selection changed to update the menus ect.
35 #include "nsIDOMNode.h"
37 #include "nsIDOMText.h" //for multiline getselection
38 #include "nsFocusManager.h"
39 #include "nsTextEditRules.h"
40 #include "nsPresState.h"
41 #include "nsContentList.h"
42 #include "nsAttrValueInlines.h"
43 #include "mozilla/dom/Selection.h"
44 #include "nsContentUtils.h"
45 #include "nsTextNode.h"
46 #include "nsStyleSet.h"
47 #include "mozilla/dom/ScriptSettings.h"
48 #include "mozilla/MathAlgorithms.h"
50 #define DEFAULT_COLUMN_WIDTH 20
52 using namespace mozilla
;
55 NS_NewTextControlFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
57 return new (aPresShell
) nsTextControlFrame(aContext
);
60 NS_IMPL_FRAMEARENA_HELPERS(nsTextControlFrame
)
62 NS_QUERYFRAME_HEAD(nsTextControlFrame
)
63 NS_QUERYFRAME_ENTRY(nsIFormControlFrame
)
64 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator
)
65 NS_QUERYFRAME_ENTRY(nsITextControlFrame
)
66 NS_QUERYFRAME_ENTRY(nsIStatefulFrame
)
67 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
71 nsTextControlFrame::AccessibleType()
73 return a11y::eHTMLTextFieldType
;
78 class EditorInitializerEntryTracker
{
80 explicit EditorInitializerEntryTracker(nsTextControlFrame
&frame
)
84 if (!mFrame
.mInEditorInitialization
) {
85 mFrame
.mInEditorInitialization
= true;
89 ~EditorInitializerEntryTracker()
92 mFrame
.mInEditorInitialization
= false;
95 bool EnteredMoreThanOnce() const { return !mFirstEntry
; }
97 nsTextControlFrame
&mFrame
;
102 nsTextControlFrame::nsTextControlFrame(nsStyleContext
* aContext
)
103 : nsContainerFrame(aContext
)
104 , mEditorHasBeenInitialized(false)
105 , mIsProcessing(false)
107 , mInEditorInitialization(false)
112 nsTextControlFrame::~nsTextControlFrame()
117 nsTextControlFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
119 mScrollEvent
.Revoke();
121 EditorInitializer
* initializer
= (EditorInitializer
*) Properties().Get(TextControlInitializer());
123 initializer
->Revoke();
124 Properties().Delete(TextControlInitializer());
127 // Unbind the text editor state object from the frame. The editor will live
128 // on, but things like controllers will be released.
129 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
130 NS_ASSERTION(txtCtrl
, "Content not a text control element");
131 txtCtrl
->UnbindFromFrame(this);
133 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame
*>(this), false);
135 nsContainerFrame::DestroyFrom(aDestructRoot
);
139 nsTextControlFrame::GetType() const
141 return nsGkAtoms::textInputFrame
;
145 nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext
* aRenderingContext
,
147 LogicalSize
& aIntrinsicSize
,
148 float aFontSizeInflation
)
150 // Get leading and the Average/MaxAdvance char width
151 nscoord lineHeight
= 0;
152 nscoord charWidth
= 0;
153 nscoord charMaxAdvance
= 0;
155 nsRefPtr
<nsFontMetrics
> fontMet
;
157 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet
),
159 NS_ENSURE_SUCCESS(rv
, rv
);
162 nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
163 NS_AUTOHEIGHT
, aFontSizeInflation
);
164 charWidth
= fontMet
->AveCharWidth();
165 charMaxAdvance
= fontMet
->MaxAdvance();
167 // Set the width equal to the width in characters
168 int32_t cols
= GetCols();
169 aIntrinsicSize
.ISize(aWM
) = cols
* charWidth
;
171 // To better match IE, take the maximum character width(in twips) and remove
172 // 4 pixels add this on as additional padding(internalPadding). But only do
173 // this if we think we have a fixed-width font.
174 if (mozilla::Abs(charWidth
- charMaxAdvance
) > (unsigned)nsPresContext::CSSPixelsToAppUnits(1)) {
175 nscoord internalPadding
=
176 std::max(0, charMaxAdvance
- nsPresContext::CSSPixelsToAppUnits(4));
177 nscoord t
= nsPresContext::CSSPixelsToAppUnits(1);
178 // Round to a multiple of t
179 nscoord rest
= internalPadding
% t
;
180 if (rest
< t
- rest
) {
181 internalPadding
-= rest
;
183 internalPadding
+= t
- rest
;
185 // Now add the extra padding on (so that small input sizes work well)
186 aIntrinsicSize
.ISize(aWM
) += internalPadding
;
188 // This is to account for the anonymous <br> having a 1 twip width
189 // in Full Standards mode, see BRFrame::Reflow and bug 228752.
190 if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards
) {
191 aIntrinsicSize
.ISize(aWM
) += 1;
195 // Increment width with cols * letter-spacing.
197 const nsStyleCoord
& lsCoord
= StyleText()->mLetterSpacing
;
198 if (eStyleUnit_Coord
== lsCoord
.GetUnit()) {
199 nscoord letterSpacing
= lsCoord
.GetCoordValue();
200 if (letterSpacing
!= 0) {
201 aIntrinsicSize
.ISize(aWM
) += cols
* letterSpacing
;
206 // Set the height equal to total number of rows (times the height of each
208 aIntrinsicSize
.BSize(aWM
) = lineHeight
* GetRows();
210 // Add in the size of the scrollbars for textarea
212 nsIFrame
* first
= GetFirstPrincipalChild();
214 nsIScrollableFrame
*scrollableFrame
= do_QueryFrame(first
);
215 NS_ASSERTION(scrollableFrame
, "Child must be scrollable");
217 if (scrollableFrame
) {
218 nsMargin scrollbarSizes
=
219 scrollableFrame
->GetDesiredScrollbarSizes(PresContext(), aRenderingContext
);
221 aIntrinsicSize
.Width(aWM
) += scrollbarSizes
.LeftRight();
222 aIntrinsicSize
.Height(aWM
) += scrollbarSizes
.TopBottom();
230 nsTextControlFrame::EnsureEditorInitialized()
232 // This method initializes our editor, if needed.
234 // This code used to be called from CreateAnonymousContent(), but
235 // when the editor set the initial string, it would trigger a
236 // PresShell listener which called FlushPendingNotifications()
237 // during frame construction. This was causing other form controls
238 // to display wrong values. Additionally, calling this every time
239 // a text frame control is instantiated means that we're effectively
240 // instantiating the editor for all text fields, even if they
241 // never get used. So, now this method is being called lazily only
242 // when we actually need an editor.
244 if (mEditorHasBeenInitialized
)
247 nsIDocument
* doc
= mContent
->GetComposedDoc();
248 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
250 nsWeakFrame
weakFrame(this);
252 // Flush out content on our document. Have to do this, because script
253 // blockers don't prevent the sink flushing out content and notifying in the
254 // process, which can destroy frames.
255 doc
->FlushPendingNotifications(Flush_ContentAndNotify
);
256 NS_ENSURE_TRUE(weakFrame
.IsAlive(), NS_ERROR_FAILURE
);
258 // Make sure that editor init doesn't do things that would kill us off
259 // (especially off the script blockers it'll create for its DOM mutations).
261 nsAutoScriptBlocker scriptBlocker
;
263 // Time to mess with our security context... See comments in GetValue()
264 // for why this is needed.
265 mozilla::dom::AutoNoJSAPI nojsapi
;
267 // Make sure that we try to focus the content even if the method fails
268 class EnsureSetFocus
{
270 explicit EnsureSetFocus(nsTextControlFrame
* aFrame
)
273 if (nsContentUtils::IsFocusedContent(mFrame
->GetContent()))
274 mFrame
->SetFocus(true, false);
277 nsTextControlFrame
*mFrame
;
279 EnsureSetFocus
makeSureSetFocusHappens(this);
282 // Make sure we are not being called again until we're finished.
283 // If reentrancy happens, just pretend that we don't have an editor.
284 const EditorInitializerEntryTracker
tracker(*this);
285 NS_ASSERTION(!tracker
.EnteredMoreThanOnce(),
286 "EnsureEditorInitialized has been called while a previous call was in progress");
289 // Create an editor for the frame, if one doesn't already exist
290 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
291 NS_ASSERTION(txtCtrl
, "Content not a text control element");
292 nsresult rv
= txtCtrl
->CreateEditor();
293 NS_ENSURE_SUCCESS(rv
, rv
);
294 NS_ENSURE_STATE(weakFrame
.IsAlive());
296 // Set mEditorHasBeenInitialized so that subsequent calls will use the
298 mEditorHasBeenInitialized
= true;
300 // Set the selection to the beginning of the text field.
301 if (weakFrame
.IsAlive()) {
302 SetSelectionEndPoints(0, 0);
305 NS_ENSURE_STATE(weakFrame
.IsAlive());
310 nsTextControlFrame::CreateAnonymousContent(nsTArray
<ContentInfo
>& aElements
)
312 NS_ASSERTION(mContent
, "We should have a content!");
314 mState
|= NS_FRAME_INDEPENDENT_SELECTION
;
316 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
317 NS_ASSERTION(txtCtrl
, "Content not a text control element");
319 // Bind the frame to its text control
320 nsresult rv
= txtCtrl
->BindToFrame(this);
321 NS_ENSURE_SUCCESS(rv
, rv
);
323 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
324 NS_ENSURE_TRUE(rootNode
, NS_ERROR_OUT_OF_MEMORY
);
326 if (!aElements
.AppendElement(rootNode
))
327 return NS_ERROR_OUT_OF_MEMORY
;
329 // Do we need a placeholder node?
330 nsAutoString placeholderTxt
;
331 mContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::placeholder
,
333 nsContentUtils::RemoveNewlines(placeholderTxt
);
334 mUsePlaceholder
= !placeholderTxt
.IsEmpty();
336 // Create the placeholder anonymous content if needed.
337 if (mUsePlaceholder
) {
338 nsIContent
* placeholderNode
= txtCtrl
->CreatePlaceholderNode();
339 NS_ENSURE_TRUE(placeholderNode
, NS_ERROR_OUT_OF_MEMORY
);
341 // Associate ::-moz-placeholder pseudo-element with the placeholder node.
342 nsCSSPseudoElements::Type pseudoType
=
343 nsCSSPseudoElements::ePseudo_mozPlaceholder
;
345 nsRefPtr
<nsStyleContext
> placeholderStyleContext
=
346 PresContext()->StyleSet()->ResolvePseudoElementStyle(
347 mContent
->AsElement(), pseudoType
, StyleContext(),
348 placeholderNode
->AsElement());
350 if (!aElements
.AppendElement(ContentInfo(placeholderNode
,
351 placeholderStyleContext
))) {
352 return NS_ERROR_OUT_OF_MEMORY
;
355 if (!IsSingleLineTextControl()) {
356 // For textareas, UpdateValueDisplay doesn't initialize the visibility
357 // status of the placeholder because it returns early, so we have to
358 // do that manually here.
359 txtCtrl
->UpdatePlaceholderVisibility(true);
363 rv
= UpdateValueDisplay(false);
364 NS_ENSURE_SUCCESS(rv
, rv
);
366 // textareas are eagerly initialized
367 bool initEagerly
= !IsSingleLineTextControl();
369 // Also, input elements which have a cached selection should get eager
370 // editor initialization.
371 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
372 NS_ASSERTION(txtCtrl
, "Content not a text control element");
373 initEagerly
= txtCtrl
->HasCachedSelection();
376 nsCOMPtr
<nsIDOMHTMLElement
> element
= do_QueryInterface(txtCtrl
);
378 // so are input text controls with spellcheck=true
379 element
->GetSpellcheck(&initEagerly
);
384 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
385 "Someone forgot a script blocker?");
386 EditorInitializer
* initializer
= (EditorInitializer
*) Properties().Get(TextControlInitializer());
388 initializer
->Revoke();
390 initializer
= new EditorInitializer(this);
391 Properties().Set(TextControlInitializer(),initializer
);
392 if (!nsContentUtils::AddScriptRunner(initializer
)) {
393 initializer
->Revoke(); // paranoia
394 Properties().Delete(TextControlInitializer());
396 return NS_ERROR_OUT_OF_MEMORY
;
404 nsTextControlFrame::AppendAnonymousContentTo(nsTArray
<nsIContent
*>& aElements
,
407 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
408 NS_ASSERTION(txtCtrl
, "Content not a text control element");
410 nsIContent
* root
= txtCtrl
->GetRootEditorNode();
412 aElements
.AppendElement(root
);
415 nsIContent
* placeholder
= txtCtrl
->GetPlaceholderNode();
416 if (placeholder
&& !(aFilter
& nsIContent::eSkipPlaceholderContent
))
417 aElements
.AppendElement(placeholder
);
422 nsTextControlFrame::GetPrefISize(nsRenderingContext
* aRenderingContext
)
424 DebugOnly
<nscoord
> result
= 0;
425 DISPLAY_PREF_WIDTH(this, result
);
427 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
428 WritingMode wm
= GetWritingMode();
429 LogicalSize
autoSize(wm
);
430 CalcIntrinsicSize(aRenderingContext
, wm
, autoSize
, inflation
);
432 return autoSize
.ISize(wm
);
436 nsTextControlFrame::GetMinISize(nsRenderingContext
* aRenderingContext
)
438 // Our min width is just our preferred width if we have auto width.
440 DISPLAY_MIN_WIDTH(this, result
);
442 result
= GetPrefISize(aRenderingContext
);
448 nsTextControlFrame::ComputeAutoSize(nsRenderingContext
*aRenderingContext
,
450 const LogicalSize
& aCBSize
,
451 nscoord aAvailableISize
,
452 const LogicalSize
& aMargin
,
453 const LogicalSize
& aBorder
,
454 const LogicalSize
& aPadding
,
457 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
458 LogicalSize
autoSize(aWM
);
459 nsresult rv
= CalcIntrinsicSize(aRenderingContext
, aWM
, autoSize
, inflation
);
462 autoSize
.SizeTo(aWM
, 0, 0);
465 // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width
467 const nsStyleCoord
& inlineStyleCoord
=
468 aWM
.IsVertical() ? StylePosition()->mHeight
: StylePosition()->mWidth
;
469 if (inlineStyleCoord
.GetUnit() == eStyleUnit_Auto
) {
470 LogicalSize ancestorAutoSize
=
471 nsContainerFrame::ComputeAutoSize(aRenderingContext
, aWM
,
472 aCBSize
, aAvailableISize
,
474 aPadding
, aShrinkWrap
);
475 // Disabled when there's inflation; see comment in GetPrefSize.
476 MOZ_ASSERT(inflation
!= 1.0f
||
477 ancestorAutoSize
.ISize(aWM
) == autoSize
.ISize(aWM
),
478 "Incorrect size computed by ComputeAutoSize?");
487 nsTextControlFrame::Reflow(nsPresContext
* aPresContext
,
488 nsHTMLReflowMetrics
& aDesiredSize
,
489 const nsHTMLReflowState
& aReflowState
,
490 nsReflowStatus
& aStatus
)
492 DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
493 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
495 // make sure that the form registers itself on the initial/first reflow
496 if (mState
& NS_FRAME_FIRST_REFLOW
) {
497 nsFormControlFrame::RegUnRegAccessKey(this, true);
500 // set values of reflow's out parameters
501 WritingMode wm
= aReflowState
.GetWritingMode();
504 aReflowState
.ComputedISize() +
505 aReflowState
.ComputedLogicalBorderPadding().IStartEnd(wm
),
506 aReflowState
.ComputedBSize() +
507 aReflowState
.ComputedLogicalBorderPadding().BStartEnd(wm
));
508 aDesiredSize
.SetSize(wm
, finalSize
);
510 // computation of the ascent wrt the input height
511 nscoord lineHeight
= aReflowState
.ComputedBSize();
512 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
513 if (!IsSingleLineTextControl()) {
514 lineHeight
= nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
515 NS_AUTOHEIGHT
, inflation
);
517 nsRefPtr
<nsFontMetrics
> fontMet
;
518 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet
),
520 // now adjust for our borders and padding
521 aDesiredSize
.SetBlockStartAscent(
522 nsLayoutUtils::GetCenteredFontBaseline(fontMet
, lineHeight
,
523 wm
.IsLineInverted()) +
524 aReflowState
.ComputedLogicalBorderPadding().BStart(wm
));
527 aDesiredSize
.SetOverflowAreasToDesiredBounds();
528 // perform reflow on all kids
529 nsIFrame
* kid
= mFrames
.FirstChild();
531 ReflowTextControlChild(kid
, aPresContext
, aReflowState
, aStatus
, aDesiredSize
);
532 kid
= kid
->GetNextSibling();
535 // take into account css properties that affect overflow handling
536 FinishAndStoreOverflow(&aDesiredSize
);
538 aStatus
= NS_FRAME_COMPLETE
;
539 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
543 nsTextControlFrame::ReflowTextControlChild(nsIFrame
* aKid
,
544 nsPresContext
* aPresContext
,
545 const nsHTMLReflowState
& aReflowState
,
546 nsReflowStatus
& aStatus
,
547 nsHTMLReflowMetrics
& aParentDesiredSize
)
549 // compute available size and frame offsets for child
550 WritingMode wm
= aKid
->GetWritingMode();
551 LogicalSize availSize
= aReflowState
.ComputedSizeWithPadding(wm
);
552 availSize
.BSize(wm
) = NS_UNCONSTRAINEDSIZE
;
554 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
,
555 aKid
, availSize
, -1, -1,
556 nsHTMLReflowState::CALLER_WILL_INIT
);
557 // Override padding with our computed padding in case we got it from theming or percentage
558 kidReflowState
.Init(aPresContext
, -1, -1, nullptr, &aReflowState
.ComputedPhysicalPadding());
560 // Set computed width and computed height for the child
561 kidReflowState
.SetComputedWidth(aReflowState
.ComputedWidth());
562 kidReflowState
.SetComputedHeight(aReflowState
.ComputedHeight());
564 // Offset the frame by the size of the parent's border
565 nscoord xOffset
= aReflowState
.ComputedPhysicalBorderPadding().left
-
566 aReflowState
.ComputedPhysicalPadding().left
;
567 nscoord yOffset
= aReflowState
.ComputedPhysicalBorderPadding().top
-
568 aReflowState
.ComputedPhysicalPadding().top
;
571 nsHTMLReflowMetrics
desiredSize(aReflowState
);
572 ReflowChild(aKid
, aPresContext
, desiredSize
, kidReflowState
,
573 xOffset
, yOffset
, 0, aStatus
);
576 FinishReflowChild(aKid
, aPresContext
, desiredSize
,
577 &kidReflowState
, xOffset
, yOffset
, 0);
579 // consider the overflow
580 aParentDesiredSize
.mOverflowAreas
.UnionWith(desiredSize
.mOverflowAreas
);
584 nsTextControlFrame::GetMinSize(nsBoxLayoutState
& aState
)
586 // XXXbz why? Why not the nsBoxFrame sizes?
587 return nsBox::GetMinSize(aState
);
591 nsTextControlFrame::IsCollapsed()
593 // We're never collapsed in the box sense.
598 nsTextControlFrame::IsLeaf() const
604 nsTextControlFrame::ScrollOnFocusEvent::Run()
607 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(mFrame
->GetContent());
608 NS_ASSERTION(txtCtrl
, "Content not a text control element");
609 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
611 mFrame
->mScrollEvent
.Forget();
612 selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
613 nsISelectionController::SELECTION_FOCUS_REGION
,
614 nsISelectionController::SCROLL_SYNCHRONOUS
);
620 //IMPLEMENTING NS_IFORMCONTROLFRAME
621 void nsTextControlFrame::SetFocus(bool aOn
, bool aRepaint
)
623 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
624 NS_ASSERTION(txtCtrl
, "Content not a text control element");
626 // Revoke the previous scroll event if one exists
627 mScrollEvent
.Revoke();
629 // If 'dom.placeholeder.show_on_focus' preference is 'false', focusing or
630 // blurring the frame can have an impact on the placeholder visibility.
631 if (mUsePlaceholder
) {
632 txtCtrl
->UpdatePlaceholderVisibility(true);
639 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
643 nsCOMPtr
<nsISelection
> ourSel
;
644 selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
645 getter_AddRefs(ourSel
));
648 nsIPresShell
* presShell
= PresContext()->GetPresShell();
649 nsRefPtr
<nsCaret
> caret
= presShell
->GetCaret();
652 // Scroll the current selection into view
653 nsISelection
*caretSelection
= caret
->GetSelection();
654 const bool isFocusedRightNow
= ourSel
== caretSelection
;
655 if (!isFocusedRightNow
) {
656 // Don't scroll the current selection if we've been focused using the mouse.
657 uint32_t lastFocusMethod
= 0;
658 nsIDocument
* doc
= GetContent()->GetComposedDoc();
660 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
662 fm
->GetLastFocusMethod(doc
->GetWindow(), &lastFocusMethod
);
665 if (!(lastFocusMethod
& nsIFocusManager::FLAG_BYMOUSE
)) {
666 nsRefPtr
<ScrollOnFocusEvent
> event
= new ScrollOnFocusEvent(this);
667 nsresult rv
= NS_DispatchToCurrentThread(event
);
668 if (NS_SUCCEEDED(rv
)) {
669 mScrollEvent
= event
;
674 // tell the caret to use our selection
675 caret
->SetSelection(ourSel
);
677 // mutual-exclusion: the selection is either controlled by the
678 // document or by the text input/area. Clear any selection in the
679 // document since the focus is now on our independent selection.
681 nsCOMPtr
<nsISelectionController
> selcon
= do_QueryInterface(presShell
);
682 nsCOMPtr
<nsISelection
> docSel
;
683 selcon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
684 getter_AddRefs(docSel
));
687 bool isCollapsed
= false;
688 docSel
->GetIsCollapsed(&isCollapsed
);
690 docSel
->RemoveAllRanges();
693 nsresult
nsTextControlFrame::SetFormProperty(nsIAtom
* aName
, const nsAString
& aValue
)
695 if (!mIsProcessing
)//some kind of lock.
697 mIsProcessing
= true;
698 if (nsGkAtoms::select
== aName
)
700 // Select all the text.
702 // XXX: This is lame, we can't call editor's SelectAll method
703 // because that triggers AutoCopies in unix builds.
704 // Instead, we have to call our own homegrown version
705 // of select all which merely builds a range that selects
706 // all of the content and adds that to the selection.
708 nsWeakFrame weakThis
= this;
709 SelectAllOrCollapseToEndOfText(true); // NOTE: can destroy the world
710 if (!weakThis
.IsAlive()) {
714 mIsProcessing
= false;
720 nsTextControlFrame::GetEditor(nsIEditor
**aEditor
)
722 NS_ENSURE_ARG_POINTER(aEditor
);
724 nsresult rv
= EnsureEditorInitialized();
725 NS_ENSURE_SUCCESS(rv
, rv
);
727 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
728 NS_ASSERTION(txtCtrl
, "Content not a text control element");
729 *aEditor
= txtCtrl
->GetTextEditor();
730 NS_IF_ADDREF(*aEditor
);
735 nsTextControlFrame::SetSelectionInternal(nsIDOMNode
*aStartNode
,
736 int32_t aStartOffset
,
737 nsIDOMNode
*aEndNode
,
739 nsITextControlFrame::SelectionDirection aDirection
)
741 // Create a new range to represent the new selection.
742 // Note that we use a new range to avoid having to do
743 // isIncreasing checks to avoid possible errors.
745 nsRefPtr
<nsRange
> range
= new nsRange(mContent
);
746 nsresult rv
= range
->SetStart(aStartNode
, aStartOffset
);
747 NS_ENSURE_SUCCESS(rv
, rv
);
749 rv
= range
->SetEnd(aEndNode
, aEndOffset
);
750 NS_ENSURE_SUCCESS(rv
, rv
);
752 // Get the selection, clear it and add the new range to it!
753 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
754 NS_ASSERTION(txtCtrl
, "Content not a text control element");
755 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
756 NS_ENSURE_TRUE(selCon
, NS_ERROR_FAILURE
);
758 nsCOMPtr
<nsISelection
> selection
;
759 selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
760 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
762 nsCOMPtr
<nsISelectionPrivate
> selPriv
= do_QueryInterface(selection
, &rv
);
763 NS_ENSURE_SUCCESS(rv
, rv
);
765 nsDirection direction
;
766 if (aDirection
== eNone
) {
767 // Preserve the direction
768 direction
= selPriv
->GetSelectionDirection();
770 direction
= (aDirection
== eBackward
) ? eDirPrevious
: eDirNext
;
773 rv
= selection
->RemoveAllRanges();
774 NS_ENSURE_SUCCESS(rv
, rv
);
776 rv
= selection
->AddRange(range
); // NOTE: can destroy the world
777 NS_ENSURE_SUCCESS(rv
, rv
);
779 selPriv
->SetSelectionDirection(direction
);
784 nsTextControlFrame::ScrollSelectionIntoView()
786 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
787 NS_ASSERTION(txtCtrl
, "Content not a text control element");
788 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
790 // Scroll the selection into view (see bug 231389).
791 return selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
792 nsISelectionController::SELECTION_FOCUS_REGION
,
793 nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY
);
796 return NS_ERROR_FAILURE
;
799 mozilla::dom::Element
*
800 nsTextControlFrame::GetRootNodeAndInitializeEditor()
802 nsCOMPtr
<nsIDOMElement
> root
;
803 GetRootNodeAndInitializeEditor(getter_AddRefs(root
));
804 nsCOMPtr
<mozilla::dom::Element
> rootElem
= do_QueryInterface(root
);
809 nsTextControlFrame::GetRootNodeAndInitializeEditor(nsIDOMElement
**aRootElement
)
811 NS_ENSURE_ARG_POINTER(aRootElement
);
813 nsCOMPtr
<nsIEditor
> editor
;
814 GetEditor(getter_AddRefs(editor
));
818 return editor
->GetRootElement(aRootElement
);
822 nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect
)
824 nsCOMPtr
<nsIDOMElement
> rootElement
;
825 nsresult rv
= GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement
));
826 NS_ENSURE_SUCCESS(rv
, rv
);
828 nsCOMPtr
<nsIContent
> rootContent
= do_QueryInterface(rootElement
);
829 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
831 NS_ENSURE_TRUE(rootNode
&& rootContent
, NS_ERROR_FAILURE
);
833 int32_t numChildren
= rootContent
->GetChildCount();
835 if (numChildren
> 0) {
836 // We never want to place the selection after the last
837 // br under the root node!
838 nsIContent
*child
= rootContent
->GetChildAt(numChildren
- 1);
840 if (child
->Tag() == nsGkAtoms::br
)
843 if (!aSelect
&& numChildren
) {
844 child
= rootContent
->GetChildAt(numChildren
- 1);
845 if (child
&& child
->IsNodeOfType(nsINode::eTEXT
)) {
846 rootNode
= do_QueryInterface(child
);
847 const nsTextFragment
* fragment
= child
->GetText();
848 numChildren
= fragment
? fragment
->GetLength() : 0;
853 rv
= SetSelectionInternal(rootNode
, aSelect
? 0 : numChildren
,
854 rootNode
, numChildren
);
855 NS_ENSURE_SUCCESS(rv
, rv
);
857 return ScrollSelectionIntoView();
861 nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart
, int32_t aSelEnd
,
862 nsITextControlFrame::SelectionDirection aDirection
)
864 NS_ASSERTION(aSelStart
<= aSelEnd
, "Invalid selection offsets!");
866 if (aSelStart
> aSelEnd
)
867 return NS_ERROR_FAILURE
;
869 nsCOMPtr
<nsIDOMNode
> startNode
, endNode
;
870 int32_t startOffset
, endOffset
;
872 // Calculate the selection start point.
874 nsresult rv
= OffsetToDOMPoint(aSelStart
, getter_AddRefs(startNode
), &startOffset
);
876 NS_ENSURE_SUCCESS(rv
, rv
);
878 if (aSelStart
== aSelEnd
) {
879 // Collapsed selection, so start and end are the same!
881 endOffset
= startOffset
;
884 // Selection isn't collapsed so we have to calculate
885 // the end point too.
887 rv
= OffsetToDOMPoint(aSelEnd
, getter_AddRefs(endNode
), &endOffset
);
889 NS_ENSURE_SUCCESS(rv
, rv
);
892 return SetSelectionInternal(startNode
, startOffset
, endNode
, endOffset
, aDirection
);
896 nsTextControlFrame::SetSelectionRange(int32_t aSelStart
, int32_t aSelEnd
,
897 nsITextControlFrame::SelectionDirection aDirection
)
899 nsresult rv
= EnsureEditorInitialized();
900 NS_ENSURE_SUCCESS(rv
, rv
);
902 if (aSelStart
> aSelEnd
) {
903 // Simulate what we'd see SetSelectionStart() was called, followed
904 // by a SetSelectionEnd().
909 return SetSelectionEndPoints(aSelStart
, aSelEnd
, aDirection
);
914 nsTextControlFrame::SetSelectionStart(int32_t aSelectionStart
)
916 nsresult rv
= EnsureEditorInitialized();
917 NS_ENSURE_SUCCESS(rv
, rv
);
919 int32_t selStart
= 0, selEnd
= 0;
921 rv
= GetSelectionRange(&selStart
, &selEnd
);
922 NS_ENSURE_SUCCESS(rv
, rv
);
924 if (aSelectionStart
> selEnd
) {
925 // Collapse to the new start point.
926 selEnd
= aSelectionStart
;
929 selStart
= aSelectionStart
;
931 return SetSelectionEndPoints(selStart
, selEnd
);
935 nsTextControlFrame::SetSelectionEnd(int32_t aSelectionEnd
)
937 nsresult rv
= EnsureEditorInitialized();
938 NS_ENSURE_SUCCESS(rv
, rv
);
940 int32_t selStart
= 0, selEnd
= 0;
942 rv
= GetSelectionRange(&selStart
, &selEnd
);
943 NS_ENSURE_SUCCESS(rv
, rv
);
945 if (aSelectionEnd
< selStart
) {
946 // Collapse to the new end point.
947 selStart
= aSelectionEnd
;
950 selEnd
= aSelectionEnd
;
952 return SetSelectionEndPoints(selStart
, selEnd
);
956 nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset
,
957 nsIDOMNode
** aResult
,
960 NS_ENSURE_ARG_POINTER(aResult
&& aPosition
);
965 nsCOMPtr
<nsIDOMElement
> rootElement
;
966 nsresult rv
= GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement
));
967 NS_ENSURE_SUCCESS(rv
, rv
);
968 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
970 NS_ENSURE_TRUE(rootNode
, NS_ERROR_FAILURE
);
972 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
974 rv
= rootNode
->GetChildNodes(getter_AddRefs(nodeList
));
975 NS_ENSURE_SUCCESS(rv
, rv
);
976 NS_ENSURE_TRUE(nodeList
, NS_ERROR_FAILURE
);
980 rv
= nodeList
->GetLength(&length
);
981 NS_ENSURE_SUCCESS(rv
, rv
);
983 NS_ASSERTION(length
<= 2, "We should have one text node and one mozBR at most");
985 nsCOMPtr
<nsIDOMNode
> firstNode
;
986 rv
= nodeList
->Item(0, getter_AddRefs(firstNode
));
987 NS_ENSURE_SUCCESS(rv
, rv
);
988 nsCOMPtr
<nsIDOMText
> textNode
= do_QueryInterface(firstNode
);
990 if (length
== 0 || aOffset
< 0) {
991 NS_IF_ADDREF(*aResult
= rootNode
);
993 } else if (textNode
) {
994 uint32_t textLength
= 0;
995 textNode
->GetLength(&textLength
);
996 if (length
== 2 && uint32_t(aOffset
) == textLength
) {
997 // If we're at the end of the text node and we have a trailing BR node,
998 // set the selection on the BR node.
999 NS_IF_ADDREF(*aResult
= rootNode
);
1002 // Otherwise, set the selection on the textnode itself.
1003 NS_IF_ADDREF(*aResult
= firstNode
);
1004 *aPosition
= std::min(aOffset
, int32_t(textLength
));
1007 NS_IF_ADDREF(*aResult
= rootNode
);
1015 nsTextControlFrame::GetSelectionRange(int32_t* aSelectionStart
,
1016 int32_t* aSelectionEnd
,
1017 SelectionDirection
* aDirection
)
1019 // make sure we have an editor
1020 nsresult rv
= EnsureEditorInitialized();
1021 NS_ENSURE_SUCCESS(rv
, rv
);
1023 if (aSelectionStart
) {
1024 *aSelectionStart
= 0;
1026 if (aSelectionEnd
) {
1030 *aDirection
= eNone
;
1033 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1034 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1035 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
1036 NS_ENSURE_TRUE(selCon
, NS_ERROR_FAILURE
);
1037 nsCOMPtr
<nsISelection
> selection
;
1038 rv
= selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
1039 NS_ENSURE_SUCCESS(rv
, rv
);
1040 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
1042 dom::Selection
* sel
= static_cast<dom::Selection
*>(selection
.get());
1044 nsDirection direction
= sel
->GetSelectionDirection();
1045 if (direction
== eDirNext
) {
1046 *aDirection
= eForward
;
1047 } else if (direction
== eDirPrevious
) {
1048 *aDirection
= eBackward
;
1050 NS_NOTREACHED("Invalid nsDirection enum value");
1054 if (!aSelectionStart
|| !aSelectionEnd
) {
1058 mozilla::dom::Element
* root
= GetRootNodeAndInitializeEditor();
1059 NS_ENSURE_STATE(root
);
1060 nsContentUtils::GetSelectionInTextControl(sel
, root
,
1061 *aSelectionStart
, *aSelectionEnd
);
1066 /////END INTERFACE IMPLEMENTATIONS
1070 nsTextControlFrame::AttributeChanged(int32_t aNameSpaceID
,
1071 nsIAtom
* aAttribute
,
1074 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1075 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1076 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
1077 const bool needEditor
= nsGkAtoms::maxlength
== aAttribute
||
1078 nsGkAtoms::readonly
== aAttribute
||
1079 nsGkAtoms::disabled
== aAttribute
||
1080 nsGkAtoms::spellcheck
== aAttribute
;
1081 nsCOMPtr
<nsIEditor
> editor
;
1083 GetEditor(getter_AddRefs(editor
));
1085 if ((needEditor
&& !editor
) || !selCon
) {
1086 return nsContainerFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
1089 if (nsGkAtoms::maxlength
== aAttribute
) {
1091 bool maxDefined
= GetMaxLength(&maxLength
);
1092 nsCOMPtr
<nsIPlaintextEditor
> textEditor
= do_QueryInterface(editor
);
1094 if (maxDefined
) { // set the maxLength attribute
1095 textEditor
->SetMaxTextLength(maxLength
);
1096 // if maxLength>docLength, we need to truncate the doc content
1097 } else { // unset the maxLength attribute
1098 textEditor
->SetMaxTextLength(-1);
1104 if (nsGkAtoms::readonly
== aAttribute
) {
1106 editor
->GetFlags(&flags
);
1107 if (AttributeExists(nsGkAtoms::readonly
)) { // set readonly
1108 flags
|= nsIPlaintextEditor::eEditorReadonlyMask
;
1109 if (nsContentUtils::IsFocusedContent(mContent
)) {
1110 selCon
->SetCaretEnabled(false);
1112 } else { // unset readonly
1113 flags
&= ~(nsIPlaintextEditor::eEditorReadonlyMask
);
1114 if (!(flags
& nsIPlaintextEditor::eEditorDisabledMask
) &&
1115 nsContentUtils::IsFocusedContent(mContent
)) {
1116 selCon
->SetCaretEnabled(true);
1119 editor
->SetFlags(flags
);
1123 if (nsGkAtoms::disabled
== aAttribute
) {
1125 editor
->GetFlags(&flags
);
1126 int16_t displaySelection
= nsISelectionController::SELECTION_OFF
;
1127 const bool focused
= nsContentUtils::IsFocusedContent(mContent
);
1128 const bool hasAttr
= AttributeExists(nsGkAtoms::disabled
);
1129 if (hasAttr
) { // set disabled
1130 flags
|= nsIPlaintextEditor::eEditorDisabledMask
;
1131 } else { // unset disabled
1132 flags
&= ~(nsIPlaintextEditor::eEditorDisabledMask
);
1133 displaySelection
= focused
? nsISelectionController::SELECTION_ON
1134 : nsISelectionController::SELECTION_HIDDEN
;
1136 selCon
->SetDisplaySelection(displaySelection
);
1138 selCon
->SetCaretEnabled(!hasAttr
);
1140 editor
->SetFlags(flags
);
1144 if (!mEditorHasBeenInitialized
&& nsGkAtoms::value
== aAttribute
) {
1145 UpdateValueDisplay(true);
1149 // Allow the base class to handle common attributes supported by all form
1151 return nsContainerFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
1156 nsTextControlFrame::GetText(nsString
& aText
)
1158 nsresult rv
= NS_OK
;
1159 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1160 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1161 if (IsSingleLineTextControl()) {
1162 // There will be no line breaks so we can ignore the wrap property.
1163 txtCtrl
->GetTextEditorValue(aText
, true);
1165 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textArea
= do_QueryInterface(mContent
);
1167 rv
= textArea
->GetValue(aText
);
1175 nsTextControlFrame::GetPhonetic(nsAString
& aPhonetic
)
1177 aPhonetic
.Truncate(0);
1179 nsCOMPtr
<nsIEditor
> editor
;
1180 nsresult rv
= GetEditor(getter_AddRefs(editor
));
1181 NS_ENSURE_SUCCESS(rv
, rv
);
1183 nsCOMPtr
<nsIEditorIMESupport
> imeSupport
= do_QueryInterface(editor
);
1185 nsCOMPtr
<nsIPhonetic
> phonetic
= do_QueryInterface(imeSupport
);
1187 phonetic
->GetPhonetic(aPhonetic
);
1192 ///END NSIFRAME OVERLOADS
1193 /////BEGIN PROTECTED METHODS
1196 nsTextControlFrame::GetMaxLength(int32_t* aSize
)
1200 nsGenericHTMLElement
*content
= nsGenericHTMLElement::FromContent(mContent
);
1202 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::maxlength
);
1203 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
1204 *aSize
= attr
->GetIntegerValue();
1212 // END IMPLEMENTING NS_IFORMCONTROLFRAME
1215 nsTextControlFrame::SetInitialChildList(ChildListID aListID
,
1216 nsFrameList
& aChildList
)
1218 nsContainerFrame::SetInitialChildList(aListID
, aChildList
);
1220 nsIFrame
* first
= GetFirstPrincipalChild();
1222 // Mark the scroll frame as being a reflow root. This will allow
1223 // incremental reflows to be initiated at the scroll frame, rather
1224 // than descending from the root frame of the frame hierarchy.
1226 first
->AddStateBits(NS_FRAME_REFLOW_ROOT
);
1228 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1229 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1230 txtCtrl
->InitializeKeyboardEventListeners();
1232 nsPoint
* contentScrollPos
= static_cast<nsPoint
*>
1233 (Properties().Get(ContentScrollPos()));
1234 if (contentScrollPos
) {
1235 // If we have a scroll pos stored to be passed to our anonymous
1237 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(first
);
1238 NS_ASSERTION(statefulFrame
, "unexpected type of frame for the anonymous div");
1239 nsPresState fakePresState
;
1240 fakePresState
.SetScrollState(*contentScrollPos
);
1241 statefulFrame
->RestoreState(&fakePresState
);
1242 Properties().Remove(ContentScrollPos());
1243 delete contentScrollPos
;
1249 nsTextControlFrame::SetValueChanged(bool aValueChanged
)
1251 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1252 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1254 if (mUsePlaceholder
) {
1255 nsWeakFrame
weakFrame(this);
1256 txtCtrl
->UpdatePlaceholderVisibility(true);
1257 if (!weakFrame
.IsAlive()) {
1262 txtCtrl
->SetValueChanged(aValueChanged
);
1267 nsTextControlFrame::UpdateValueDisplay(bool aNotify
,
1268 bool aBeforeEditorInit
,
1269 const nsAString
*aValue
)
1271 if (!IsSingleLineTextControl()) // textareas don't use this
1274 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1275 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1276 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1278 NS_PRECONDITION(rootNode
, "Must have a div content\n");
1279 NS_PRECONDITION(!mEditorHasBeenInitialized
,
1280 "Do not call this after editor has been initialized");
1281 NS_ASSERTION(!mUsePlaceholder
|| txtCtrl
->GetPlaceholderNode(),
1282 "A placeholder div must exist");
1284 nsIContent
*textContent
= rootNode
->GetChildAt(0);
1286 // Set up a textnode with our value
1287 nsRefPtr
<nsTextNode
> textNode
=
1288 new nsTextNode(mContent
->NodeInfo()->NodeInfoManager());
1290 NS_ASSERTION(textNode
, "Must have textcontent!\n");
1292 rootNode
->AppendChildTo(textNode
, aNotify
);
1293 textContent
= textNode
;
1296 NS_ENSURE_TRUE(textContent
, NS_ERROR_UNEXPECTED
);
1298 // Get the current value of the textfield from the content.
1303 txtCtrl
->GetTextEditorValue(value
, true);
1306 // Update the display of the placeholder value if needed.
1307 // We don't need to do this if we're about to initialize the
1308 // editor, since EnsureEditorInitialized takes care of this.
1309 if (mUsePlaceholder
&& !aBeforeEditorInit
)
1311 nsWeakFrame
weakFrame(this);
1312 txtCtrl
->UpdatePlaceholderVisibility(aNotify
);
1313 NS_ENSURE_STATE(weakFrame
.IsAlive());
1316 if (aBeforeEditorInit
&& value
.IsEmpty()) {
1317 rootNode
->RemoveChildAt(0, true);
1321 if (!value
.IsEmpty() && IsPasswordTextControl()) {
1322 nsTextEditRules::FillBufWithPWChars(&value
, value
.Length());
1324 return textContent
->SetText(value
, aNotify
);
1328 nsTextControlFrame::GetOwnedSelectionController(nsISelectionController
** aSelCon
)
1330 NS_ENSURE_ARG_POINTER(aSelCon
);
1332 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1333 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1335 *aSelCon
= txtCtrl
->GetSelectionController();
1336 NS_IF_ADDREF(*aSelCon
);
1342 nsTextControlFrame::GetOwnedFrameSelection()
1344 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1345 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1347 return txtCtrl
->GetConstFrameSelection();
1351 nsTextControlFrame::SaveState(nsPresState
** aState
)
1353 NS_ENSURE_ARG_POINTER(aState
);
1357 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1358 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1360 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1362 // Query the nsIStatefulFrame from the HTMLScrollFrame
1363 nsIStatefulFrame
* scrollStateFrame
= do_QueryFrame(rootNode
->GetPrimaryFrame());
1364 if (scrollStateFrame
) {
1365 return scrollStateFrame
->SaveState(aState
);
1373 nsTextControlFrame::RestoreState(nsPresState
* aState
)
1375 NS_ENSURE_ARG_POINTER(aState
);
1377 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1378 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1380 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1382 // Query the nsIStatefulFrame from the HTMLScrollFrame
1383 nsIStatefulFrame
* scrollStateFrame
= do_QueryFrame(rootNode
->GetPrimaryFrame());
1384 if (scrollStateFrame
) {
1385 return scrollStateFrame
->RestoreState(aState
);
1389 // Most likely, we don't have our anonymous content constructed yet, which
1390 // would cause us to end up here. In this case, we'll just store the scroll
1391 // pos ourselves, and forward it to the scroll frame later when it's created.
1392 Properties().Set(ContentScrollPos(), new nsPoint(aState
->GetScrollState()));
1397 nsTextControlFrame::PeekOffset(nsPeekOffsetStruct
*aPos
)
1399 return NS_ERROR_FAILURE
;
1403 nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
1404 const nsRect
& aDirtyRect
,
1405 const nsDisplayListSet
& aLists
)
1408 * The implementation of this method is equivalent as:
1409 * nsContainerFrame::BuildDisplayList()
1410 * with the difference that we filter-out the placeholder frame when it
1411 * should not be visible.
1413 DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame");
1415 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1416 NS_ASSERTION(txtCtrl
, "Content not a text control element!");
1418 DisplayBorderBackgroundOutline(aBuilder
, aLists
);
1420 nsIFrame
* kid
= mFrames
.FirstChild();
1421 // Redirect all lists to the Content list so that nothing can escape, ie
1422 // opacity creating stacking contexts that then get sorted with stacking
1423 // contexts external to us.
1424 nsDisplayList
* content
= aLists
.Content();
1425 nsDisplayListSet
set(content
, content
, content
, content
, content
, content
);
1428 // If the frame is the placeholder frame, we should only show it if the
1429 // placeholder has to be visible.
1430 if (kid
->GetContent() != txtCtrl
->GetPlaceholderNode() ||
1431 txtCtrl
->GetPlaceholderVisibility()) {
1432 BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, set
, 0);
1434 kid
= kid
->GetNextSibling();
1438 mozilla::dom::Element
*
1439 nsTextControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType
)
1441 if (aType
== nsCSSPseudoElements::ePseudo_mozPlaceholder
) {
1442 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1443 return txtCtrl
->GetPlaceholderNode();
1446 return nsContainerFrame::GetPseudoElement(aType
);
1450 nsTextControlFrame::EditorInitializer::Run()
1456 // Need to block script to avoid bug 669767.
1457 nsAutoScriptBlocker scriptBlocker
;
1459 nsCOMPtr
<nsIPresShell
> shell
=
1460 mFrame
->PresContext()->GetPresShell();
1461 bool observes
= shell
->ObservesNativeAnonMutationsForPrint();
1462 shell
->ObserveNativeAnonMutationsForPrint(true);
1463 // This can cause the frame to be destroyed (and call Revoke()).
1464 mFrame
->EnsureEditorInitialized();
1465 shell
->ObserveNativeAnonMutationsForPrint(observes
);
1467 // The frame can *still* be destroyed even though we have a scriptblocker,
1470 return NS_ERROR_FAILURE
;
1473 mFrame
->FinishedInitializer();