layout/forms/nsTextControlFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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"
     8 #include "nsCOMPtr.h"
     9 #include "nsTextControlFrame.h"
    10 #include "nsIPlaintextEditor.h"
    11 #include "nsCaret.h"
    12 #include "nsGenericHTMLElement.h"
    13 #include "nsIEditor.h"
    14 #include "nsIEditorIMESupport.h"
    15 #include "nsIPhonetic.h"
    16 #include "nsTextFragment.h"
    17 #include "nsIDOMHTMLTextAreaElement.h"
    18 #include "nsNameSpaceManager.h"
    19 #include "nsINodeInfo.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"
    31 #include <algorithm>
    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;
    54 nsIFrame*
    55 NS_NewTextControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    56 {
    57   return new (aPresShell) nsTextControlFrame(aPresShell, aContext);
    58 }
    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)
    69 #ifdef ACCESSIBILITY
    70 a11y::AccType
    71 nsTextControlFrame::AccessibleType()
    72 {
    73   return a11y::eHTMLTextFieldType;
    74 }
    75 #endif
    77 #ifdef DEBUG
    78 class EditorInitializerEntryTracker {
    79 public:
    80   explicit EditorInitializerEntryTracker(nsTextControlFrame &frame)
    81     : mFrame(frame)
    82     , mFirstEntry(false)
    83   {
    84     if (!mFrame.mInEditorInitialization) {
    85       mFrame.mInEditorInitialization = true;
    86       mFirstEntry = true;
    87     }
    88   }
    89   ~EditorInitializerEntryTracker()
    90   {
    91     if (mFirstEntry) {
    92       mFrame.mInEditorInitialization = false;
    93     }
    94   }
    95   bool EnteredMoreThanOnce() const { return !mFirstEntry; }
    96 private:
    97   nsTextControlFrame &mFrame;
    98   bool mFirstEntry;
    99 };
   100 #endif
   102 nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext)
   103   : nsContainerFrame(aContext)
   104   , mEditorHasBeenInitialized(false)
   105   , mIsProcessing(false)
   106 #ifdef DEBUG
   107   , mInEditorInitialization(false)
   108 #endif
   109 {
   110 }
   112 nsTextControlFrame::~nsTextControlFrame()
   113 {
   114 }
   116 void
   117 nsTextControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
   118 {
   119   mScrollEvent.Revoke();
   121   EditorInitializer* initializer = (EditorInitializer*) Properties().Get(TextControlInitializer());
   122   if (initializer) {
   123     initializer->Revoke();
   124     Properties().Delete(TextControlInitializer());
   125   }
   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);
   136 }
   138 nsIAtom*
   139 nsTextControlFrame::GetType() const 
   140 { 
   141   return nsGkAtoms::textInputFrame;
   142 }
   144 nsresult
   145 nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext* aRenderingContext,
   146                                       nsSize&             aIntrinsicSize,
   147                                       float               aFontSizeInflation)
   148 {
   149   // Get leading and the Average/MaxAdvance char width 
   150   nscoord lineHeight  = 0;
   151   nscoord charWidth   = 0;
   152   nscoord charMaxAdvance  = 0;
   154   nsRefPtr<nsFontMetrics> fontMet;
   155   nsresult rv =
   156     nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet),
   157                                           aFontSizeInflation);
   158   NS_ENSURE_SUCCESS(rv, rv);
   159   aRenderingContext->SetFont(fontMet);
   161   lineHeight =
   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.width = 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;
   182     } else {
   183       internalPadding += t - rest;
   184     }
   185     // Now add the extra padding on (so that small input sizes work well)
   186     aIntrinsicSize.width += internalPadding;
   187   } else {
   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.width += 1;
   192     }
   193   }
   195   // Increment width with cols * letter-spacing.
   196   {
   197     const nsStyleCoord& lsCoord = StyleText()->mLetterSpacing;
   198     if (eStyleUnit_Coord == lsCoord.GetUnit()) {
   199       nscoord letterSpacing = lsCoord.GetCoordValue();
   200       if (letterSpacing != 0) {
   201         aIntrinsicSize.width += cols * letterSpacing;
   202       }
   203     }
   204   }
   206   // Set the height equal to total number of rows (times the height of each
   207   // line, of course)
   208   aIntrinsicSize.height = lineHeight * GetRows();
   210   // Add in the size of the scrollbars for textarea
   211   if (IsTextArea()) {
   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  += scrollbarSizes.LeftRight();
   223       aIntrinsicSize.height += scrollbarSizes.TopBottom();;
   224     }
   225   }
   227   return NS_OK;
   228 }
   230 nsresult
   231 nsTextControlFrame::EnsureEditorInitialized()
   232 {
   233   // This method initializes our editor, if needed.
   235   // This code used to be called from CreateAnonymousContent(), but
   236   // when the editor set the initial string, it would trigger a
   237   // PresShell listener which called FlushPendingNotifications()
   238   // during frame construction. This was causing other form controls
   239   // to display wrong values.  Additionally, calling this every time
   240   // a text frame control is instantiated means that we're effectively
   241   // instantiating the editor for all text fields, even if they
   242   // never get used.  So, now this method is being called lazily only
   243   // when we actually need an editor.
   245   if (mEditorHasBeenInitialized)
   246     return NS_OK;
   248   nsIDocument* doc = mContent->GetCurrentDoc();
   249   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   251   nsWeakFrame weakFrame(this);
   253   // Flush out content on our document.  Have to do this, because script
   254   // blockers don't prevent the sink flushing out content and notifying in the
   255   // process, which can destroy frames.
   256   doc->FlushPendingNotifications(Flush_ContentAndNotify);
   257   NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE);
   259   // Make sure that editor init doesn't do things that would kill us off
   260   // (especially off the script blockers it'll create for its DOM mutations).
   261   {
   262     nsAutoScriptBlocker scriptBlocker;
   264     // Time to mess with our security context... See comments in GetValue()
   265     // for why this is needed.
   266     mozilla::dom::AutoNoJSAPI nojsapi;
   268     // Make sure that we try to focus the content even if the method fails
   269     class EnsureSetFocus {
   270     public:
   271       explicit EnsureSetFocus(nsTextControlFrame* aFrame)
   272         : mFrame(aFrame) {}
   273       ~EnsureSetFocus() {
   274         if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
   275           mFrame->SetFocus(true, false);
   276       }
   277     private:
   278       nsTextControlFrame *mFrame;
   279     };
   280     EnsureSetFocus makeSureSetFocusHappens(this);
   282 #ifdef DEBUG
   283     // Make sure we are not being called again until we're finished.
   284     // If reentrancy happens, just pretend that we don't have an editor.
   285     const EditorInitializerEntryTracker tracker(*this);
   286     NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
   287                  "EnsureEditorInitialized has been called while a previous call was in progress");
   288 #endif
   290     // Create an editor for the frame, if one doesn't already exist
   291     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   292     NS_ASSERTION(txtCtrl, "Content not a text control element");
   293     nsresult rv = txtCtrl->CreateEditor();
   294     NS_ENSURE_SUCCESS(rv, rv);
   295     NS_ENSURE_STATE(weakFrame.IsAlive());
   297     // Set mEditorHasBeenInitialized so that subsequent calls will use the
   298     // editor.
   299     mEditorHasBeenInitialized = true;
   301     // Set the selection to the beginning of the text field.
   302     if (weakFrame.IsAlive()) {
   303       SetSelectionEndPoints(0, 0);
   304     }
   305   }
   306   NS_ENSURE_STATE(weakFrame.IsAlive());
   307   return NS_OK;
   308 }
   310 nsresult
   311 nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
   312 {
   313   NS_ASSERTION(mContent, "We should have a content!");
   315   mState |= NS_FRAME_INDEPENDENT_SELECTION;
   317   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   318   NS_ASSERTION(txtCtrl, "Content not a text control element");
   320   // Bind the frame to its text control
   321   nsresult rv = txtCtrl->BindToFrame(this);
   322   NS_ENSURE_SUCCESS(rv, rv);
   324   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
   325   NS_ENSURE_TRUE(rootNode, NS_ERROR_OUT_OF_MEMORY);
   327   if (!aElements.AppendElement(rootNode))
   328     return NS_ERROR_OUT_OF_MEMORY;
   330   // Do we need a placeholder node?
   331   nsAutoString placeholderTxt;
   332   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder,
   333                     placeholderTxt);
   334   nsContentUtils::RemoveNewlines(placeholderTxt);
   335   mUsePlaceholder = !placeholderTxt.IsEmpty();
   337   // Create the placeholder anonymous content if needed.
   338   if (mUsePlaceholder) {
   339     nsIContent* placeholderNode = txtCtrl->CreatePlaceholderNode();
   340     NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY);
   342     // Associate ::-moz-placeholder pseudo-element with the placeholder node.
   343     nsCSSPseudoElements::Type pseudoType =
   344       nsCSSPseudoElements::ePseudo_mozPlaceholder;
   346     nsRefPtr<nsStyleContext> placeholderStyleContext =
   347       PresContext()->StyleSet()->ResolvePseudoElementStyle(
   348           mContent->AsElement(), pseudoType, StyleContext(),
   349           placeholderNode->AsElement());
   351     if (!aElements.AppendElement(ContentInfo(placeholderNode,
   352                                  placeholderStyleContext))) {
   353       return NS_ERROR_OUT_OF_MEMORY;
   354     }
   355   }
   357   rv = UpdateValueDisplay(false);
   358   NS_ENSURE_SUCCESS(rv, rv);
   360   // textareas are eagerly initialized
   361   bool initEagerly = !IsSingleLineTextControl();
   362   if (!initEagerly) {
   363     // Also, input elements which have a cached selection should get eager
   364     // editor initialization.
   365     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   366     NS_ASSERTION(txtCtrl, "Content not a text control element");
   367     initEagerly = txtCtrl->HasCachedSelection();
   368   }
   369   if (!initEagerly) {
   370     nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(txtCtrl);
   371     if (element) {
   372       // so are input text controls with spellcheck=true
   373       element->GetSpellcheck(&initEagerly);
   374     }
   375   }
   377   if (initEagerly) {
   378     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
   379                  "Someone forgot a script blocker?");
   380     EditorInitializer* initializer = (EditorInitializer*) Properties().Get(TextControlInitializer());
   381     if (initializer) {
   382       initializer->Revoke();
   383     }
   384     initializer = new EditorInitializer(this);
   385     Properties().Set(TextControlInitializer(),initializer);
   386     if (!nsContentUtils::AddScriptRunner(initializer)) {
   387       initializer->Revoke(); // paranoia
   388       Properties().Delete(TextControlInitializer());
   389       delete initializer;
   390       return NS_ERROR_OUT_OF_MEMORY;
   391     }
   392   }
   394   return NS_OK;
   395 }
   397 void
   398 nsTextControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
   399                                              uint32_t aFilter)
   400 {
   401   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   402   NS_ASSERTION(txtCtrl, "Content not a text control element");
   404   aElements.MaybeAppendElement(txtCtrl->GetRootEditorNode());
   405   if (!(aFilter & nsIContent::eSkipPlaceholderContent))
   406     aElements.MaybeAppendElement(txtCtrl->GetPlaceholderNode());
   408 }
   410 nscoord
   411 nsTextControlFrame::GetPrefWidth(nsRenderingContext* aRenderingContext)
   412 {
   413     DebugOnly<nscoord> result = 0;
   414     DISPLAY_PREF_WIDTH(this, result);
   416     float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   417     nsSize autoSize;
   418     CalcIntrinsicSize(aRenderingContext, autoSize, inflation);
   420     return autoSize.width; 
   421 }
   423 nscoord
   424 nsTextControlFrame::GetMinWidth(nsRenderingContext* aRenderingContext)
   425 {
   426   // Our min width is just our preferred width if we have auto width.
   427   nscoord result;
   428   DISPLAY_MIN_WIDTH(this, result);
   430   result = GetPrefWidth(aRenderingContext);
   432   return result;
   433 }
   435 nsSize
   436 nsTextControlFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
   437                                     nsSize aCBSize, nscoord aAvailableWidth,
   438                                     nsSize aMargin, nsSize aBorder,
   439                                     nsSize aPadding, bool aShrinkWrap)
   440 {
   441   float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   442   nsSize autoSize;
   443   nsresult rv = CalcIntrinsicSize(aRenderingContext, autoSize, inflation);
   444   if (NS_FAILED(rv)) {
   445     // What now?
   446     autoSize.SizeTo(0, 0);
   447   }
   448 #ifdef DEBUG
   449   // Note: Ancestor ComputeAutoSize only computes a width if we're auto-width
   450   else if (StylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
   451     nsSize ancestorAutoSize =
   452       nsContainerFrame::ComputeAutoSize(aRenderingContext,
   453                                         aCBSize, aAvailableWidth,
   454                                         aMargin, aBorder,
   455                                         aPadding, aShrinkWrap);
   456     // Disabled when there's inflation; see comment in GetPrefSize.
   457     NS_ASSERTION(inflation != 1.0f || ancestorAutoSize.width == autoSize.width,
   458                  "Incorrect size computed by ComputeAutoSize?");
   459   }
   460 #endif
   462   return autoSize;
   463 }
   465 nsresult
   466 nsTextControlFrame::Reflow(nsPresContext*   aPresContext,
   467                            nsHTMLReflowMetrics&     aDesiredSize,
   468                            const nsHTMLReflowState& aReflowState,
   469                            nsReflowStatus&          aStatus)
   470 {
   471   DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
   472   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   474   // make sure that the form registers itself on the initial/first reflow
   475   if (mState & NS_FRAME_FIRST_REFLOW) {
   476     nsFormControlFrame::RegUnRegAccessKey(this, true);
   477   }
   479   // set values of reflow's out parameters
   480   aDesiredSize.Width() = aReflowState.ComputedWidth() +
   481                        aReflowState.ComputedPhysicalBorderPadding().LeftRight();
   482   aDesiredSize.Height() = aReflowState.ComputedHeight() +
   483                         aReflowState.ComputedPhysicalBorderPadding().TopBottom();
   485   // computation of the ascent wrt the input height
   486   nscoord lineHeight = aReflowState.ComputedHeight();
   487   float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   488   if (!IsSingleLineTextControl()) {
   489     lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
   490                                                    NS_AUTOHEIGHT, inflation);
   491   }
   492   nsRefPtr<nsFontMetrics> fontMet;
   493   nsresult rv = nsLayoutUtils::GetFontMetricsForFrame(this, 
   494                                                       getter_AddRefs(fontMet), 
   495                                                       inflation);
   496   NS_ENSURE_SUCCESS(rv, rv);
   497   // now adjust for our borders and padding
   498   aDesiredSize.SetTopAscent( 
   499         nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight) 
   500         + aReflowState.ComputedPhysicalBorderPadding().top);
   502   // overflow handling
   503   aDesiredSize.SetOverflowAreasToDesiredBounds();
   504   // perform reflow on all kids
   505   nsIFrame* kid = mFrames.FirstChild();
   506   while (kid) {
   507     ReflowTextControlChild(kid, aPresContext, aReflowState, aStatus, aDesiredSize);
   508     kid = kid->GetNextSibling();
   509   }
   511   // take into account css properties that affect overflow handling
   512   FinishAndStoreOverflow(&aDesiredSize);
   514   aStatus = NS_FRAME_COMPLETE;
   515   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   516   return NS_OK;
   517 }
   519 void
   520 nsTextControlFrame::ReflowTextControlChild(nsIFrame*                aKid,
   521                                            nsPresContext*           aPresContext,
   522                                            const nsHTMLReflowState& aReflowState,
   523                                            nsReflowStatus&          aStatus,
   524                                            nsHTMLReflowMetrics& aParentDesiredSize)
   525 {
   526   // compute available size and frame offsets for child
   527   nsSize availSize(aReflowState.ComputedWidth() +
   528                    aReflowState.ComputedPhysicalPadding().LeftRight(),
   529                    NS_UNCONSTRAINEDSIZE);
   531   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, 
   532                                    aKid, availSize, -1, -1, nsHTMLReflowState::CALLER_WILL_INIT);
   533   // Override padding with our computed padding in case we got it from theming or percentage
   534   kidReflowState.Init(aPresContext, -1, -1, nullptr, &aReflowState.ComputedPhysicalPadding());
   536   // Set computed width and computed height for the child
   537   kidReflowState.SetComputedWidth(aReflowState.ComputedWidth());
   538   kidReflowState.SetComputedHeight(aReflowState.ComputedHeight());
   540   // Offset the frame by the size of the parent's border
   541   nscoord xOffset = aReflowState.ComputedPhysicalBorderPadding().left -
   542                     aReflowState.ComputedPhysicalPadding().left;
   543   nscoord yOffset = aReflowState.ComputedPhysicalBorderPadding().top -
   544                     aReflowState.ComputedPhysicalPadding().top;
   546   // reflow the child
   547   nsHTMLReflowMetrics desiredSize(aReflowState);
   548   ReflowChild(aKid, aPresContext, desiredSize, kidReflowState, 
   549               xOffset, yOffset, 0, aStatus);
   551   // place the child
   552   FinishReflowChild(aKid, aPresContext, desiredSize,
   553                     &kidReflowState, xOffset, yOffset, 0);
   555   // consider the overflow
   556   aParentDesiredSize.mOverflowAreas.UnionWith(desiredSize.mOverflowAreas);
   557 }
   559 nsSize
   560 nsTextControlFrame::GetMinSize(nsBoxLayoutState& aState)
   561 {
   562   // XXXbz why?  Why not the nsBoxFrame sizes?
   563   return nsBox::GetMinSize(aState);
   564 }
   566 bool
   567 nsTextControlFrame::IsCollapsed()
   568 {
   569   // We're never collapsed in the box sense.
   570   return false;
   571 }
   573 bool
   574 nsTextControlFrame::IsLeaf() const
   575 {
   576   return true;
   577 }
   579 NS_IMETHODIMP
   580 nsTextControlFrame::ScrollOnFocusEvent::Run()
   581 {
   582   if (mFrame) {
   583     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(mFrame->GetContent());
   584     NS_ASSERTION(txtCtrl, "Content not a text control element");
   585     nsISelectionController* selCon = txtCtrl->GetSelectionController();
   586     if (selCon) {
   587       mFrame->mScrollEvent.Forget();
   588       selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
   589                                       nsISelectionController::SELECTION_FOCUS_REGION,
   590                                       nsISelectionController::SCROLL_SYNCHRONOUS);
   591     }
   592   }
   593   return NS_OK;
   594 }
   596 //IMPLEMENTING NS_IFORMCONTROLFRAME
   597 void nsTextControlFrame::SetFocus(bool aOn, bool aRepaint)
   598 {
   599   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   600   NS_ASSERTION(txtCtrl, "Content not a text control element");
   602   // Revoke the previous scroll event if one exists
   603   mScrollEvent.Revoke();
   605   // If 'dom.placeholeder.show_on_focus' preference is 'false', focusing or
   606   // blurring the frame can have an impact on the placeholder visibility.
   607   if (mUsePlaceholder) {
   608     txtCtrl->UpdatePlaceholderVisibility(true);
   609   }
   611   if (!aOn) {
   612     return;
   613   }
   615   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   616   if (!selCon)
   617     return;
   619   nsCOMPtr<nsISelection> ourSel;
   620   selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, 
   621     getter_AddRefs(ourSel));
   622   if (!ourSel) return;
   624   nsIPresShell* presShell = PresContext()->GetPresShell();
   625   nsRefPtr<nsCaret> caret = presShell->GetCaret();
   626   if (!caret) return;
   628   // Scroll the current selection into view
   629   nsISelection *caretSelection = caret->GetCaretDOMSelection();
   630   const bool isFocusedRightNow = ourSel == caretSelection;
   631   if (!isFocusedRightNow) {
   632     // Don't scroll the current selection if we've been focused using the mouse.
   633     uint32_t lastFocusMethod = 0;
   634     nsIDocument* doc = GetContent()->GetCurrentDoc();
   635     if (doc) {
   636       nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   637       if (fm) {
   638         fm->GetLastFocusMethod(doc->GetWindow(), &lastFocusMethod);
   639       }
   640     }
   641     if (!(lastFocusMethod & nsIFocusManager::FLAG_BYMOUSE)) {
   642       nsRefPtr<ScrollOnFocusEvent> event = new ScrollOnFocusEvent(this);
   643       nsresult rv = NS_DispatchToCurrentThread(event);
   644       if (NS_SUCCEEDED(rv)) {
   645         mScrollEvent = event;
   646       }
   647     }
   648   }
   650   // tell the caret to use our selection
   651   caret->SetCaretDOMSelection(ourSel);
   653   // mutual-exclusion: the selection is either controlled by the
   654   // document or by the text input/area. Clear any selection in the
   655   // document since the focus is now on our independent selection.
   657   nsCOMPtr<nsISelectionController> selcon = do_QueryInterface(presShell);
   658   nsCOMPtr<nsISelection> docSel;
   659   selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
   660     getter_AddRefs(docSel));
   661   if (!docSel) return;
   663   bool isCollapsed = false;
   664   docSel->GetIsCollapsed(&isCollapsed);
   665   if (!isCollapsed)
   666     docSel->RemoveAllRanges();
   667 }
   669 nsresult nsTextControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
   670 {
   671   if (!mIsProcessing)//some kind of lock.
   672   {
   673     mIsProcessing = true;
   674     if (nsGkAtoms::select == aName)
   675     {
   676       // Select all the text.
   677       //
   678       // XXX: This is lame, we can't call editor's SelectAll method
   679       //      because that triggers AutoCopies in unix builds.
   680       //      Instead, we have to call our own homegrown version
   681       //      of select all which merely builds a range that selects
   682       //      all of the content and adds that to the selection.
   684       nsWeakFrame weakThis = this;
   685       SelectAllOrCollapseToEndOfText(true);  // NOTE: can destroy the world
   686       if (!weakThis.IsAlive()) {
   687         return NS_OK;
   688       }
   689     }
   690     mIsProcessing = false;
   691   }
   692   return NS_OK;
   693 }
   695 NS_IMETHODIMP
   696 nsTextControlFrame::GetEditor(nsIEditor **aEditor)
   697 {
   698   NS_ENSURE_ARG_POINTER(aEditor);
   700   nsresult rv = EnsureEditorInitialized();
   701   NS_ENSURE_SUCCESS(rv, rv);
   703   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   704   NS_ASSERTION(txtCtrl, "Content not a text control element");
   705   *aEditor = txtCtrl->GetTextEditor();
   706   NS_IF_ADDREF(*aEditor);
   707   return NS_OK;
   708 }
   710 nsresult
   711 nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode,
   712                                          int32_t aStartOffset,
   713                                          nsIDOMNode *aEndNode,
   714                                          int32_t aEndOffset,
   715                                          nsITextControlFrame::SelectionDirection aDirection)
   716 {
   717   // Create a new range to represent the new selection.
   718   // Note that we use a new range to avoid having to do
   719   // isIncreasing checks to avoid possible errors.
   721   nsRefPtr<nsRange> range = new nsRange(mContent);
   722   nsresult rv = range->SetStart(aStartNode, aStartOffset);
   723   NS_ENSURE_SUCCESS(rv, rv);
   725   rv = range->SetEnd(aEndNode, aEndOffset);
   726   NS_ENSURE_SUCCESS(rv, rv);
   728   // Get the selection, clear it and add the new range to it!
   729   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   730   NS_ASSERTION(txtCtrl, "Content not a text control element");
   731   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   732   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
   734   nsCOMPtr<nsISelection> selection;
   735   selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
   736   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
   738   nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection, &rv);
   739   NS_ENSURE_SUCCESS(rv, rv);
   741   nsDirection direction;
   742   if (aDirection == eNone) {
   743     // Preserve the direction
   744     direction = selPriv->GetSelectionDirection();
   745   } else {
   746     direction = (aDirection == eBackward) ? eDirPrevious : eDirNext;
   747   }
   749   rv = selection->RemoveAllRanges();
   750   NS_ENSURE_SUCCESS(rv, rv);
   752   rv = selection->AddRange(range);  // NOTE: can destroy the world
   753   NS_ENSURE_SUCCESS(rv, rv);
   755   selPriv->SetSelectionDirection(direction);
   756   return rv;
   757 }
   759 nsresult
   760 nsTextControlFrame::ScrollSelectionIntoView()
   761 {
   762   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   763   NS_ASSERTION(txtCtrl, "Content not a text control element");
   764   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   765   if (selCon) {
   766     // Scroll the selection into view (see bug 231389).
   767     return selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
   768                                            nsISelectionController::SELECTION_FOCUS_REGION,
   769                                            nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY);
   770   }
   772   return NS_ERROR_FAILURE;
   773 }
   775 mozilla::dom::Element*
   776 nsTextControlFrame::GetRootNodeAndInitializeEditor()
   777 {
   778   nsCOMPtr<nsIDOMElement> root;
   779   GetRootNodeAndInitializeEditor(getter_AddRefs(root));
   780   nsCOMPtr<mozilla::dom::Element> rootElem = do_QueryInterface(root);
   781   return rootElem;
   782 }
   784 nsresult
   785 nsTextControlFrame::GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement)
   786 {
   787   NS_ENSURE_ARG_POINTER(aRootElement);
   789   nsCOMPtr<nsIEditor> editor;
   790   GetEditor(getter_AddRefs(editor));
   791   if (!editor)
   792     return NS_OK;
   794   return editor->GetRootElement(aRootElement);
   795 }
   797 nsresult
   798 nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect)
   799 {
   800   nsCOMPtr<nsIDOMElement> rootElement;
   801   nsresult rv = GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement));
   802   NS_ENSURE_SUCCESS(rv, rv);
   804   nsCOMPtr<nsIContent> rootContent = do_QueryInterface(rootElement);
   805   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
   807   NS_ENSURE_TRUE(rootNode && rootContent, NS_ERROR_FAILURE);
   809   int32_t numChildren = rootContent->GetChildCount();
   811   if (numChildren > 0) {
   812     // We never want to place the selection after the last
   813     // br under the root node!
   814     nsIContent *child = rootContent->GetChildAt(numChildren - 1);
   815     if (child) {
   816       if (child->Tag() == nsGkAtoms::br)
   817         --numChildren;
   818     }
   819     if (!aSelect && numChildren) {
   820       child = rootContent->GetChildAt(numChildren - 1);
   821       if (child && child->IsNodeOfType(nsINode::eTEXT)) {
   822         rootNode = do_QueryInterface(child);
   823         const nsTextFragment* fragment = child->GetText();
   824         numChildren = fragment ? fragment->GetLength() : 0;
   825       }
   826     }
   827   }
   829   rv = SetSelectionInternal(rootNode, aSelect ? 0 : numChildren,
   830                             rootNode, numChildren);
   831   NS_ENSURE_SUCCESS(rv, rv);
   833   return ScrollSelectionIntoView();
   834 }
   836 nsresult
   837 nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd,
   838                                           nsITextControlFrame::SelectionDirection aDirection)
   839 {
   840   NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!");
   842   if (aSelStart > aSelEnd)
   843     return NS_ERROR_FAILURE;
   845   nsCOMPtr<nsIDOMNode> startNode, endNode;
   846   int32_t startOffset, endOffset;
   848   // Calculate the selection start point.
   850   nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset);
   852   NS_ENSURE_SUCCESS(rv, rv);
   854   if (aSelStart == aSelEnd) {
   855     // Collapsed selection, so start and end are the same!
   856     endNode   = startNode;
   857     endOffset = startOffset;
   858   }
   859   else {
   860     // Selection isn't collapsed so we have to calculate
   861     // the end point too.
   863     rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset);
   865     NS_ENSURE_SUCCESS(rv, rv);
   866   }
   868   return SetSelectionInternal(startNode, startOffset, endNode, endOffset, aDirection);
   869 }
   871 NS_IMETHODIMP
   872 nsTextControlFrame::SetSelectionRange(int32_t aSelStart, int32_t aSelEnd,
   873                                       nsITextControlFrame::SelectionDirection aDirection)
   874 {
   875   nsresult rv = EnsureEditorInitialized();
   876   NS_ENSURE_SUCCESS(rv, rv);
   878   if (aSelStart > aSelEnd) {
   879     // Simulate what we'd see SetSelectionStart() was called, followed
   880     // by a SetSelectionEnd().
   882     aSelStart   = aSelEnd;
   883   }
   885   return SetSelectionEndPoints(aSelStart, aSelEnd, aDirection);
   886 }
   889 NS_IMETHODIMP
   890 nsTextControlFrame::SetSelectionStart(int32_t aSelectionStart)
   891 {
   892   nsresult rv = EnsureEditorInitialized();
   893   NS_ENSURE_SUCCESS(rv, rv);
   895   int32_t selStart = 0, selEnd = 0; 
   897   rv = GetSelectionRange(&selStart, &selEnd);
   898   NS_ENSURE_SUCCESS(rv, rv);
   900   if (aSelectionStart > selEnd) {
   901     // Collapse to the new start point.
   902     selEnd = aSelectionStart; 
   903   }
   905   selStart = aSelectionStart;
   907   return SetSelectionEndPoints(selStart, selEnd);
   908 }
   910 NS_IMETHODIMP
   911 nsTextControlFrame::SetSelectionEnd(int32_t aSelectionEnd)
   912 {
   913   nsresult rv = EnsureEditorInitialized();
   914   NS_ENSURE_SUCCESS(rv, rv);
   916   int32_t selStart = 0, selEnd = 0; 
   918   rv = GetSelectionRange(&selStart, &selEnd);
   919   NS_ENSURE_SUCCESS(rv, rv);
   921   if (aSelectionEnd < selStart) {
   922     // Collapse to the new end point.
   923     selStart = aSelectionEnd; 
   924   }
   926   selEnd = aSelectionEnd;
   928   return SetSelectionEndPoints(selStart, selEnd);
   929 }
   931 nsresult
   932 nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset,
   933                                      nsIDOMNode** aResult,
   934                                      int32_t* aPosition)
   935 {
   936   NS_ENSURE_ARG_POINTER(aResult && aPosition);
   938   *aResult = nullptr;
   939   *aPosition = 0;
   941   nsCOMPtr<nsIDOMElement> rootElement;
   942   nsresult rv = GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement));
   943   NS_ENSURE_SUCCESS(rv, rv);
   944   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
   946   NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
   948   nsCOMPtr<nsIDOMNodeList> nodeList;
   950   rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
   951   NS_ENSURE_SUCCESS(rv, rv);
   952   NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
   954   uint32_t length = 0;
   956   rv = nodeList->GetLength(&length);
   957   NS_ENSURE_SUCCESS(rv, rv);
   959   NS_ASSERTION(length <= 2, "We should have one text node and one mozBR at most");
   961   nsCOMPtr<nsIDOMNode> firstNode;
   962   rv = nodeList->Item(0, getter_AddRefs(firstNode));
   963   NS_ENSURE_SUCCESS(rv, rv);
   964   nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(firstNode);
   966   if (length == 0 || aOffset < 0) {
   967     NS_IF_ADDREF(*aResult = rootNode);
   968     *aPosition = 0;
   969   } else if (textNode) {
   970     uint32_t textLength = 0;
   971     textNode->GetLength(&textLength);
   972     if (length == 2 && uint32_t(aOffset) == textLength) {
   973       // If we're at the end of the text node and we have a trailing BR node,
   974       // set the selection on the BR node.
   975       NS_IF_ADDREF(*aResult = rootNode);
   976       *aPosition = 1;
   977     } else {
   978       // Otherwise, set the selection on the textnode itself.
   979       NS_IF_ADDREF(*aResult = firstNode);
   980       *aPosition = std::min(aOffset, int32_t(textLength));
   981     }
   982   } else {
   983     NS_IF_ADDREF(*aResult = rootNode);
   984     *aPosition = 0;
   985   }
   987   return NS_OK;
   988 }
   990 NS_IMETHODIMP
   991 nsTextControlFrame::GetSelectionRange(int32_t* aSelectionStart,
   992                                       int32_t* aSelectionEnd,
   993                                       SelectionDirection* aDirection)
   994 {
   995   // make sure we have an editor
   996   nsresult rv = EnsureEditorInitialized();
   997   NS_ENSURE_SUCCESS(rv, rv);
   999   if (aSelectionStart) {
  1000     *aSelectionStart = 0;
  1002   if (aSelectionEnd) {
  1003     *aSelectionEnd = 0;
  1005   if (aDirection) {
  1006     *aDirection = eNone;
  1009   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1010   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1011   nsISelectionController* selCon = txtCtrl->GetSelectionController();
  1012   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
  1013   nsCOMPtr<nsISelection> selection;
  1014   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
  1015   NS_ENSURE_SUCCESS(rv, rv);
  1016   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  1018   dom::Selection* sel = static_cast<dom::Selection*>(selection.get());
  1019   if (aDirection) {
  1020     nsDirection direction = sel->GetSelectionDirection();
  1021     if (direction == eDirNext) {
  1022       *aDirection = eForward;
  1023     } else if (direction == eDirPrevious) {
  1024       *aDirection = eBackward;
  1025     } else {
  1026       NS_NOTREACHED("Invalid nsDirection enum value");
  1030   if (!aSelectionStart || !aSelectionEnd) {
  1031     return NS_OK;
  1034   mozilla::dom::Element* root = GetRootNodeAndInitializeEditor();
  1035   NS_ENSURE_STATE(root);
  1036   nsContentUtils::GetSelectionInTextControl(sel, root,
  1037                                             *aSelectionStart, *aSelectionEnd);
  1039   return NS_OK;
  1042 /////END INTERFACE IMPLEMENTATIONS
  1044 ////NSIFRAME
  1045 nsresult
  1046 nsTextControlFrame::AttributeChanged(int32_t         aNameSpaceID,
  1047                                      nsIAtom*        aAttribute,
  1048                                      int32_t         aModType)
  1050   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1051   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1052   nsISelectionController* selCon = txtCtrl->GetSelectionController();
  1053   const bool needEditor = nsGkAtoms::maxlength == aAttribute ||
  1054                             nsGkAtoms::readonly == aAttribute ||
  1055                             nsGkAtoms::disabled == aAttribute ||
  1056                             nsGkAtoms::spellcheck == aAttribute;
  1057   nsCOMPtr<nsIEditor> editor;
  1058   if (needEditor) {
  1059     GetEditor(getter_AddRefs(editor));
  1061   if ((needEditor && !editor) || !selCon) {
  1062     return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
  1065   if (nsGkAtoms::maxlength == aAttribute) {
  1066     int32_t maxLength;
  1067     bool maxDefined = GetMaxLength(&maxLength);
  1068     nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(editor);
  1069     if (textEditor) {
  1070       if (maxDefined) { // set the maxLength attribute
  1071         textEditor->SetMaxTextLength(maxLength);
  1072         // if maxLength>docLength, we need to truncate the doc content
  1073       } else { // unset the maxLength attribute
  1074         textEditor->SetMaxTextLength(-1);
  1077     return NS_OK;
  1080   if (nsGkAtoms::readonly == aAttribute) {
  1081     uint32_t flags;
  1082     editor->GetFlags(&flags);
  1083     if (AttributeExists(nsGkAtoms::readonly)) { // set readonly
  1084       flags |= nsIPlaintextEditor::eEditorReadonlyMask;
  1085       if (nsContentUtils::IsFocusedContent(mContent)) {
  1086         selCon->SetCaretEnabled(false);
  1088     } else { // unset readonly
  1089       flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
  1090       if (!(flags & nsIPlaintextEditor::eEditorDisabledMask) &&
  1091           nsContentUtils::IsFocusedContent(mContent)) {
  1092         selCon->SetCaretEnabled(true);
  1095     editor->SetFlags(flags);
  1096     return NS_OK;
  1099   if (nsGkAtoms::disabled == aAttribute) {
  1100     uint32_t flags;
  1101     editor->GetFlags(&flags);
  1102     int16_t displaySelection = nsISelectionController::SELECTION_OFF;
  1103     const bool focused = nsContentUtils::IsFocusedContent(mContent);
  1104     const bool hasAttr = AttributeExists(nsGkAtoms::disabled);
  1105     if (hasAttr) { // set disabled
  1106       flags |= nsIPlaintextEditor::eEditorDisabledMask;
  1107     } else { // unset disabled
  1108       flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
  1109       displaySelection = focused ? nsISelectionController::SELECTION_ON
  1110                                  : nsISelectionController::SELECTION_HIDDEN;
  1112     selCon->SetDisplaySelection(displaySelection);
  1113     if (focused) {
  1114       selCon->SetCaretEnabled(!hasAttr);
  1116     editor->SetFlags(flags);
  1117     return NS_OK;
  1120   if (!mEditorHasBeenInitialized && nsGkAtoms::value == aAttribute) {
  1121     UpdateValueDisplay(true);
  1122     return NS_OK;
  1125   // Allow the base class to handle common attributes supported by all form
  1126   // elements...
  1127   return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
  1131 nsresult
  1132 nsTextControlFrame::GetText(nsString& aText)
  1134   nsresult rv = NS_OK;
  1135   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1136   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1137   if (IsSingleLineTextControl()) {
  1138     // There will be no line breaks so we can ignore the wrap property.
  1139     txtCtrl->GetTextEditorValue(aText, true);
  1140   } else {
  1141     nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(mContent);
  1142     if (textArea) {
  1143       rv = textArea->GetValue(aText);
  1146   return rv;
  1150 nsresult
  1151 nsTextControlFrame::GetPhonetic(nsAString& aPhonetic)
  1153   aPhonetic.Truncate(0); 
  1155   nsCOMPtr<nsIEditor> editor;
  1156   nsresult rv = GetEditor(getter_AddRefs(editor));
  1157   NS_ENSURE_SUCCESS(rv, rv);
  1159   nsCOMPtr<nsIEditorIMESupport> imeSupport = do_QueryInterface(editor);
  1160   if (imeSupport) {
  1161     nsCOMPtr<nsIPhonetic> phonetic = do_QueryInterface(imeSupport);
  1162     if (phonetic)
  1163       phonetic->GetPhonetic(aPhonetic);
  1165   return NS_OK;
  1168 ///END NSIFRAME OVERLOADS
  1169 /////BEGIN PROTECTED METHODS
  1171 bool
  1172 nsTextControlFrame::GetMaxLength(int32_t* aSize)
  1174   *aSize = -1;
  1176   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
  1177   if (content) {
  1178     const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::maxlength);
  1179     if (attr && attr->Type() == nsAttrValue::eInteger) {
  1180       *aSize = attr->GetIntegerValue();
  1182       return true;
  1185   return false;
  1188 // END IMPLEMENTING NS_IFORMCONTROLFRAME
  1190 nsresult
  1191 nsTextControlFrame::SetInitialChildList(ChildListID     aListID,
  1192                                         nsFrameList&    aChildList)
  1194   nsresult rv = nsContainerFrame::SetInitialChildList(aListID, aChildList);
  1196   nsIFrame* first = GetFirstPrincipalChild();
  1198   // Mark the scroll frame as being a reflow root. This will allow
  1199   // incremental reflows to be initiated at the scroll frame, rather
  1200   // than descending from the root frame of the frame hierarchy.
  1201   if (first) {
  1202     first->AddStateBits(NS_FRAME_REFLOW_ROOT);
  1204     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1205     NS_ASSERTION(txtCtrl, "Content not a text control element");
  1206     txtCtrl->InitializeKeyboardEventListeners();
  1208     nsPoint* contentScrollPos = static_cast<nsPoint*>
  1209       (Properties().Get(ContentScrollPos()));
  1210     if (contentScrollPos) {
  1211       // If we have a scroll pos stored to be passed to our anonymous
  1212       // div, do it here!
  1213       nsIStatefulFrame* statefulFrame = do_QueryFrame(first);
  1214       NS_ASSERTION(statefulFrame, "unexpected type of frame for the anonymous div");
  1215       nsPresState fakePresState;
  1216       fakePresState.SetScrollState(*contentScrollPos);
  1217       statefulFrame->RestoreState(&fakePresState);
  1218       Properties().Remove(ContentScrollPos());
  1219       delete contentScrollPos;
  1222   return rv;
  1225 void
  1226 nsTextControlFrame::SetValueChanged(bool aValueChanged)
  1228   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1229   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1231   if (mUsePlaceholder) {
  1232     nsWeakFrame weakFrame(this);
  1233     txtCtrl->UpdatePlaceholderVisibility(true);
  1234     if (!weakFrame.IsAlive()) {
  1235       return;
  1239   txtCtrl->SetValueChanged(aValueChanged);
  1243 nsresult
  1244 nsTextControlFrame::UpdateValueDisplay(bool aNotify,
  1245                                        bool aBeforeEditorInit,
  1246                                        const nsAString *aValue)
  1248   if (!IsSingleLineTextControl()) // textareas don't use this
  1249     return NS_OK;
  1251   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1252   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1253   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1255   NS_PRECONDITION(rootNode, "Must have a div content\n");
  1256   NS_PRECONDITION(!mEditorHasBeenInitialized,
  1257                   "Do not call this after editor has been initialized");
  1258   NS_ASSERTION(!mUsePlaceholder || txtCtrl->GetPlaceholderNode(),
  1259                "A placeholder div must exist");
  1261   nsIContent *textContent = rootNode->GetChildAt(0);
  1262   if (!textContent) {
  1263     // Set up a textnode with our value
  1264     nsRefPtr<nsTextNode> textNode =
  1265       new nsTextNode(mContent->NodeInfo()->NodeInfoManager());
  1267     NS_ASSERTION(textNode, "Must have textcontent!\n");
  1269     rootNode->AppendChildTo(textNode, aNotify);
  1270     textContent = textNode;
  1273   NS_ENSURE_TRUE(textContent, NS_ERROR_UNEXPECTED);
  1275   // Get the current value of the textfield from the content.
  1276   nsAutoString value;
  1277   if (aValue) {
  1278     value = *aValue;
  1279   } else {
  1280     txtCtrl->GetTextEditorValue(value, true);
  1283   // Update the display of the placeholder value if needed.
  1284   // We don't need to do this if we're about to initialize the
  1285   // editor, since EnsureEditorInitialized takes care of this.
  1286   if (mUsePlaceholder && !aBeforeEditorInit)
  1288     nsWeakFrame weakFrame(this);
  1289     txtCtrl->UpdatePlaceholderVisibility(aNotify);
  1290     NS_ENSURE_STATE(weakFrame.IsAlive());
  1293   if (aBeforeEditorInit && value.IsEmpty()) {
  1294     rootNode->RemoveChildAt(0, true);
  1295     return NS_OK;
  1298   if (!value.IsEmpty() && IsPasswordTextControl()) {
  1299     nsTextEditRules::FillBufWithPWChars(&value, value.Length());
  1301   return textContent->SetText(value, aNotify);
  1304 NS_IMETHODIMP
  1305 nsTextControlFrame::GetOwnedSelectionController(nsISelectionController** aSelCon)
  1307   NS_ENSURE_ARG_POINTER(aSelCon);
  1309   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1310   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1312   *aSelCon = txtCtrl->GetSelectionController();
  1313   NS_IF_ADDREF(*aSelCon);
  1315   return NS_OK;
  1318 nsFrameSelection*
  1319 nsTextControlFrame::GetOwnedFrameSelection()
  1321   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1322   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1324   return txtCtrl->GetConstFrameSelection();
  1327 NS_IMETHODIMP
  1328 nsTextControlFrame::SaveState(nsPresState** aState)
  1330   NS_ENSURE_ARG_POINTER(aState);
  1332   *aState = nullptr;
  1334   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1335   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1337   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1338   if (rootNode) {
  1339     // Query the nsIStatefulFrame from the HTMLScrollFrame
  1340     nsIStatefulFrame* scrollStateFrame = do_QueryFrame(rootNode->GetPrimaryFrame());
  1341     if (scrollStateFrame) {
  1342       return scrollStateFrame->SaveState(aState);
  1346   return NS_OK;
  1349 NS_IMETHODIMP
  1350 nsTextControlFrame::RestoreState(nsPresState* aState)
  1352   NS_ENSURE_ARG_POINTER(aState);
  1354   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1355   NS_ASSERTION(txtCtrl, "Content not a text control element");
  1357   nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1358   if (rootNode) {
  1359     // Query the nsIStatefulFrame from the HTMLScrollFrame
  1360     nsIStatefulFrame* scrollStateFrame = do_QueryFrame(rootNode->GetPrimaryFrame());
  1361     if (scrollStateFrame) {
  1362       return scrollStateFrame->RestoreState(aState);
  1366   // Most likely, we don't have our anonymous content constructed yet, which
  1367   // would cause us to end up here.  In this case, we'll just store the scroll
  1368   // pos ourselves, and forward it to the scroll frame later when it's created.
  1369   Properties().Set(ContentScrollPos(), new nsPoint(aState->GetScrollState()));
  1370   return NS_OK;
  1373 nsresult
  1374 nsTextControlFrame::PeekOffset(nsPeekOffsetStruct *aPos)
  1376   return NS_ERROR_FAILURE;
  1379 void
  1380 nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
  1381                                      const nsRect&           aDirtyRect,
  1382                                      const nsDisplayListSet& aLists)
  1384   /*
  1385    * The implementation of this method is equivalent as:
  1386    * nsContainerFrame::BuildDisplayList()
  1387    * with the difference that we filter-out the placeholder frame when it
  1388    * should not be visible.
  1389    */
  1390   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame");
  1392   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1393   NS_ASSERTION(txtCtrl, "Content not a text control element!");
  1395   DisplayBorderBackgroundOutline(aBuilder, aLists);
  1397   nsIFrame* kid = mFrames.FirstChild();
  1398   // Redirect all lists to the Content list so that nothing can escape, ie
  1399   // opacity creating stacking contexts that then get sorted with stacking
  1400   // contexts external to us.
  1401   nsDisplayList* content = aLists.Content();
  1402   nsDisplayListSet set(content, content, content, content, content, content);
  1404   while (kid) {
  1405     // If the frame is the placeholder frame, we should only show it if the
  1406     // placeholder has to be visible.
  1407     if (kid->GetContent() != txtCtrl->GetPlaceholderNode() ||
  1408         txtCtrl->GetPlaceholderVisibility()) {
  1409       BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, 0);
  1411     kid = kid->GetNextSibling();
  1415 mozilla::dom::Element*
  1416 nsTextControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
  1418   if (aType == nsCSSPseudoElements::ePseudo_mozPlaceholder) {
  1419     nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1420     return txtCtrl->GetPlaceholderNode();
  1423   return nsContainerFrame::GetPseudoElement(aType);
  1426 NS_IMETHODIMP
  1427 nsTextControlFrame::EditorInitializer::Run()
  1429   if (!mFrame) {
  1430     return NS_OK;
  1433   // Need to block script to avoid bug 669767.
  1434   nsAutoScriptBlocker scriptBlocker;
  1436   nsCOMPtr<nsIPresShell> shell =
  1437     mFrame->PresContext()->GetPresShell();
  1438   bool observes = shell->ObservesNativeAnonMutationsForPrint();
  1439   shell->ObserveNativeAnonMutationsForPrint(true);
  1440   // This can cause the frame to be destroyed (and call Revoke()).
  1441   mFrame->EnsureEditorInitialized();
  1442   shell->ObserveNativeAnonMutationsForPrint(observes);
  1444   // The frame can *still* be destroyed even though we have a scriptblocker,
  1445   // bug 682684.
  1446   if (!mFrame) {
  1447     return NS_ERROR_FAILURE;
  1450   mFrame->FinishedInitializer();
  1451   return NS_OK;

mercurial