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/. */
7 #include "nsTextControlFrame.h"
8 #include "nsIDocument.h"
9 #include "nsIFormControl.h"
10 #include "nsIServiceManager.h"
11 #include "nsFrameSelection.h"
12 #include "nsIPlaintextEditor.h"
13 #include "nsEditorCID.h"
14 #include "nsLayoutCID.h"
15 #include "nsIDocumentEncoder.h"
17 #include "nsISelectionListener.h"
18 #include "nsIController.h"
19 #include "nsIControllers.h"
20 #include "nsIControllerContext.h"
21 #include "nsGenericHTMLElement.h"
22 #include "nsIEditorIMESupport.h"
23 #include "nsIPhonetic.h"
24 #include "nsTextFragment.h"
25 #include "nsIEditorObserver.h"
26 #include "nsEditProperty.h"
27 #include "nsIDOMHTMLTextAreaElement.h"
28 #include "nsINameSpaceManager.h"
29 #include "nsINodeInfo.h"
30 #include "nsFormControlFrame.h" //for registering accesskeys
32 #include "nsIContent.h"
34 #include "nsPresContext.h"
35 #include "nsRenderingContext.h"
36 #include "nsGkAtoms.h"
37 #include "nsLayoutUtils.h"
38 #include "nsIComponentManager.h"
40 #include "nsIViewManager.h"
41 #include "nsIDOMHTMLInputElement.h"
42 #include "nsIDOMElement.h"
43 #include "nsIDOMHTMLElement.h"
44 #include "nsIPresShell.h"
46 #include "nsBoxLayoutState.h"
47 //for keylistener for "return" check
48 #include "nsIDOMEventTarget.h"
49 #include "nsIDocument.h" //observe documents to send onchangenotifications
50 #include "nsIStyleSheet.h"//observe documents to send onchangenotifications
51 #include "nsIStyleRule.h"//observe documents to send onchangenotifications
52 #include "nsIDOMEventListener.h"//observe documents to send onchangenotifications
53 #include "nsGUIEvent.h"
55 #include "nsIDOMCharacterData.h" //for selection setting helper func
56 #include "nsIDOMNodeList.h" //for selection setting helper func
57 #include "nsIDOMRange.h" //for selection setting helper func
58 #include "nsPIDOMWindow.h" //needed for notify selection changed to update the menus ect.
60 #include "nsAccessibilityService.h"
62 #include "nsIDOMNode.h"
64 #include "nsITransactionManager.h"
65 #include "nsIDOMText.h" //for multiline getselection
66 #include "nsNodeInfoManager.h"
67 #include "nsContentCreatorFunctions.h"
68 #include "nsINativeKeyBindings.h"
69 #include "nsIJSContextStack.h"
70 #include "nsFocusManager.h"
71 #include "nsTextEditRules.h"
72 #include "nsPresState.h"
74 #include "mozilla/FunctionTimer.h"
75 #include "mozilla/Selection.h"
77 #define DEFAULT_COLUMN_WIDTH 20
79 using namespace mozilla
;
82 NS_NewTextControlFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
84 return new (aPresShell
) nsTextControlFrame(aPresShell
, aContext
);
87 NS_IMPL_FRAMEARENA_HELPERS(nsTextControlFrame
)
89 NS_QUERYFRAME_HEAD(nsTextControlFrame
)
90 NS_QUERYFRAME_ENTRY(nsIFormControlFrame
)
91 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator
)
92 NS_QUERYFRAME_ENTRY(nsITextControlFrame
)
93 NS_QUERYFRAME_ENTRY(nsIStatefulFrame
)
94 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
97 already_AddRefed
<Accessible
>
98 nsTextControlFrame::CreateAccessible()
100 nsAccessibilityService
* accService
= nsIPresShell::AccService();
102 return accService
->CreateHTMLTextFieldAccessible(mContent
,
103 PresContext()->PresShell());
111 class EditorInitializerEntryTracker
{
113 explicit EditorInitializerEntryTracker(nsTextControlFrame
&frame
)
117 if (!mFrame
.mInEditorInitialization
) {
118 mFrame
.mInEditorInitialization
= true;
122 ~EditorInitializerEntryTracker()
125 mFrame
.mInEditorInitialization
= false;
128 bool EnteredMoreThanOnce() const { return !mFirstEntry
; }
130 nsTextControlFrame
&mFrame
;
135 nsTextControlFrame::nsTextControlFrame(nsIPresShell
* aShell
, nsStyleContext
* aContext
)
136 : nsContainerFrame(aContext
)
138 , mIsProcessing(false)
140 , mInEditorInitialization(false)
145 nsTextControlFrame::~nsTextControlFrame()
150 nsTextControlFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
152 mScrollEvent
.Revoke();
154 EditorInitializer
* initializer
= (EditorInitializer
*) Properties().Get(TextControlInitializer());
156 initializer
->Revoke();
157 Properties().Delete(TextControlInitializer());
160 // Unbind the text editor state object from the frame. The editor will live
161 // on, but things like controllers will be released.
162 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
163 NS_ASSERTION(txtCtrl
, "Content not a text control element");
164 txtCtrl
->UnbindFromFrame(this);
166 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame
*>(this), false);
168 nsContainerFrame::DestroyFrom(aDestructRoot
);
172 nsTextControlFrame::GetType() const
174 return nsGkAtoms::textInputFrame
;
178 nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext
* aRenderingContext
,
179 nsSize
& aIntrinsicSize
,
180 float aFontSizeInflation
)
182 // Get leading and the Average/MaxAdvance char width
183 nscoord lineHeight
= 0;
184 nscoord charWidth
= 0;
185 nscoord charMaxAdvance
= 0;
187 nsRefPtr
<nsFontMetrics
> fontMet
;
189 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet
),
191 NS_ENSURE_SUCCESS(rv
, rv
);
192 aRenderingContext
->SetFont(fontMet
);
195 nsHTMLReflowState::CalcLineHeight(GetStyleContext(), NS_AUTOHEIGHT
,
197 charWidth
= fontMet
->AveCharWidth();
198 charMaxAdvance
= fontMet
->MaxAdvance();
200 // Set the width equal to the width in characters
201 PRInt32 cols
= GetCols();
202 aIntrinsicSize
.width
= cols
* charWidth
;
204 // To better match IE, take the maximum character width(in twips) and remove
205 // 4 pixels add this on as additional padding(internalPadding). But only do
206 // this if charMaxAdvance != charWidth; if they are equal, this is almost
207 // certainly a fixed-width font.
208 if (charWidth
!= charMaxAdvance
) {
209 nscoord internalPadding
= NS_MAX(0, charMaxAdvance
-
210 nsPresContext::CSSPixelsToAppUnits(4));
211 nscoord t
= nsPresContext::CSSPixelsToAppUnits(1);
212 // Round to a multiple of t
213 nscoord rest
= internalPadding
% t
;
214 if (rest
< t
- rest
) {
215 internalPadding
-= rest
;
217 internalPadding
+= t
- rest
;
219 // Now add the extra padding on (so that small input sizes work well)
220 aIntrinsicSize
.width
+= internalPadding
;
222 // This is to account for the anonymous <br> having a 1 twip width
223 // in Full Standards mode, see BRFrame::Reflow and bug 228752.
224 if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards
) {
225 aIntrinsicSize
.width
+= 1;
228 // Also add in the padding of our value div child. Note that it hasn't
229 // been reflowed yet, so we can't get its used padding, but it shouldn't be
230 // using percentage padding anyway.
231 nsMargin childPadding
;
232 nsIFrame
* firstChild
= GetFirstPrincipalChild();
233 if (firstChild
&& firstChild
->GetStylePadding()->GetPadding(childPadding
)) {
234 aIntrinsicSize
.width
+= childPadding
.LeftRight();
236 NS_ERROR("Percentage padding on value div?");
240 // Increment width with cols * letter-spacing.
242 const nsStyleCoord
& lsCoord
= GetStyleText()->mLetterSpacing
;
243 if (eStyleUnit_Coord
== lsCoord
.GetUnit()) {
244 nscoord letterSpacing
= lsCoord
.GetCoordValue();
245 if (letterSpacing
!= 0) {
246 aIntrinsicSize
.width
+= cols
* letterSpacing
;
251 // Set the height equal to total number of rows (times the height of each
253 aIntrinsicSize
.height
= lineHeight
* GetRows();
255 // Add in the size of the scrollbars for textarea
257 nsIFrame
* first
= GetFirstPrincipalChild();
259 nsIScrollableFrame
*scrollableFrame
= do_QueryFrame(first
);
260 NS_ASSERTION(scrollableFrame
, "Child must be scrollable");
262 if (scrollableFrame
) {
263 nsMargin scrollbarSizes
=
264 scrollableFrame
->GetDesiredScrollbarSizes(PresContext(), aRenderingContext
);
266 aIntrinsicSize
.width
+= scrollbarSizes
.LeftRight();
268 aIntrinsicSize
.height
+= scrollbarSizes
.TopBottom();;
276 nsTextControlFrame::EnsureEditorInitialized()
278 // This method initializes our editor, if needed.
280 // This code used to be called from CreateAnonymousContent(), but
281 // when the editor set the initial string, it would trigger a
282 // PresShell listener which called FlushPendingNotifications()
283 // during frame construction. This was causing other form controls
284 // to display wrong values. Additionally, calling this every time
285 // a text frame control is instantiated means that we're effectively
286 // instantiating the editor for all text fields, even if they
287 // never get used. So, now this method is being called lazily only
288 // when we actually need an editor.
290 // Check if this method has been called already.
291 // If so, just return early.
297 nsIDocument
* doc
= mContent
->GetCurrentDoc();
298 NS_ENSURE_TRUE(doc
, NS_ERROR_FAILURE
);
300 nsWeakFrame
weakFrame(this);
302 // Flush out content on our document. Have to do this, because script
303 // blockers don't prevent the sink flushing out content and notifying in the
304 // process, which can destroy frames.
305 doc
->FlushPendingNotifications(Flush_ContentAndNotify
);
306 NS_ENSURE_TRUE(weakFrame
.IsAlive(), NS_ERROR_FAILURE
);
308 // Make sure that editor init doesn't do things that would kill us off
309 // (especially off the script blockers it'll create for its DOM mutations).
310 nsAutoScriptBlocker scriptBlocker
;
312 // Time to mess with our security context... See comments in GetValue()
313 // for why this is needed.
317 // Make sure that we try to focus the content even if the method fails
318 class EnsureSetFocus
{
320 explicit EnsureSetFocus(nsTextControlFrame
* aFrame
)
323 if (nsContentUtils::IsFocusedContent(mFrame
->GetContent()))
324 mFrame
->SetFocus(true, false);
327 nsTextControlFrame
*mFrame
;
329 EnsureSetFocus
makeSureSetFocusHappens(this);
332 // Make sure we are not being called again until we're finished.
333 // If reentrancy happens, just pretend that we don't have an editor.
334 const EditorInitializerEntryTracker
tracker(*this);
335 NS_ASSERTION(!tracker
.EnteredMoreThanOnce(),
336 "EnsureEditorInitialized has been called while a previous call was in progress");
339 // Create an editor for the frame, if one doesn't already exist
340 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
341 NS_ASSERTION(txtCtrl
, "Content not a text control element");
342 nsresult rv
= txtCtrl
->CreateEditor();
343 NS_ENSURE_SUCCESS(rv
, rv
);
345 // Turn on mUseEditor so that subsequent calls will use the
349 // Set the selection to the beginning of the text field.
350 if (weakFrame
.IsAlive()) {
351 SetSelectionEndPoints(0, 0);
358 nsTextControlFrame::CreateAnonymousContent(nsTArray
<ContentInfo
>& aElements
)
360 NS_ASSERTION(mContent
, "We should have a content!");
362 mState
|= NS_FRAME_INDEPENDENT_SELECTION
;
364 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
365 NS_ASSERTION(txtCtrl
, "Content not a text control element");
367 // Bind the frame to its text control
368 nsresult rv
= txtCtrl
->BindToFrame(this);
369 NS_ENSURE_SUCCESS(rv
, rv
);
371 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
372 NS_ENSURE_TRUE(rootNode
, NS_ERROR_OUT_OF_MEMORY
);
374 if (!aElements
.AppendElement(rootNode
))
375 return NS_ERROR_OUT_OF_MEMORY
;
377 // Do we need a placeholder node?
378 nsAutoString placeholderTxt
;
379 mContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::placeholder
,
381 nsContentUtils::RemoveNewlines(placeholderTxt
);
382 mUsePlaceholder
= !placeholderTxt
.IsEmpty();
384 // Create the placeholder anonymous content if needed.
385 if (mUsePlaceholder
) {
386 nsIContent
* placeholderNode
= txtCtrl
->CreatePlaceholderNode();
387 NS_ENSURE_TRUE(placeholderNode
, NS_ERROR_OUT_OF_MEMORY
);
389 if (!aElements
.AppendElement(placeholderNode
))
390 return NS_ERROR_OUT_OF_MEMORY
;
393 rv
= UpdateValueDisplay(false);
394 NS_ENSURE_SUCCESS(rv
, rv
);
396 // textareas are eagerly initialized
397 bool initEagerly
= !IsSingleLineTextControl();
399 // Also, input elements which have a cached selection should get eager
400 // editor initialization.
401 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
402 NS_ASSERTION(txtCtrl
, "Content not a text control element");
403 initEagerly
= txtCtrl
->HasCachedSelection();
406 nsCOMPtr
<nsIDOMHTMLElement
> element
= do_QueryInterface(txtCtrl
);
408 // so are input text controls with spellcheck=true
409 element
->GetSpellcheck(&initEagerly
);
414 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
415 "Someone forgot a script blocker?");
416 EditorInitializer
* initializer
= (EditorInitializer
*) Properties().Get(TextControlInitializer());
418 initializer
->Revoke();
420 initializer
= new EditorInitializer(this);
421 Properties().Set(TextControlInitializer(),initializer
);
422 if (!nsContentUtils::AddScriptRunner(initializer
)) {
423 initializer
->Revoke(); // paranoia
424 Properties().Delete(TextControlInitializer());
426 return NS_ERROR_OUT_OF_MEMORY
;
434 nsTextControlFrame::AppendAnonymousContentTo(nsBaseContentList
& aElements
,
437 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
438 NS_ASSERTION(txtCtrl
, "Content not a text control element");
440 aElements
.MaybeAppendElement(txtCtrl
->GetRootEditorNode());
441 if (!(aFilter
& nsIContent::eSkipPlaceholderContent
))
442 aElements
.MaybeAppendElement(txtCtrl
->GetPlaceholderNode());
447 nsTextControlFrame::GetPrefWidth(nsRenderingContext
* aRenderingContext
)
450 DISPLAY_PREF_WIDTH(this, result
);
452 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
454 CalcIntrinsicSize(aRenderingContext
, autoSize
, inflation
);
456 return autoSize
.width
;
460 nsTextControlFrame::GetMinWidth(nsRenderingContext
* aRenderingContext
)
462 // Our min width is just our preferred width if we have auto width.
464 DISPLAY_MIN_WIDTH(this, result
);
466 result
= GetPrefWidth(aRenderingContext
);
472 nsTextControlFrame::ComputeAutoSize(nsRenderingContext
*aRenderingContext
,
473 nsSize aCBSize
, nscoord aAvailableWidth
,
474 nsSize aMargin
, nsSize aBorder
,
475 nsSize aPadding
, bool aShrinkWrap
)
477 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
479 nsresult rv
= CalcIntrinsicSize(aRenderingContext
, autoSize
, inflation
);
482 autoSize
.SizeTo(0, 0);
485 // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width
486 else if (GetStylePosition()->mWidth
.GetUnit() == eStyleUnit_Auto
) {
487 nsSize ancestorAutoSize
=
488 nsContainerFrame::ComputeAutoSize(aRenderingContext
,
489 aCBSize
, aAvailableWidth
,
491 aPadding
, aShrinkWrap
);
492 // Disabled when there's inflation; see comment in GetPrefSize.
493 NS_ASSERTION(inflation
!= 1.0f
|| ancestorAutoSize
.width
== autoSize
.width
,
494 "Incorrect size computed by ComputeAutoSize?");
502 nsTextControlFrame::Reflow(nsPresContext
* aPresContext
,
503 nsHTMLReflowMetrics
& aDesiredSize
,
504 const nsHTMLReflowState
& aReflowState
,
505 nsReflowStatus
& aStatus
)
507 DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
508 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
510 // make sure that the form registers itself on the initial/first reflow
511 if (mState
& NS_FRAME_FIRST_REFLOW
) {
512 nsFormControlFrame::RegUnRegAccessKey(this, true);
515 // set values of reflow's out parameters
516 aDesiredSize
.width
= aReflowState
.ComputedWidth() +
517 aReflowState
.mComputedBorderPadding
.LeftRight();
518 aDesiredSize
.height
= NS_CSS_MINMAX(aReflowState
.ComputedHeight(),
519 aReflowState
.mComputedMinHeight
,
520 aReflowState
.mComputedMaxHeight
);
521 nscoord lineHeight
= aDesiredSize
.height
;
522 aDesiredSize
.height
+= aReflowState
.mComputedBorderPadding
.TopBottom();
524 // computation of the ascent wrt the input height
525 float inflation
= nsLayoutUtils::FontSizeInflationFor(this);
526 if (!IsSingleLineTextControl()) {
527 lineHeight
= nsHTMLReflowState::CalcLineHeight(GetStyleContext(),
528 NS_AUTOHEIGHT
, inflation
);
530 nsRefPtr
<nsFontMetrics
> fontMet
;
531 nsresult rv
= nsLayoutUtils::GetFontMetricsForFrame(this,
532 getter_AddRefs(fontMet
),
534 NS_ENSURE_SUCCESS(rv
, rv
);
535 // now adjust for our borders and padding
536 aDesiredSize
.ascent
=
537 nsLayoutUtils::GetCenteredFontBaseline(fontMet
, lineHeight
)
538 + aReflowState
.mComputedBorderPadding
.top
;
541 aDesiredSize
.SetOverflowAreasToDesiredBounds();
542 // perform reflow on all kids
543 nsIFrame
* kid
= mFrames
.FirstChild();
545 ReflowTextControlChild(kid
, aPresContext
, aReflowState
, aStatus
, aDesiredSize
);
546 kid
= kid
->GetNextSibling();
548 // take into account css properties that affect overflow handling
549 FinishAndStoreOverflow(&aDesiredSize
);
551 aStatus
= NS_FRAME_COMPLETE
;
552 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
557 nsTextControlFrame::ReflowTextControlChild(nsIFrame
* aKid
,
558 nsPresContext
* aPresContext
,
559 const nsHTMLReflowState
& aReflowState
,
560 nsReflowStatus
& aStatus
,
561 nsHTMLReflowMetrics
& aParentDesiredSize
)
563 // compute available size and frame offsets for child
564 nsSize
availSize(aReflowState
.ComputedWidth(),
565 aReflowState
.ComputedHeight());
566 availSize
.width
= NS_MAX(availSize
.width
, 0);
567 availSize
.height
= NS_MAX(availSize
.height
, 0);
569 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
,
572 // Set computed width and computed height for the child
573 nscoord width
= availSize
.width
;
574 width
-= kidReflowState
.mComputedMargin
.LeftRight() +
575 kidReflowState
.mComputedBorderPadding
.LeftRight();
576 width
= NS_MAX(width
, 0);
577 kidReflowState
.SetComputedWidth(width
);
579 nscoord height
= availSize
.height
;
580 height
-= kidReflowState
.mComputedMargin
.TopBottom() +
581 kidReflowState
.mComputedBorderPadding
.TopBottom();
582 height
= NS_MAX(height
, 0);
583 kidReflowState
.SetComputedHeight(height
);
585 // compute the offsets
586 nscoord xOffset
= aReflowState
.mComputedBorderPadding
.left
587 + kidReflowState
.mComputedMargin
.left
;
588 nscoord yOffset
= aReflowState
.mComputedBorderPadding
.top
589 + kidReflowState
.mComputedMargin
.top
;
592 nsHTMLReflowMetrics desiredSize
;
593 ReflowChild(aKid
, aPresContext
, desiredSize
, kidReflowState
,
594 xOffset
, yOffset
, 0, aStatus
);
597 FinishReflowChild(aKid
, aPresContext
, &kidReflowState
,
598 desiredSize
, xOffset
, yOffset
, 0);
600 // consider the overflow
601 aParentDesiredSize
.mOverflowAreas
.UnionWith(desiredSize
.mOverflowAreas
);
605 nsTextControlFrame::GetMinSize(nsBoxLayoutState
& aState
)
607 // XXXbz why? Why not the nsBoxFrame sizes?
608 return nsBox::GetMinSize(aState
);
612 nsTextControlFrame::IsCollapsed()
614 // We're never collapsed in the box sense.
619 nsTextControlFrame::IsLeaf() const
625 nsTextControlFrame::ScrollOnFocusEvent::Run()
628 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(mFrame
->GetContent());
629 NS_ASSERTION(txtCtrl
, "Content not a text control element");
630 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
632 mFrame
->mScrollEvent
.Forget();
633 selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
634 nsISelectionController::SELECTION_FOCUS_REGION
,
635 nsISelectionController::SCROLL_SYNCHRONOUS
);
641 //IMPLEMENTING NS_IFORMCONTROLFRAME
642 void nsTextControlFrame::SetFocus(bool aOn
, bool aRepaint
)
644 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
645 NS_ASSERTION(txtCtrl
, "Content not a text control element");
647 // Revoke the previous scroll event if one exists
648 mScrollEvent
.Revoke();
654 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
658 nsCOMPtr
<nsISelection
> ourSel
;
659 selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
660 getter_AddRefs(ourSel
));
663 nsIPresShell
* presShell
= PresContext()->GetPresShell();
664 nsRefPtr
<nsCaret
> caret
= presShell
->GetCaret();
667 // Scroll the current selection into view
668 nsISelection
*caretSelection
= caret
->GetCaretDOMSelection();
669 const bool isFocusedRightNow
= ourSel
== caretSelection
;
670 if (!isFocusedRightNow
) {
671 // Don't scroll the current selection if we've been focused using the mouse.
672 PRUint32 lastFocusMethod
= 0;
673 nsIDocument
* doc
= GetContent()->GetCurrentDoc();
675 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
677 fm
->GetLastFocusMethod(doc
->GetWindow(), &lastFocusMethod
);
680 if (!(lastFocusMethod
& nsIFocusManager::FLAG_BYMOUSE
)) {
681 nsRefPtr
<ScrollOnFocusEvent
> event
= new ScrollOnFocusEvent(this);
682 nsresult rv
= NS_DispatchToCurrentThread(event
);
683 if (NS_SUCCEEDED(rv
)) {
684 mScrollEvent
= event
;
689 // tell the caret to use our selection
690 caret
->SetCaretDOMSelection(ourSel
);
692 // mutual-exclusion: the selection is either controlled by the
693 // document or by the text input/area. Clear any selection in the
694 // document since the focus is now on our independent selection.
696 nsCOMPtr
<nsISelectionController
> selcon
= do_QueryInterface(presShell
);
697 nsCOMPtr
<nsISelection
> docSel
;
698 selcon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
699 getter_AddRefs(docSel
));
702 bool isCollapsed
= false;
703 docSel
->GetIsCollapsed(&isCollapsed
);
705 docSel
->RemoveAllRanges();
708 nsresult
nsTextControlFrame::SetFormProperty(nsIAtom
* aName
, const nsAString
& aValue
)
710 if (!mIsProcessing
)//some kind of lock.
712 mIsProcessing
= true;
713 if (nsGkAtoms::select
== aName
)
715 // Select all the text.
717 // XXX: This is lame, we can't call editor's SelectAll method
718 // because that triggers AutoCopies in unix builds.
719 // Instead, we have to call our own homegrown version
720 // of select all which merely builds a range that selects
721 // all of the content and adds that to the selection.
723 nsWeakFrame weakThis
= this;
724 SelectAllOrCollapseToEndOfText(true); // NOTE: can destroy the world
725 if (!weakThis
.IsAlive()) {
729 mIsProcessing
= false;
735 nsTextControlFrame::GetFormProperty(nsIAtom
* aName
, nsAString
& aValue
) const
737 NS_ASSERTION(nsGkAtoms::value
!= aName
,
738 "Should get the value from the content node instead");
745 nsTextControlFrame::GetEditor(nsIEditor
**aEditor
)
747 NS_ENSURE_ARG_POINTER(aEditor
);
749 nsresult rv
= EnsureEditorInitialized();
750 NS_ENSURE_SUCCESS(rv
, rv
);
752 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
753 NS_ASSERTION(txtCtrl
, "Content not a text control element");
754 *aEditor
= txtCtrl
->GetTextEditor();
755 NS_IF_ADDREF(*aEditor
);
760 nsTextControlFrame::GetTextLength(PRInt32
* aTextLength
)
762 NS_ENSURE_ARG_POINTER(aTextLength
);
764 nsAutoString textContents
;
765 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
766 NS_ASSERTION(txtCtrl
, "Content not a text control element");
767 txtCtrl
->GetTextEditorValue(textContents
, false); // this is expensive!
768 *aTextLength
= textContents
.Length();
773 nsTextControlFrame::SetSelectionInternal(nsIDOMNode
*aStartNode
,
774 PRInt32 aStartOffset
,
775 nsIDOMNode
*aEndNode
,
777 nsITextControlFrame::SelectionDirection aDirection
)
779 // Create a new range to represent the new selection.
780 // Note that we use a new range to avoid having to do
781 // isIncreasing checks to avoid possible errors.
783 nsRefPtr
<nsRange
> range
= new nsRange();
784 nsresult rv
= range
->SetStart(aStartNode
, aStartOffset
);
785 NS_ENSURE_SUCCESS(rv
, rv
);
787 rv
= range
->SetEnd(aEndNode
, aEndOffset
);
788 NS_ENSURE_SUCCESS(rv
, rv
);
790 // Get the selection, clear it and add the new range to it!
791 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
792 NS_ASSERTION(txtCtrl
, "Content not a text control element");
793 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
794 NS_ENSURE_TRUE(selCon
, NS_ERROR_FAILURE
);
796 nsCOMPtr
<nsISelection
> selection
;
797 selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
798 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
800 nsCOMPtr
<nsISelectionPrivate
> selPriv
= do_QueryInterface(selection
, &rv
);
801 NS_ENSURE_SUCCESS(rv
, rv
);
803 nsDirection direction
;
804 if (aDirection
== eNone
) {
805 // Preserve the direction
806 direction
= selPriv
->GetSelectionDirection();
808 direction
= (aDirection
== eBackward
) ? eDirPrevious
: eDirNext
;
811 rv
= selection
->RemoveAllRanges();
812 NS_ENSURE_SUCCESS(rv
, rv
);
814 rv
= selection
->AddRange(range
); // NOTE: can destroy the world
815 NS_ENSURE_SUCCESS(rv
, rv
);
817 selPriv
->SetSelectionDirection(direction
);
822 nsTextControlFrame::ScrollSelectionIntoView()
824 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
825 NS_ASSERTION(txtCtrl
, "Content not a text control element");
826 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
828 // Scroll the selection into view (see bug 231389).
829 return selCon
->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL
,
830 nsISelectionController::SELECTION_FOCUS_REGION
,
831 nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY
);
834 return NS_ERROR_FAILURE
;
837 mozilla::dom::Element
*
838 nsTextControlFrame::GetRootNodeAndInitializeEditor()
840 nsCOMPtr
<nsIDOMElement
> root
;
841 GetRootNodeAndInitializeEditor(getter_AddRefs(root
));
842 nsCOMPtr
<mozilla::dom::Element
> rootElem
= do_QueryInterface(root
);
847 nsTextControlFrame::GetRootNodeAndInitializeEditor(nsIDOMElement
**aRootElement
)
849 NS_ENSURE_ARG_POINTER(aRootElement
);
851 nsCOMPtr
<nsIEditor
> editor
;
852 GetEditor(getter_AddRefs(editor
));
856 return editor
->GetRootElement(aRootElement
);
860 nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect
)
862 nsCOMPtr
<nsIDOMElement
> rootElement
;
863 nsresult rv
= GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement
));
864 NS_ENSURE_SUCCESS(rv
, rv
);
866 nsCOMPtr
<nsIContent
> rootContent
= do_QueryInterface(rootElement
);
867 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
869 NS_ENSURE_TRUE(rootNode
&& rootContent
, NS_ERROR_FAILURE
);
871 PRInt32 numChildren
= rootContent
->GetChildCount();
873 if (numChildren
> 0) {
874 // We never want to place the selection after the last
875 // br under the root node!
876 nsIContent
*child
= rootContent
->GetChildAt(numChildren
- 1);
878 if (child
->Tag() == nsGkAtoms::br
)
881 if (!aSelect
&& numChildren
) {
882 child
= rootContent
->GetChildAt(numChildren
- 1);
883 if (child
&& child
->IsNodeOfType(nsINode::eTEXT
)) {
884 rootNode
= do_QueryInterface(child
);
885 const nsTextFragment
* fragment
= child
->GetText();
886 numChildren
= fragment
? fragment
->GetLength() : 0;
891 rv
= SetSelectionInternal(rootNode
, aSelect
? 0 : numChildren
,
892 rootNode
, numChildren
);
893 NS_ENSURE_SUCCESS(rv
, rv
);
895 return ScrollSelectionIntoView();
899 nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart
, PRInt32 aSelEnd
,
900 nsITextControlFrame::SelectionDirection aDirection
)
902 NS_ASSERTION(aSelStart
<= aSelEnd
, "Invalid selection offsets!");
904 if (aSelStart
> aSelEnd
)
905 return NS_ERROR_FAILURE
;
907 nsCOMPtr
<nsIDOMNode
> startNode
, endNode
;
908 PRInt32 startOffset
, endOffset
;
910 // Calculate the selection start point.
912 nsresult rv
= OffsetToDOMPoint(aSelStart
, getter_AddRefs(startNode
), &startOffset
);
914 NS_ENSURE_SUCCESS(rv
, rv
);
916 if (aSelStart
== aSelEnd
) {
917 // Collapsed selection, so start and end are the same!
919 endOffset
= startOffset
;
922 // Selection isn't collapsed so we have to calculate
923 // the end point too.
925 rv
= OffsetToDOMPoint(aSelEnd
, getter_AddRefs(endNode
), &endOffset
);
927 NS_ENSURE_SUCCESS(rv
, rv
);
930 return SetSelectionInternal(startNode
, startOffset
, endNode
, endOffset
, aDirection
);
934 nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart
, PRInt32 aSelEnd
,
935 nsITextControlFrame::SelectionDirection aDirection
)
937 nsresult rv
= EnsureEditorInitialized();
938 NS_ENSURE_SUCCESS(rv
, rv
);
940 if (aSelStart
> aSelEnd
) {
941 // Simulate what we'd see SetSelectionStart() was called, followed
942 // by a SetSelectionEnd().
947 return SetSelectionEndPoints(aSelStart
, aSelEnd
, aDirection
);
952 nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart
)
954 nsresult rv
= EnsureEditorInitialized();
955 NS_ENSURE_SUCCESS(rv
, rv
);
957 PRInt32 selStart
= 0, selEnd
= 0;
959 rv
= GetSelectionRange(&selStart
, &selEnd
);
960 NS_ENSURE_SUCCESS(rv
, rv
);
962 if (aSelectionStart
> selEnd
) {
963 // Collapse to the new start point.
964 selEnd
= aSelectionStart
;
967 selStart
= aSelectionStart
;
969 return SetSelectionEndPoints(selStart
, selEnd
);
973 nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd
)
975 nsresult rv
= EnsureEditorInitialized();
976 NS_ENSURE_SUCCESS(rv
, rv
);
978 PRInt32 selStart
= 0, selEnd
= 0;
980 rv
= GetSelectionRange(&selStart
, &selEnd
);
981 NS_ENSURE_SUCCESS(rv
, rv
);
983 if (aSelectionEnd
< selStart
) {
984 // Collapse to the new end point.
985 selStart
= aSelectionEnd
;
988 selEnd
= aSelectionEnd
;
990 return SetSelectionEndPoints(selStart
, selEnd
);
994 nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset
,
995 nsIDOMNode
** aResult
,
998 NS_ENSURE_ARG_POINTER(aResult
&& aPosition
);
1003 nsCOMPtr
<nsIDOMElement
> rootElement
;
1004 nsresult rv
= GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement
));
1005 NS_ENSURE_SUCCESS(rv
, rv
);
1006 nsCOMPtr
<nsIDOMNode
> rootNode(do_QueryInterface(rootElement
));
1008 NS_ENSURE_TRUE(rootNode
, NS_ERROR_FAILURE
);
1010 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
1012 rv
= rootNode
->GetChildNodes(getter_AddRefs(nodeList
));
1013 NS_ENSURE_SUCCESS(rv
, rv
);
1014 NS_ENSURE_TRUE(nodeList
, NS_ERROR_FAILURE
);
1016 PRUint32 length
= 0;
1018 rv
= nodeList
->GetLength(&length
);
1019 NS_ENSURE_SUCCESS(rv
, rv
);
1021 NS_ASSERTION(length
<= 2, "We should have one text node and one mozBR at most");
1023 nsCOMPtr
<nsIDOMNode
> firstNode
;
1024 rv
= nodeList
->Item(0, getter_AddRefs(firstNode
));
1025 NS_ENSURE_SUCCESS(rv
, rv
);
1026 nsCOMPtr
<nsIDOMText
> textNode
= do_QueryInterface(firstNode
);
1028 if (length
== 0 || aOffset
< 0) {
1029 NS_IF_ADDREF(*aResult
= rootNode
);
1031 } else if (textNode
) {
1032 PRUint32 textLength
= 0;
1033 textNode
->GetLength(&textLength
);
1034 if (length
== 2 && PRUint32(aOffset
) == textLength
) {
1035 // If we're at the end of the text node and we have a trailing BR node,
1036 // set the selection on the BR node.
1037 NS_IF_ADDREF(*aResult
= rootNode
);
1040 // Otherwise, set the selection on the textnode itself.
1041 NS_IF_ADDREF(*aResult
= firstNode
);
1042 *aPosition
= NS_MIN(aOffset
, PRInt32(textLength
));
1045 NS_IF_ADDREF(*aResult
= rootNode
);
1053 nsTextControlFrame::GetSelectionRange(PRInt32
* aSelectionStart
,
1054 PRInt32
* aSelectionEnd
,
1055 SelectionDirection
* aDirection
)
1057 // make sure we have an editor
1058 nsresult rv
= EnsureEditorInitialized();
1059 NS_ENSURE_SUCCESS(rv
, rv
);
1061 if (aSelectionStart
) {
1062 *aSelectionStart
= 0;
1064 if (aSelectionEnd
) {
1068 *aDirection
= eNone
;
1071 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1072 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1073 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
1074 NS_ENSURE_TRUE(selCon
, NS_ERROR_FAILURE
);
1075 nsCOMPtr
<nsISelection
> selection
;
1076 rv
= selCon
->GetSelection(nsISelectionController::SELECTION_NORMAL
, getter_AddRefs(selection
));
1077 NS_ENSURE_SUCCESS(rv
, rv
);
1078 NS_ENSURE_TRUE(selection
, NS_ERROR_FAILURE
);
1079 nsCOMPtr
<nsISelectionPrivate
> selPriv
= do_QueryInterface(selection
);
1080 NS_ENSURE_TRUE(selPriv
, NS_ERROR_FAILURE
);
1081 nsRefPtr
<nsFrameSelection
> frameSel
;
1082 rv
= selPriv
->GetFrameSelection(getter_AddRefs(frameSel
));
1083 NS_ENSURE_SUCCESS(rv
, rv
);
1084 NS_ENSURE_TRUE(frameSel
, NS_ERROR_FAILURE
);
1085 nsRefPtr
<Selection
> typedSel
=
1086 frameSel
->GetSelection(nsISelectionController::SELECTION_NORMAL
);
1087 NS_ENSURE_TRUE(typedSel
, NS_ERROR_FAILURE
);
1090 nsDirection direction
= typedSel
->GetSelectionDirection();
1091 if (direction
== eDirNext
) {
1092 *aDirection
= eForward
;
1093 } else if (direction
== eDirPrevious
) {
1094 *aDirection
= eBackward
;
1096 NS_NOTREACHED("Invalid nsDirection enum value");
1100 if (!aSelectionStart
|| !aSelectionEnd
) {
1104 nsContentUtils::GetSelectionInTextControl(typedSel
,
1105 GetRootNodeAndInitializeEditor(), *aSelectionStart
, *aSelectionEnd
);
1110 /////END INTERFACE IMPLEMENTATIONS
1114 nsTextControlFrame::AttributeChanged(PRInt32 aNameSpaceID
,
1115 nsIAtom
* aAttribute
,
1118 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1119 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1120 nsISelectionController
* selCon
= txtCtrl
->GetSelectionController();
1121 const bool needEditor
= nsGkAtoms::maxlength
== aAttribute
||
1122 nsGkAtoms::readonly
== aAttribute
||
1123 nsGkAtoms::disabled
== aAttribute
||
1124 nsGkAtoms::spellcheck
== aAttribute
;
1125 nsCOMPtr
<nsIEditor
> editor
;
1127 GetEditor(getter_AddRefs(editor
));
1129 if ((needEditor
&& !editor
) || !selCon
)
1130 return nsContainerFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
1132 nsresult rv
= NS_OK
;
1134 if (nsGkAtoms::maxlength
== aAttribute
)
1137 bool maxDefined
= GetMaxLength(&maxLength
);
1139 nsCOMPtr
<nsIPlaintextEditor
> textEditor
= do_QueryInterface(editor
);
1143 { // set the maxLength attribute
1144 textEditor
->SetMaxTextLength(maxLength
);
1145 // if maxLength>docLength, we need to truncate the doc content
1147 else { // unset the maxLength attribute
1148 textEditor
->SetMaxTextLength(-1);
1151 rv
= NS_OK
; // don't propagate the error
1153 else if (nsGkAtoms::readonly
== aAttribute
)
1156 editor
->GetFlags(&flags
);
1157 if (AttributeExists(nsGkAtoms::readonly
))
1159 flags
|= nsIPlaintextEditor::eEditorReadonlyMask
;
1160 if (nsContentUtils::IsFocusedContent(mContent
))
1161 selCon
->SetCaretEnabled(false);
1165 flags
&= ~(nsIPlaintextEditor::eEditorReadonlyMask
);
1166 if (!(flags
& nsIPlaintextEditor::eEditorDisabledMask
) &&
1167 nsContentUtils::IsFocusedContent(mContent
))
1168 selCon
->SetCaretEnabled(true);
1170 editor
->SetFlags(flags
);
1172 else if (nsGkAtoms::disabled
== aAttribute
)
1175 editor
->GetFlags(&flags
);
1176 if (AttributeExists(nsGkAtoms::disabled
))
1178 flags
|= nsIPlaintextEditor::eEditorDisabledMask
;
1179 selCon
->SetDisplaySelection(nsISelectionController::SELECTION_OFF
);
1180 if (nsContentUtils::IsFocusedContent(mContent
))
1181 selCon
->SetCaretEnabled(false);
1185 flags
&= ~(nsIPlaintextEditor::eEditorDisabledMask
);
1186 selCon
->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN
);
1187 if (nsContentUtils::IsFocusedContent(mContent
)) {
1188 selCon
->SetCaretEnabled(true);
1191 editor
->SetFlags(flags
);
1193 else if (!mUseEditor
&& nsGkAtoms::value
== aAttribute
) {
1194 UpdateValueDisplay(true);
1196 // Allow the base class to handle common attributes supported
1197 // by all form elements...
1199 rv
= nsContainerFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
1207 nsTextControlFrame::GetText(nsString
& aText
)
1209 nsresult rv
= NS_OK
;
1210 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1211 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1212 if (IsSingleLineTextControl()) {
1213 // There will be no line breaks so we can ignore the wrap property.
1214 txtCtrl
->GetTextEditorValue(aText
, true);
1216 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textArea
= do_QueryInterface(mContent
);
1218 rv
= textArea
->GetValue(aText
);
1226 nsTextControlFrame::GetPhonetic(nsAString
& aPhonetic
)
1228 aPhonetic
.Truncate(0);
1230 nsCOMPtr
<nsIEditor
> editor
;
1231 nsresult rv
= GetEditor(getter_AddRefs(editor
));
1232 NS_ENSURE_SUCCESS(rv
, rv
);
1234 nsCOMPtr
<nsIEditorIMESupport
> imeSupport
= do_QueryInterface(editor
);
1236 nsCOMPtr
<nsIPhonetic
> phonetic
= do_QueryInterface(imeSupport
);
1238 phonetic
->GetPhonetic(aPhonetic
);
1243 ///END NSIFRAME OVERLOADS
1244 /////BEGIN PROTECTED METHODS
1247 nsTextControlFrame::GetMaxLength(PRInt32
* aSize
)
1251 nsGenericHTMLElement
*content
= nsGenericHTMLElement::FromContent(mContent
);
1253 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::maxlength
);
1254 if (attr
&& attr
->Type() == nsAttrValue::eInteger
) {
1255 *aSize
= attr
->GetIntegerValue();
1263 // END IMPLEMENTING NS_IFORMCONTROLFRAME
1266 nsTextControlFrame::SetInitialChildList(ChildListID aListID
,
1267 nsFrameList
& aChildList
)
1269 nsresult rv
= nsContainerFrame::SetInitialChildList(aListID
, aChildList
);
1271 nsIFrame
* first
= GetFirstPrincipalChild();
1273 // Mark the scroll frame as being a reflow root. This will allow
1274 // incremental reflows to be initiated at the scroll frame, rather
1275 // than descending from the root frame of the frame hierarchy.
1277 first
->AddStateBits(NS_FRAME_REFLOW_ROOT
);
1279 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1280 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1281 txtCtrl
->InitializeKeyboardEventListeners();
1283 nsPoint
* contentScrollPos
= static_cast<nsPoint
*>
1284 (Properties().Get(ContentScrollPos()));
1285 if (contentScrollPos
) {
1286 // If we have a scroll pos stored to be passed to our anonymous
1288 nsIStatefulFrame
* statefulFrame
= do_QueryFrame(first
);
1289 NS_ASSERTION(statefulFrame
, "unexpected type of frame for the anonymous div");
1290 nsPresState fakePresState
;
1291 fakePresState
.SetScrollState(*contentScrollPos
);
1292 statefulFrame
->RestoreState(&fakePresState
);
1293 Properties().Remove(ContentScrollPos());
1294 delete contentScrollPos
;
1301 nsTextControlFrame::IsScrollable() const
1303 return !IsSingleLineTextControl();
1307 nsTextControlFrame::SetValueChanged(bool aValueChanged
)
1309 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1310 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1312 if (mUsePlaceholder
) {
1314 GetTextLength(&textLength
);
1316 nsWeakFrame
weakFrame(this);
1317 txtCtrl
->SetPlaceholderClass(!textLength
, true);
1318 if (!weakFrame
.IsAlive()) {
1323 txtCtrl
->SetValueChanged(aValueChanged
);
1328 nsTextControlFrame::UpdateValueDisplay(bool aNotify
,
1329 bool aBeforeEditorInit
,
1330 const nsAString
*aValue
)
1332 if (!IsSingleLineTextControl()) // textareas don't use this
1335 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1336 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1337 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1339 NS_PRECONDITION(rootNode
, "Must have a div content\n");
1340 NS_PRECONDITION(!mUseEditor
,
1341 "Do not call this after editor has been initialized");
1342 NS_ASSERTION(!mUsePlaceholder
|| txtCtrl
->GetPlaceholderNode(),
1343 "A placeholder div must exist");
1345 nsIContent
*textContent
= rootNode
->GetChildAt(0);
1347 // Set up a textnode with our value
1348 nsCOMPtr
<nsIContent
> textNode
;
1349 nsresult rv
= NS_NewTextNode(getter_AddRefs(textNode
),
1350 mContent
->NodeInfo()->NodeInfoManager());
1351 NS_ENSURE_SUCCESS(rv
, rv
);
1353 NS_ASSERTION(textNode
, "Must have textcontent!\n");
1355 rootNode
->AppendChildTo(textNode
, aNotify
);
1356 textContent
= textNode
;
1359 NS_ENSURE_TRUE(textContent
, NS_ERROR_UNEXPECTED
);
1361 // Get the current value of the textfield from the content.
1366 txtCtrl
->GetTextEditorValue(value
, true);
1369 // Update the display of the placeholder value if needed.
1370 // We don't need to do this if we're about to initialize the
1371 // editor, since EnsureEditorInitialized takes care of this.
1372 if (mUsePlaceholder
&& !aBeforeEditorInit
)
1374 nsWeakFrame
weakFrame(this);
1375 txtCtrl
->SetPlaceholderClass(value
.IsEmpty(), aNotify
);
1376 NS_ENSURE_STATE(weakFrame
.IsAlive());
1379 if (aBeforeEditorInit
&& value
.IsEmpty()) {
1380 rootNode
->RemoveChildAt(0, true);
1384 if (!value
.IsEmpty() && IsPasswordTextControl()) {
1385 nsTextEditRules::FillBufWithPWChars(&value
, value
.Length());
1387 return textContent
->SetText(value
, aNotify
);
1391 nsTextControlFrame::GetOwnedSelectionController(nsISelectionController
** aSelCon
)
1393 NS_ENSURE_ARG_POINTER(aSelCon
);
1395 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1396 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1398 *aSelCon
= txtCtrl
->GetSelectionController();
1399 NS_IF_ADDREF(*aSelCon
);
1405 nsTextControlFrame::GetOwnedFrameSelection()
1407 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1408 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1410 return txtCtrl
->GetConstFrameSelection();
1414 nsTextControlFrame::SaveState(nsIStatefulFrame::SpecialStateID aStateID
, nsPresState
** aState
)
1416 NS_ENSURE_ARG_POINTER(aState
);
1420 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1421 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1423 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1425 // Query the nsIStatefulFrame from the HTMLScrollFrame
1426 nsIStatefulFrame
* scrollStateFrame
= do_QueryFrame(rootNode
->GetPrimaryFrame());
1427 if (scrollStateFrame
) {
1428 return scrollStateFrame
->SaveState(aStateID
, aState
);
1436 nsTextControlFrame::RestoreState(nsPresState
* aState
)
1438 NS_ENSURE_ARG_POINTER(aState
);
1440 nsCOMPtr
<nsITextControlElement
> txtCtrl
= do_QueryInterface(GetContent());
1441 NS_ASSERTION(txtCtrl
, "Content not a text control element");
1443 nsIContent
* rootNode
= txtCtrl
->GetRootEditorNode();
1445 // Query the nsIStatefulFrame from the HTMLScrollFrame
1446 nsIStatefulFrame
* scrollStateFrame
= do_QueryFrame(rootNode
->GetPrimaryFrame());
1447 if (scrollStateFrame
) {
1448 return scrollStateFrame
->RestoreState(aState
);
1452 // Most likely, we don't have our anonymous content constructed yet, which
1453 // would cause us to end up here. In this case, we'll just store the scroll
1454 // pos ourselves, and forward it to the scroll frame later when it's created.
1455 Properties().Set(ContentScrollPos(), new nsPoint(aState
->GetScrollState()));
1460 nsTextControlFrame::PeekOffset(nsPeekOffsetStruct
*aPos
)
1462 return NS_ERROR_FAILURE
;