layout/mathml/nsMathMLmactionFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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 "nsMathMLmactionFrame.h"
     7 #include "nsCOMPtr.h"
     8 #include "nsPresContext.h"
     9 #include "nsNameSpaceManager.h"
    10 #include "prprf.h"         // For PR_snprintf()
    11 #include "nsIDocShell.h"
    12 #include "nsIDocShellTreeOwner.h"
    13 #include "nsIWebBrowserChrome.h"
    14 #include "nsIInterfaceRequestorUtils.h"
    15 #include "nsTextFragment.h"
    16 #include "nsIDOMEvent.h"
    17 #include "mozilla/gfx/2D.h"
    19 //
    20 // <maction> -- bind actions to a subexpression - implementation
    21 //
    23 enum nsMactionActionTypes {
    24   NS_MATHML_ACTION_TYPE_CLASS_ERROR            = 0x10,
    25   NS_MATHML_ACTION_TYPE_CLASS_USE_SELECTION    = 0x20,
    26   NS_MATHML_ACTION_TYPE_CLASS_IGNORE_SELECTION = 0x40,
    27   NS_MATHML_ACTION_TYPE_CLASS_BITMASK          = 0xF0,
    29   NS_MATHML_ACTION_TYPE_NONE       = NS_MATHML_ACTION_TYPE_CLASS_ERROR|0x01,
    31   NS_MATHML_ACTION_TYPE_TOGGLE     = NS_MATHML_ACTION_TYPE_CLASS_USE_SELECTION|0x01,
    32   NS_MATHML_ACTION_TYPE_UNKNOWN    = NS_MATHML_ACTION_TYPE_CLASS_USE_SELECTION|0x02,
    34   NS_MATHML_ACTION_TYPE_STATUSLINE = NS_MATHML_ACTION_TYPE_CLASS_IGNORE_SELECTION|0x01,
    35   NS_MATHML_ACTION_TYPE_TOOLTIP    = NS_MATHML_ACTION_TYPE_CLASS_IGNORE_SELECTION|0x02
    36 };
    39 // helper function to parse actiontype attribute
    40 static int32_t
    41 GetActionType(nsIContent* aContent)
    42 {
    43   nsAutoString value;
    45   if (aContent) {
    46     if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::actiontype_, value))
    47       return NS_MATHML_ACTION_TYPE_NONE; 
    48   }
    50   if (value.EqualsLiteral("toggle"))
    51     return NS_MATHML_ACTION_TYPE_TOGGLE;
    52   if (value.EqualsLiteral("statusline"))
    53     return NS_MATHML_ACTION_TYPE_STATUSLINE;
    54   if (value.EqualsLiteral("tooltip"))
    55     return NS_MATHML_ACTION_TYPE_TOOLTIP;
    57   return NS_MATHML_ACTION_TYPE_UNKNOWN;
    58 }
    60 nsIFrame*
    61 NS_NewMathMLmactionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    62 {
    63   return new (aPresShell) nsMathMLmactionFrame(aContext);
    64 }
    66 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmactionFrame)
    68 nsMathMLmactionFrame::~nsMathMLmactionFrame()
    69 {
    70   // unregister us as a mouse event listener ...
    71   //  printf("maction:%p unregistering as mouse event listener ...\n", this);
    72   if (mListener) {
    73     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("click"), mListener,
    74                                         false);
    75     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mouseover"), mListener,
    76                                         false);
    77     mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mouseout"), mListener,
    78                                         false);
    79   }
    80 }
    82 void
    83 nsMathMLmactionFrame::Init(nsIContent*      aContent,
    84                            nsIFrame*        aParent,
    85                            nsIFrame*        aPrevInFlow)
    86 {
    87   // Init our local attributes
    89   mChildCount = -1; // these will be updated in GetSelectedFrame()
    90   mActionType = GetActionType(aContent);
    92   // Let the base class do the rest
    93   return nsMathMLSelectedFrame::Init(aContent, aParent, aPrevInFlow);
    94 }
    96 nsresult
    97 nsMathMLmactionFrame::ChildListChanged(int32_t aModType)
    98 {
    99   // update cached values
   100   mChildCount = -1;
   101   mSelectedFrame = nullptr;
   103   return nsMathMLSelectedFrame::ChildListChanged(aModType);
   104 }
   106 // return the frame whose number is given by the attribute selection="number"
   107 nsIFrame* 
   108 nsMathMLmactionFrame::GetSelectedFrame()
   109 {
   110   nsAutoString value;
   111   int32_t selection; 
   113   if ((mActionType & NS_MATHML_ACTION_TYPE_CLASS_BITMASK) == 
   114        NS_MATHML_ACTION_TYPE_CLASS_ERROR) {
   115     mSelection = -1;
   116     mInvalidMarkup = true;
   117     mSelectedFrame = nullptr;
   118     return mSelectedFrame;
   119   }
   121   // Selection is not applied to tooltip and statusline.
   122   // Thereby return the first child.
   123   if ((mActionType & NS_MATHML_ACTION_TYPE_CLASS_BITMASK) == 
   124        NS_MATHML_ACTION_TYPE_CLASS_IGNORE_SELECTION) {
   125     // We don't touch mChildCount here. It's incorrect to assign it 1,
   126     // and it's inefficient to count the children. It's fine to leave
   127     // it be equal -1 because it's not used with other actiontypes.
   128     mSelection = 1;
   129     mInvalidMarkup = false;
   130     mSelectedFrame = mFrames.FirstChild();
   131     return mSelectedFrame;
   132   }
   134   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value);
   135   if (!value.IsEmpty()) {
   136     nsresult errorCode;
   137     selection = value.ToInteger(&errorCode);
   138     if (NS_FAILED(errorCode)) 
   139       selection = 1;
   140   }
   141   else selection = 1; // default is first frame
   143   if (-1 != mChildCount) { // we have been in this function before...
   144     // cater for invalid user-supplied selection
   145     if (selection > mChildCount || selection < 1)
   146       selection = -1;
   147     // quick return if it is identical with our cache
   148     if (selection == mSelection) 
   149       return mSelectedFrame;
   150   }
   152   // get the selected child and cache new values...
   153   int32_t count = 0;
   154   nsIFrame* childFrame = mFrames.FirstChild();
   155   while (childFrame) {
   156     if (!mSelectedFrame) 
   157       mSelectedFrame = childFrame; // default is first child
   158     if (++count == selection) 
   159       mSelectedFrame = childFrame;
   161     childFrame = childFrame->GetNextSibling();
   162   }
   163   // cater for invalid user-supplied selection
   164   if (selection > count || selection < 1)
   165     selection = -1;
   167   mChildCount = count;
   168   mSelection = selection;
   169   mInvalidMarkup = (mSelection == -1);
   170   TransmitAutomaticData();
   172   return mSelectedFrame;
   173 }
   175 nsresult
   176 nsMathMLmactionFrame::SetInitialChildList(ChildListID     aListID,
   177                                           nsFrameList&    aChildList)
   178 {
   179   nsresult rv = nsMathMLSelectedFrame::SetInitialChildList(aListID, aChildList);
   181   if (!mSelectedFrame) {
   182     mActionType = NS_MATHML_ACTION_TYPE_NONE;
   183   }
   184   else {
   185     // create mouse event listener and register it
   186     mListener = new nsMathMLmactionFrame::MouseListener(this);
   187     // printf("maction:%p registering as mouse event listener ...\n", this);
   188     mContent->AddSystemEventListener(NS_LITERAL_STRING("click"), mListener,
   189                                      false, false);
   190     mContent->AddSystemEventListener(NS_LITERAL_STRING("mouseover"), mListener,
   191                                      false, false);
   192     mContent->AddSystemEventListener(NS_LITERAL_STRING("mouseout"), mListener,
   193                                      false, false);
   194   }
   195   return rv;
   196 }
   198 nsresult
   199 nsMathMLmactionFrame::AttributeChanged(int32_t  aNameSpaceID,
   200                                        nsIAtom* aAttribute,
   201                                        int32_t  aModType)
   202 {
   203   bool needsReflow = false;
   205   if (aAttribute == nsGkAtoms::actiontype_) {
   206     // updating mActionType ...
   207     int32_t oldActionType = mActionType;
   208     mActionType = GetActionType(mContent);
   210     // Initiate a reflow when actiontype classes are different.
   211     if ((oldActionType & NS_MATHML_ACTION_TYPE_CLASS_BITMASK) !=
   212           (mActionType & NS_MATHML_ACTION_TYPE_CLASS_BITMASK)) {
   213       needsReflow = true;
   214     }
   215   } else if (aAttribute == nsGkAtoms::selection_) {
   216     if ((mActionType & NS_MATHML_ACTION_TYPE_CLASS_BITMASK) == 
   217          NS_MATHML_ACTION_TYPE_CLASS_USE_SELECTION) {
   218       needsReflow = true;
   219     }
   220   } else {
   221     // let the base class handle other attribute changes
   222     return 
   223       nsMathMLContainerFrame::AttributeChanged(aNameSpaceID, 
   224                                                aAttribute, aModType);
   225   }
   227   if (needsReflow) {
   228     PresContext()->PresShell()->
   229       FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
   230   }
   232   return NS_OK;
   233 }
   235 // ################################################################
   236 // Event handlers 
   237 // ################################################################
   239 NS_IMPL_ISUPPORTS(nsMathMLmactionFrame::MouseListener,
   240                   nsIDOMEventListener)
   243 // helper to show a msg on the status bar
   244 // curled from nsObjectFrame.cpp ...
   245 void
   246 ShowStatus(nsPresContext* aPresContext, nsString& aStatusMsg)
   247 {
   248   nsCOMPtr<nsIDocShellTreeItem> docShellItem(aPresContext->GetDocShell());
   249   if (docShellItem) {
   250     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   251     docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
   252     if (treeOwner) {
   253       nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
   254       if (browserChrome) {
   255         browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, aStatusMsg.get());
   256       }
   257     }
   258   }
   259 }
   261 NS_IMETHODIMP
   262 nsMathMLmactionFrame::MouseListener::HandleEvent(nsIDOMEvent* aEvent)
   263 {
   264   nsAutoString eventType;
   265   aEvent->GetType(eventType);
   266   if (eventType.EqualsLiteral("mouseover")) {
   267     mOwner->MouseOver();
   268   }
   269   else if (eventType.EqualsLiteral("click")) {
   270     mOwner->MouseClick();
   271   }
   272   else if (eventType.EqualsLiteral("mouseout")) {
   273     mOwner->MouseOut();
   274   }
   275   else {
   276     NS_ABORT();
   277   }
   279   return NS_OK;
   280 }
   282 void
   283 nsMathMLmactionFrame::MouseOver()
   284 {
   285   // see if we should display a status message
   286   if (NS_MATHML_ACTION_TYPE_STATUSLINE == mActionType) {
   287     // retrieve content from a second child if it exists
   288     nsIFrame* childFrame = mFrames.FrameAt(1);
   289     if (!childFrame) return;
   291     nsIContent* content = childFrame->GetContent();
   292     if (!content) return;
   294     // check whether the content is mtext or not
   295     if (content->GetNameSpaceID() == kNameSpaceID_MathML &&
   296         content->Tag() == nsGkAtoms::mtext_) {
   297       // get the text to be displayed
   298       content = content->GetFirstChild();
   299       if (!content) return;
   301       const nsTextFragment* textFrg = content->GetText();
   302       if (!textFrg) return;
   304       nsAutoString text;
   305       textFrg->AppendTo(text);
   306       // collapse whitespaces as listed in REC, section 3.2.6.1
   307       text.CompressWhitespace();
   308       ShowStatus(PresContext(), text);
   309     }
   310   }
   311 }
   313 void
   314 nsMathMLmactionFrame::MouseOut()
   315 {
   316   // see if we should remove the status message
   317   if (NS_MATHML_ACTION_TYPE_STATUSLINE == mActionType) {
   318     nsAutoString value;
   319     value.SetLength(0);
   320     ShowStatus(PresContext(), value);
   321   }
   322 }
   324 void
   325 nsMathMLmactionFrame::MouseClick()
   326 {
   327   if (NS_MATHML_ACTION_TYPE_TOGGLE == mActionType) {
   328     if (mChildCount > 1) {
   329       int32_t selection = (mSelection == mChildCount)? 1 : mSelection + 1;
   330       nsAutoString value;
   331       char cbuf[10];
   332       PR_snprintf(cbuf, sizeof(cbuf), "%d", selection);
   333       value.AssignASCII(cbuf);
   334       bool notify = false; // don't yet notify the document
   335       mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value, notify);
   337       // Now trigger a content-changed reflow...
   338       PresContext()->PresShell()->
   339         FrameNeedsReflow(mSelectedFrame, nsIPresShell::eTreeChange,
   340                          NS_FRAME_IS_DIRTY);
   341     }
   342   }
   343 }

mercurial