LCOV - code coverage report
Current view: top level - layout/forms - nsDateTimeControlFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 202 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : /**
       7             :  * This frame type is used for input type=date, time, month, week, and
       8             :  * datetime-local.
       9             :  */
      10             : 
      11             : #include "nsDateTimeControlFrame.h"
      12             : 
      13             : #include "nsContentUtils.h"
      14             : #include "nsFormControlFrame.h"
      15             : #include "nsGkAtoms.h"
      16             : #include "nsContentUtils.h"
      17             : #include "nsContentCreatorFunctions.h"
      18             : #include "nsContentList.h"
      19             : #include "mozilla/dom/HTMLInputElement.h"
      20             : #include "nsNodeInfoManager.h"
      21             : #include "nsIDateTimeInputArea.h"
      22             : #include "nsIObserverService.h"
      23             : #include "nsIDOMHTMLInputElement.h"
      24             : #include "nsIDOMMutationEvent.h"
      25             : #include "jsapi.h"
      26             : #include "nsJSUtils.h"
      27             : #include "nsThreadUtils.h"
      28             : 
      29             : using namespace mozilla;
      30             : using namespace mozilla::dom;
      31             : 
      32             : nsIFrame*
      33           0 : NS_NewDateTimeControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      34             : {
      35           0 :   return new (aPresShell) nsDateTimeControlFrame(aContext);
      36             : }
      37             : 
      38           0 : NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
      39             : 
      40           0 : NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
      41           0 :   NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
      42           0 :   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
      43           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
      44             : 
      45           0 : nsDateTimeControlFrame::nsDateTimeControlFrame(nsStyleContext* aContext)
      46           0 :   : nsContainerFrame(aContext, kClassID)
      47             : {
      48           0 : }
      49             : 
      50             : void
      51           0 : nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
      52             : {
      53           0 :   nsContentUtils::DestroyAnonymousContent(&mInputAreaContent);
      54           0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
      55           0 : }
      56             : 
      57             : void
      58           0 : nsDateTimeControlFrame::OnValueChanged()
      59             : {
      60             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
      61           0 :     do_QueryInterface(mInputAreaContent);
      62           0 :   if (inputAreaContent) {
      63           0 :     inputAreaContent->NotifyInputElementValueChanged();
      64             :   }
      65           0 : }
      66             : 
      67             : void
      68           0 : nsDateTimeControlFrame::OnMinMaxStepAttrChanged()
      69             : {
      70             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
      71           0 :     do_QueryInterface(mInputAreaContent);
      72           0 :   if (inputAreaContent) {
      73           0 :     inputAreaContent->NotifyMinMaxStepAttrChanged();
      74             :   }
      75           0 : }
      76             : 
      77             : void
      78           0 : nsDateTimeControlFrame::SetValueFromPicker(const DateTimeValue& aValue)
      79             : {
      80             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
      81           0 :     do_QueryInterface(mInputAreaContent);
      82           0 :   if (inputAreaContent) {
      83           0 :     AutoJSAPI api;
      84           0 :     if (!api.Init(mContent->OwnerDoc()->GetScopeObject())) {
      85           0 :       return;
      86             :     }
      87             : 
      88           0 :     JSObject* wrapper = mContent->GetWrapper();
      89           0 :     if (!wrapper) {
      90           0 :       return;
      91             :     }
      92             : 
      93           0 :     JSObject* scope = xpc::GetXBLScope(api.cx(), wrapper);
      94           0 :     AutoJSAPI jsapi;
      95           0 :     if (!scope || !jsapi.Init(scope)) {
      96           0 :       return;
      97             :     }
      98             : 
      99           0 :     JS::Rooted<JS::Value> jsValue(jsapi.cx());
     100           0 :     if (!ToJSValue(jsapi.cx(), aValue, &jsValue)) {
     101           0 :       return;
     102             :     }
     103             : 
     104           0 :     inputAreaContent->SetValueFromPicker(jsValue);
     105             :   }
     106             : }
     107             : 
     108             : void
     109           0 : nsDateTimeControlFrame::SetPickerState(bool aOpen)
     110             : {
     111             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     112           0 :     do_QueryInterface(mInputAreaContent);
     113           0 :   if (inputAreaContent) {
     114           0 :     inputAreaContent->SetPickerState(aOpen);
     115             :   }
     116           0 : }
     117             : 
     118             : void
     119           0 : nsDateTimeControlFrame::HandleFocusEvent()
     120             : {
     121             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     122           0 :     do_QueryInterface(mInputAreaContent);
     123           0 :   if (inputAreaContent) {
     124           0 :     inputAreaContent->FocusInnerTextBox();
     125             :   }
     126           0 : }
     127             : 
     128             : void
     129           0 : nsDateTimeControlFrame::HandleBlurEvent()
     130             : {
     131             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     132           0 :     do_QueryInterface(mInputAreaContent);
     133           0 :   if (inputAreaContent) {
     134           0 :     inputAreaContent->BlurInnerTextBox();
     135             :   }
     136           0 : }
     137             : 
     138             : bool
     139           0 : nsDateTimeControlFrame::HasBadInput()
     140             : {
     141             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     142           0 :     do_QueryInterface(mInputAreaContent);
     143             : 
     144           0 :   bool result = false;
     145           0 :   if (inputAreaContent) {
     146           0 :     inputAreaContent->HasBadInput(&result);
     147             :   }
     148             : 
     149           0 :   return result;
     150             : }
     151             : 
     152             : nscoord
     153           0 : nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext)
     154             : {
     155             :   nscoord result;
     156           0 :   DISPLAY_MIN_WIDTH(this, result);
     157             : 
     158           0 :   nsIFrame* kid = mFrames.FirstChild();
     159           0 :   if (kid) { // display:none?
     160           0 :     result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     161             :                                                   kid,
     162             :                                                   nsLayoutUtils::MIN_ISIZE);
     163             :   } else {
     164           0 :     result = 0;
     165             :   }
     166             : 
     167           0 :   return result;
     168             : }
     169             : 
     170             : nscoord
     171           0 : nsDateTimeControlFrame::GetPrefISize(gfxContext* aRenderingContext)
     172             : {
     173             :   nscoord result;
     174           0 :   DISPLAY_PREF_WIDTH(this, result);
     175             : 
     176           0 :   nsIFrame* kid = mFrames.FirstChild();
     177           0 :   if (kid) { // display:none?
     178           0 :     result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     179             :                                                   kid,
     180             :                                                   nsLayoutUtils::PREF_ISIZE);
     181             :   } else {
     182           0 :     result = 0;
     183             :   }
     184             : 
     185           0 :   return result;
     186             : }
     187             : 
     188             : void
     189           0 : nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
     190             :                                ReflowOutput& aDesiredSize,
     191             :                                const ReflowInput& aReflowInput,
     192             :                                nsReflowStatus& aStatus)
     193             : {
     194           0 :   MarkInReflow();
     195             : 
     196           0 :   DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame");
     197           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
     198           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     199             :                  ("enter nsDateTimeControlFrame::Reflow: availSize=%d,%d",
     200             :                   aReflowInput.AvailableWidth(),
     201             :                   aReflowInput.AvailableHeight()));
     202             : 
     203           0 :   NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
     204             : 
     205           0 :   const WritingMode myWM = aReflowInput.GetWritingMode();
     206             : 
     207             :   // The ISize of our content box, which is the available ISize
     208             :   // for our anonymous content:
     209           0 :   const nscoord contentBoxISize = aReflowInput.ComputedISize();
     210           0 :   nscoord contentBoxBSize = aReflowInput.ComputedBSize();
     211             : 
     212             :   // Figure out our border-box sizes as well (by adding borderPadding to
     213             :   // content-box sizes):
     214             :   const nscoord borderBoxISize = contentBoxISize +
     215           0 :     aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM);
     216             : 
     217             :   nscoord borderBoxBSize;
     218           0 :   if (contentBoxBSize != NS_INTRINSICSIZE) {
     219           0 :     borderBoxBSize = contentBoxBSize +
     220           0 :       aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
     221             :   } // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize.
     222             : 
     223           0 :   nsIFrame* inputAreaFrame = mFrames.FirstChild();
     224           0 :   if (!inputAreaFrame) { // display:none?
     225           0 :     if (contentBoxBSize == NS_INTRINSICSIZE) {
     226           0 :       contentBoxBSize = 0;
     227             :       borderBoxBSize =
     228           0 :         aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
     229             :     }
     230             :   } else {
     231           0 :     NS_ASSERTION(inputAreaFrame->GetContent() == mInputAreaContent,
     232             :                  "What is this child doing here?");
     233             : 
     234           0 :     ReflowOutput childDesiredSize(aReflowInput);
     235             : 
     236           0 :     WritingMode wm = inputAreaFrame->GetWritingMode();
     237           0 :     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     238           0 :     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     239             : 
     240             :     ReflowInput childReflowOuput(aPresContext, aReflowInput,
     241           0 :                                  inputAreaFrame, availSize);
     242             : 
     243             :     // Convert input area margin into my own writing-mode (in case it differs):
     244             :     LogicalMargin childMargin =
     245           0 :       childReflowOuput.ComputedLogicalMargin().ConvertTo(myWM, wm);
     246             : 
     247             :     // offsets of input area frame within this frame:
     248             :     LogicalPoint
     249             :       childOffset(myWM,
     250           0 :                   aReflowInput.ComputedLogicalBorderPadding().IStart(myWM) +
     251           0 :                   childMargin.IStart(myWM),
     252           0 :                   aReflowInput.ComputedLogicalBorderPadding().BStart(myWM) +
     253           0 :                   childMargin.BStart(myWM));
     254             : 
     255           0 :     nsReflowStatus childStatus;
     256             :     // We initially reflow the child with a dummy containerSize; positioning
     257             :     // will be fixed later.
     258           0 :     const nsSize dummyContainerSize;
     259           0 :     ReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
     260             :                 childReflowOuput, myWM, childOffset, dummyContainerSize, 0,
     261           0 :                 childStatus);
     262           0 :     MOZ_ASSERT(childStatus.IsFullyComplete(),
     263             :                "We gave our child unconstrained available block-size, "
     264             :                "so it should be complete");
     265             : 
     266             :     nscoord childMarginBoxBSize =
     267           0 :       childDesiredSize.BSize(myWM) + childMargin.BStartEnd(myWM);
     268             : 
     269           0 :     if (contentBoxBSize == NS_INTRINSICSIZE) {
     270             :       // We are intrinsically sized -- we should shrinkwrap the input area's
     271             :       // block-size:
     272           0 :       contentBoxBSize = childMarginBoxBSize;
     273             : 
     274             :       // Make sure we obey min/max-bsize in the case when we're doing intrinsic
     275             :       // sizing (we get it for free when we have a non-intrinsic
     276             :       // aReflowInput.ComputedBSize()).  Note that we do this before
     277             :       // adjusting for borderpadding, since ComputedMaxBSize and
     278             :       // ComputedMinBSize are content heights.
     279             :       contentBoxBSize =
     280           0 :         NS_CSS_MINMAX(contentBoxBSize,
     281             :                       aReflowInput.ComputedMinBSize(),
     282           0 :                       aReflowInput.ComputedMaxBSize());
     283             : 
     284           0 :       borderBoxBSize = contentBoxBSize +
     285           0 :         aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
     286             :     }
     287             : 
     288             :     // Center child in block axis
     289           0 :     nscoord extraSpace = contentBoxBSize - childMarginBoxBSize;
     290           0 :     childOffset.B(myWM) += std::max(0, extraSpace / 2);
     291             : 
     292             :     // Needed in FinishReflowChild, for logical-to-physical conversion:
     293           0 :     nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize).
     294           0 :                            GetPhysicalSize(myWM);
     295             : 
     296             :     // Place the child
     297             :     FinishReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
     298           0 :                       &childReflowOuput, myWM, childOffset, borderBoxSize, 0);
     299             : 
     300             :     nsSize contentBoxSize =
     301           0 :       LogicalSize(myWM, contentBoxISize, contentBoxBSize).
     302           0 :         GetPhysicalSize(myWM);
     303           0 :     aDesiredSize.SetBlockStartAscent(
     304           0 :       childDesiredSize.BlockStartAscent() +
     305           0 :       inputAreaFrame->BStart(aReflowInput.GetWritingMode(),
     306           0 :                              contentBoxSize));
     307             :   }
     308             : 
     309           0 :   LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
     310           0 :   aDesiredSize.SetSize(myWM, logicalDesiredSize);
     311             : 
     312           0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
     313             : 
     314           0 :   if (inputAreaFrame) {
     315           0 :     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inputAreaFrame);
     316             :   }
     317             : 
     318           0 :   FinishAndStoreOverflow(&aDesiredSize);
     319             : 
     320           0 :   aStatus.Reset();
     321             : 
     322           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     323             :                  ("exit nsDateTimeControlFrame::Reflow: size=%d,%d",
     324             :                   aDesiredSize.Width(), aDesiredSize.Height()));
     325           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
     326           0 : }
     327             : 
     328             : nsresult
     329           0 : nsDateTimeControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
     330             : {
     331             :   // Set up "datetimebox" XUL element which will be XBL-bound to the
     332             :   // actual controls.
     333             :   nsNodeInfoManager* nodeInfoManager =
     334           0 :     mContent->GetComposedDoc()->NodeInfoManager();
     335             :   RefPtr<NodeInfo> nodeInfo =
     336           0 :     nodeInfoManager->GetNodeInfo(nsGkAtoms::datetimebox, nullptr,
     337           0 :                                  kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE);
     338           0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
     339             : 
     340           0 :   NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
     341           0 :   aElements.AppendElement(mInputAreaContent);
     342             : 
     343             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     344           0 :     do_QueryInterface(mInputAreaContent);
     345           0 :   if (inputAreaContent) {
     346             :     // Propogate our tabindex.
     347           0 :     nsAutoString tabIndexStr;
     348           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr)) {
     349           0 :       inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("tabindex"),
     350           0 :                                          tabIndexStr);
     351             :     }
     352             : 
     353             :     // Propagate our readonly state.
     354           0 :     nsAutoString readonly;
     355           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly)) {
     356           0 :       inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("readonly"),
     357           0 :                                          readonly);
     358             :     }
     359             : 
     360           0 :     SyncDisabledState();
     361             :   }
     362             : 
     363           0 :   return NS_OK;
     364             : }
     365             : 
     366             : void
     367           0 : nsDateTimeControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
     368             :                                                  uint32_t aFilter)
     369             : {
     370           0 :   if (mInputAreaContent) {
     371           0 :     aElements.AppendElement(mInputAreaContent);
     372             :   }
     373           0 : }
     374             : 
     375             : void
     376           0 : nsDateTimeControlFrame::SyncDisabledState()
     377             : {
     378           0 :   NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
     379             :   nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     380           0 :     do_QueryInterface(mInputAreaContent);
     381           0 :   if (!inputAreaContent) {
     382           0 :     return;
     383             :   }
     384             : 
     385           0 :   EventStates eventStates = mContent->AsElement()->State();
     386           0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
     387           0 :     inputAreaContent->SetEditAttribute(NS_LITERAL_STRING("disabled"),
     388           0 :                                        EmptyString());
     389             :   } else {
     390           0 :     inputAreaContent->RemoveEditAttribute(NS_LITERAL_STRING("disabled"));
     391             :   }
     392             : }
     393             : 
     394             : nsresult
     395           0 : nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
     396             :                                          nsIAtom* aAttribute,
     397             :                                          int32_t aModType)
     398             : {
     399           0 :   NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
     400             : 
     401             :   // nsGkAtoms::disabled is handled by SyncDisabledState
     402           0 :   if (aNameSpaceID == kNameSpaceID_None) {
     403           0 :     if (aAttribute == nsGkAtoms::value ||
     404           0 :         aAttribute == nsGkAtoms::readonly ||
     405           0 :         aAttribute == nsGkAtoms::tabindex) {
     406           0 :       MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
     407           0 :       auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
     408             :       // If script changed the <input>'s type before setting these attributes
     409             :       // then we don't need to do anything since we are going to be reframed.
     410           0 :       if (contentAsInputElem->ControlType() == NS_FORM_INPUT_TIME ||
     411           0 :           contentAsInputElem->ControlType() == NS_FORM_INPUT_DATE) {
     412             :         nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
     413           0 :           do_QueryInterface(mInputAreaContent);
     414           0 :         if (aAttribute == nsGkAtoms::value) {
     415           0 :           if (inputAreaContent) {
     416           0 :             nsContentUtils::AddScriptRunner(NewRunnableMethod(
     417             :               "nsIDateTimeInputArea::NotifyInputElementValueChanged",
     418             :               inputAreaContent,
     419           0 :               &nsIDateTimeInputArea::NotifyInputElementValueChanged));
     420             :           }
     421             :         } else {
     422           0 :           if (aModType == nsIDOMMutationEvent::REMOVAL) {
     423           0 :             if (inputAreaContent) {
     424           0 :               nsAtomString name(aAttribute);
     425           0 :               inputAreaContent->RemoveEditAttribute(name);
     426             :             }
     427             :           } else {
     428           0 :             MOZ_ASSERT(aModType == nsIDOMMutationEvent::ADDITION ||
     429             :                        aModType == nsIDOMMutationEvent::MODIFICATION);
     430           0 :             if (inputAreaContent) {
     431           0 :               nsAtomString name(aAttribute);
     432           0 :               nsAutoString value;
     433           0 :               mContent->GetAttr(aNameSpaceID, aAttribute, value);
     434           0 :               inputAreaContent->SetEditAttribute(name, value);
     435             :             }
     436             :           }
     437             :         }
     438             :       }
     439             :     }
     440             :   }
     441             : 
     442           0 :   return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
     443           0 :                                             aModType);
     444             : }
     445             : 
     446             : void
     447           0 : nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates)
     448             : {
     449           0 :   if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
     450           0 :     nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
     451             :   }
     452           0 : }

Generated by: LCOV version 1.13