Bug 924692 - Part 1: Add touch caret rendering support; r=roc
authorPhoebe Chang <phchang@mozilla.com>
Tue, 03 Jun 2014 15:08:25 +0800
changeset 186263 4a2ec83f83922e91c38eb5ca86f650c464f502d8
parent 186262 04dd691d5f5954f0af1748d9d5940df2246047eb
child 186264 b8d910d939131a48fc3e95bf8e3dcd64a126254b
push id7112
push usercbook@mozilla.com
push dateTue, 03 Jun 2014 12:54:43 +0000
treeherderfx-team@9063b60fe526 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs924692
milestone32.0a1
Bug 924692 - Part 1: Add touch caret rendering support; r=roc
b2g/installer/package-manifest.in
editor/composer/src/moz.build
editor/composer/src/res/text_selection_handle.png
editor/composer/src/res/text_selection_handle@1.5.png
editor/composer/src/res/text_selection_handle@2.png
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/style/ua.css
modules/libpref/src/init/all.js
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -666,16 +666,19 @@
 @BINPATH@/res/table-add-row-before-hover.gif
 @BINPATH@/res/table-add-row-before.gif
 @BINPATH@/res/table-remove-column-active.gif
 @BINPATH@/res/table-remove-column-hover.gif
 @BINPATH@/res/table-remove-column.gif
 @BINPATH@/res/table-remove-row-active.gif
 @BINPATH@/res/table-remove-row-hover.gif
 @BINPATH@/res/table-remove-row.gif
+@BINPATH@/res/text_selection_handle.png
+@BINPATH@/res/text_selection_handle@1.5.png
+@BINPATH@/res/text_selection_handle@2.png
 @BINPATH@/res/grabber.gif
 #ifdef XP_MACOSX
 @BINPATH@/res/cursors/*
 #endif
 @BINPATH@/res/fonts/*
 @BINPATH@/res/dtd/*
 @BINPATH@/res/html/*
 @BINPATH@/res/langGroups.properties
--- a/editor/composer/src/moz.build
+++ b/editor/composer/src/moz.build
@@ -34,9 +34,12 @@ RESOURCE_FILES += [
     'res/table-add-row-before-hover.gif',
     'res/table-add-row-before.gif',
     'res/table-remove-column-active.gif',
     'res/table-remove-column-hover.gif',
     'res/table-remove-column.gif',
     'res/table-remove-row-active.gif',
     'res/table-remove-row-hover.gif',
     'res/table-remove-row.gif',
+    'res/text_selection_handle.png',
+    'res/text_selection_handle@1.5.png',
+    'res/text_selection_handle@2.png',
 ]
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..656854decc593d3ccd8767654f1743fb2523b64e
GIT binary patch
literal 1580
zc$|Gy4NMbf7`{?1D%Saj!@qGJ8^SW$-j)7JZ3`_w&azsV!ZaDzyKAY?-g!N2AqXO|
zj?5q8R%L27j8hSv6VVu%N<bM9LAU78;S33OnrsflE+~+~t|)9-)Gv4UeczksdEWPX
zzb98=Oi$s@STq9w0DfAk&cx31*f(MtFZkX6<6G>skkMx`8Ki}Ap)>(#anekHX?D~~
zm<SXv+|*7a008%0TV@uMWmv7mNV@<HVgznG1q4Te+D)NY9>IWS!fJD<p#C2kA<%}a
zpmh?1$Ur3#xwh0In#d?h&%}!IFa-{&SAq#{B`aVj7!-8d^Bqp5TLq2lD%o`~EQG*u
z2$QFRUKEvOFoH=WO@I=CI1UrRFesG@;CP8t3V#41A{Y^h*hd-%$15dLB_ab~4v5W0
z;})e!m;5ppyHi2A3_~e}LYK=WaES#ZZ56@_g(9edAaN`r&ROVSP<Nce88xAxBb*p*
zqZk|M0E2tfOcpRI2%0#8otl(&IA6AjZJ5xFQbJfD68;BhFuWORw@;#-jES(k8STt0
zqzIvjaFPWy#$KEyDoCc3Ni=~nB%Mi;`4e3<=8_EQ%q1x>DMJdz7*NdS2nJ%u83uzg
z&EaHF2S%jnR1g~x*lf5`s!LSJ^{_;N=o4XBFIH%El0-x<k%<*>q88CkaCIbBU?&{R
z1Q-98D}60DXoeSTg0^iY@MM~_gX4!*+FntMR)$DL$qFs2Cx3M<FSz*YYl(ktEkd>!
z;s36BBE<S9xSTXDyP32;;b8qvv&J4cFOCI(kgwBp+Dv!1IsVG9mlG*J+1XiB`n>F}
ze*N}!n)73IZC8I?J!Pi3>z-@HKE2Ub*S&4&A7J^wiPpS`*%ab`>J^EQvuCfzdP9ct
z@r69v+to1d=hYh$8o-qYYw(?>9`n-T(^zwO`un%KHqtS9448@34cu$!Trl0x8`UkU
z)YjI^VxN2>KZW6FxMod93l@{{+gabxIq5t39vEtk{t1l!ZkKhZ!soriW@_)Hn;Ii~
zc9$qz(BsXu{Z8<i+H+llep~O~C_27(SX<01lWd~0{Rg@a-QG~33-y8XuWAG#tM1l)
z*dE96@RxJv0J(=}9<S|M(9$<`uZY{^;c)kbM%=B}lyzuAa&T<_gL>+5D3aaeDZ8}X
zyDqZ*TGNSU4KHWT{8{_Rs#CL&#Xe-#+BFq9Jem^~CBATFVX8W8p4{v7=ORX+>S7^(
z>--gMB56)hueG`@-m<I;?HDT=8%?gr9xEMv&bbj)9sm4M;9$y^5rcpJ;vWH>8c$%j
z#QzjtwPX;zc`TqAmbIPf|EMUhD=;$nJ691MD0V+;KKb4)0p}}qmG;KS$iV&5oT8zd
zM@S2Q=f-3+fB4yhk^L#1Qw!96_b<)#l~_EM+l}As?%UF`?EB`H6UUD1IMhQe`rF@n
z!TQAkWzXqP&xN&ZnSQObN_&)dCUq!`ez-%mxL=IGTX>6VcpY;#$S)82M(?NW8d|C;
z-yCwWx@}~)X$q%4JS^s5NL@l$V|6XQ*1KX)-T7soSAI54yj*stvA^d^pm^}fKx<(A
zp37DDN`aa_!E80hT*(<b<F$fh`6@mNF5sGt<|!Ym!2xwO#p#t9$;+XNxfc_zhD*WD
sCC2jX!$+^HYaaF+ha(%Jw*p+Ca&A|{+oOLS3;w^;^y#|Oi8<T;0Y<7^EC2ui
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d99b3c93b6c9471deb388c0693250dcbc77fc0dc
GIT binary patch
literal 1899
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
DQ5go@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a7fc3901ae69ac20299ea421aab904807801831e
GIT binary patch
literal 2382
zc$|G!dpMM7A09bo$RxWt8^aQ7%)!hs!-Sck#K^~pB#fCC6Z6i|GC73JM8wx&m(;4r
zDhee{j!_96bk3#~wjxQ$iir6}rSH4G>uR6tec$K#{jU4|J@@l_?mymaKi>`7nueMX
z2t?a!Bh6niTPa?&hMMA=a$aMdVlohW1d9WBQQ`!q5P-O|d659zi_44#`~fCgBIp8K
zAP{9s4kK6`O!pzNcwBqt62?A}%ZDrt7uQ5SlNAey;gLWz2P7lL8!sc^95xvdgr}qF
zd@2yb*|<{(1nl%>uy)3>h-`%Gdbmp>Nl}0ch?($2ZX75gC6W=J>XH=er8Eiw{{#`o
zk`bRp1=IcDRGtuk<Lw=gEHnlKClKs0I6Q%Xv4dmL7%U2{cnC-gj)W(Wu#WIA1EJVW
z$c`fU(>%ZIrHIIg7_pd7LZK2866_Nk?0Ldy6oyD7F4e$dkqQJ-Bmu?DL?kG(Sgt?=
zL@XhPFXr$-_)^S_<i(502*mOcxcskWLD82sDH?`KWb#oMdo=2QfOPslL%H0qXpz_-
zi27%=h#}zvD1Si2ix;vK7Z+u*MCOyILVzje2^l<I+;SKFVt8VnD2B&}Qv(R_b#x|+
z11=?OJ~8NYk{2ivGeH*MMI$2=8G8<gO(M`JL?;gnjfnN2U@#sIM0XmVf_1_>IuJ1w
zcdYv|m&Rkoa{*Ai%w_+V>+wzQk{Ld;0U_rnfbA*dap9j1P2zl83+3BdK6BaM)<XRz
z7o`w``oF7QPAUAewESvZMex=70I2Z0P+{z+xnK$eqT1?3b7v&>UOSu;7Z9k|I{$V)
zrl)SZBcZqMe0rq;E3OqrQPa0@=-ilPg)KEN(st!5zp&VWpl0aOahm$TwXQ|K)%#Z;
zMXXu_!>x+e-zrvq-*#Q)z0$Uh$Kcr9Wbw@7qyq1ei>Yxb*7cI{zLu7mQQ~lMQnyWM
zR%oHyL8#H5lMyYU1qMcZQ=b)jS?AajQ?ZRxwcR+fM)g*lPIxEnT?EWrFJs_=j(kq7
z@?No?)=-X3S<;$8<Fz)%SrZ!suX80Ku+nD}uC}H5NpaIt6F%7|N~<s>NZ@tx&#GEC
zi@Ma0ruKS=e#B|tXIr|u=%QDhdbs0}k9QYYhf!hot8&M&jPex?T0KYME4V91!i!VY
zt^l+Bu!F_Zzeg<|a4M<e54bs1!kYPWBBNZ`z}YmNzzYAU6u)yw-EgS7)>)^(ch~Rd
z>*sAY9QABF<gZ09%AwzoR^VZISMQMfY7Xb*+%c1b(g(=xg3b#gV+MnTdb>68!?dxG
zGRaW)@s?|oYSh8l4TET@raC44#>W#?@Szj8u&4GN$7?SjZ(cZe;XdR1)vP}FIw#of
z()naf&~Y1sQ|r3NFS#@CjQ_BH_@80FU6dcW6@l;YfwUJ9#y1tURLuquwoI{4Ha5SQ
zeiq*shvIY|n;|!e+ssQiE><c=+ADum{$-@0O!CX!AiKR?Yq}ov%VYw2w|#zHf=XDD
zavO$4HM#Q;nbc$mI%e;+fmL&lm!xKMpf2%|P69hKqs&cD>QR9*yXqYk$Nyc^d#U8j
z6t|24i@L7-JmPgp@x`GhRIQtbzYDNSE@95Uu^29fyBA7X3y216>AU>M_4k5LW#vKE
zn{z&NUgqvGK^AO?5v}Om?WH=pFM~K8@1d7Dn8}`coN#e&yfW?nQC-hhh?pyh9)~g=
z3pL~GfBb92c-39^Lym<#Hf-1_t!Bx5aovUL)oAnhnP}+1`^hwlReBEiT{A_=Yc8_Z
zER|tiT0>gU-BKB_MwFLvPB3X8%xEh-js2eMJ*ED9(9@Y}UfXKfM!~{XTyI<Ovv$<~
zTR<LCy7pnKbaMX<+XI%9xI$FxUQk8_(Spt)OZQ#kYP~&UvX^S2_-C)C^FJPFlnqO7
z{iHWv(E?i68?+jgJN?N&9p-Ca=yH)1QvJuqEl~b}p%GhojjyorjWC^9wfzHBFkr5W
zmNk|?cpDd6vA<)~W3pTJvRq)2*4m_^MR#hvJUgr3VAC7gJ&MFHJnC@f7mfXnm$pjJ
zmbb*3w9L&sIW^bRGy2vxN&e&CsZO3X*DVdT+A;IfCe@7AyZ6kH=%<;r)@RD|>Piw=
z`#vP+cGspz4wsJ;LK^yd+w<+BA&>w=85oZvG}j0(zYz4N7i=`3{&7fmG$?nrSLwa?
zS~b<5Il<)UMM|*5AwbvkOtY-0r#iK#?`hvk)ck<{$xZc1t(FbBMou%LwdI@j8PP*_
zg>kp*cY<}YrlzR;souaB6YF~W+t&{vj2G$n2E!<|UGlOA&UgE(y1IUYssOjxZcj$#
zF8!gGb{rdx>d@8#+7~^7UMe-FoIExFHKNKxFNEwOg;e_9@rQOf_+NQsirXF(^d#w}
zNm=!l?7Tr!&DW-D@_G;vg17q?&%32C7|oWgC-QHHu?gJXdMqJn60xQ9k$SD1=p1rn
zyqNf5+pu+G?D2y-5w%;-)js9pCj2xFWT&tEwO94<<{YKf8k?-}=+g}A7p`RQf+Gd?
zg#icZFR73%G+b2vl{iLl_R*L#zO8NY*epL(Iv;Kp#?^>~<h$QUo^hu?lty}ORadvw
z#XZbwpW2kHv(ouw?DMvpsVdHRrP}8r^|}R>K50Ys1}RkKhsSUO+cSZtSNBItCZXH)
zZ>6VX886gXX5POvB|oayZmdepI}=W&S!OHYLuX$ZRGNKn8w_`IYpZ!^tZn6=7FHq0
fo5S|YRrDbvd#9*bW<Mk^{o#0d_|mE<5gGph#aQOF
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -24,16 +24,17 @@
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsTableFrame.h"
 #include "nsTableColFrame.h"
 #include "nsTableRowFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsHTMLParts.h"
+#include "nsPresShell.h"
 #include "nsIPresShell.h"
 #include "nsUnicharUtils.h"
 #include "nsStyleSet.h"
 #include "nsViewManager.h"
 #include "nsStyleConsts.h"
 #include "nsIDOMXULElement.h"
 #include "nsContainerFrame.h"
 #include "nsNameSpaceManager.h"
@@ -2592,16 +2593,22 @@ nsCSSFrameConstructor::ConstructDocEleme
     contentFrame->SetInitialChildList(kPrincipalList, childItems);
   }
 
   // set the primary frame
   aDocElement->SetPrimaryFrame(contentFrame);
 
   SetInitialSingleChild(mDocElementContainingBlock, newFrame);
 
+  // Create touch caret frame if there is a canvas frame
+  if (mDocElementContainingBlock->GetType() == nsGkAtoms::canvasFrame) {
+    ConstructAnonymousContentForCanvas(state, mDocElementContainingBlock,
+                                       aDocElement);
+  }
+
   return newFrame;
 }
 
 
 nsIFrame*
 nsCSSFrameConstructor::ConstructRootFrame()
 {
   AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
@@ -2847,16 +2854,39 @@ nsCSSFrameConstructor::SetUpDocElementCo
   if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     SetInitialSingleChild(viewportFrame, newFrame);
   } else {
     nsFrameList newFrameList(newFrame, newFrame);
     viewportFrame->AppendFrames(kPrincipalList, newFrameList);
   }
 }
 
+void
+nsCSSFrameConstructor::ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
+                                                          nsIFrame* aFrame,
+                                                          nsIContent* aDocElement)
+{
+  NS_ASSERTION(aFrame->GetType() == nsGkAtoms::canvasFrame, "aFrame should be canvas frame!");
+
+  nsAutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> anonymousItems;
+  GetAnonymousContent(aDocElement, aFrame, anonymousItems);
+  if (anonymousItems.IsEmpty()) {
+    // Touch caret is not enabled.
+    return;
+  }
+
+  FrameConstructionItemList itemsToConstruct;
+  nsContainerFrame* frameAsContainer = do_QueryFrame(aFrame);
+  AddFCItemsForAnonymousContent(aState, frameAsContainer, anonymousItems, itemsToConstruct);
+
+  nsFrameItems frameItems;
+  ConstructFramesFromItemList(aState, itemsToConstruct, frameAsContainer, frameItems);
+  frameAsContainer->AppendFrames(kPrincipalList, frameItems);
+}
+
 nsContainerFrame*
 nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell*  aPresShell,
                                           nsPresContext* aPresContext,
                                           nsContainerFrame* aParentFrame,
                                           nsIFrame*      aPrevPageFrame,
                                           nsContainerFrame*& aCanvasFrame)
 {
   nsStyleContext* parentStyleContext = aParentFrame->StyleContext();
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -1764,16 +1764,20 @@ private:
    * style contexts in the undisplayed content map must be non-pseudo
    * contexts and also handles unbinding undisplayed generated content
    * as needed.
    */
   static void SetAsUndisplayedContent(FrameConstructionItemList& aList,
                                       nsIContent* aContent,
                                       nsStyleContext* aStyleContext,
                                       bool aIsGeneratedContent);
+  // Create touch caret frame.
+  void ConstructAnonymousContentForCanvas(nsFrameConstructorState& aState,
+                                          nsIFrame* aFrame,
+                                          nsIContent* aDocElement);
 
 public:
 
   friend class nsFrameConstructorState;
 
 private:
 
   nsIDocument*        mDocument;  // Weak ref
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -48,16 +48,17 @@ class nsDocShell;
 class nsIDocument;
 class nsIFrame;
 class nsPresContext;
 class nsStyleSet;
 class nsViewManager;
 class nsView;
 class nsRenderingContext;
 class nsIPageSequenceFrame;
+class nsCanvasFrame;
 class nsAString;
 class nsCaret;
 class nsFrameSelection;
 class nsFrameManager;
 class nsILayoutHistoryState;
 class nsIReflowCallback;
 class nsIDOMNode;
 class nsIntRegion;
@@ -463,16 +464,22 @@ public:
 
   /**
    * Returns the page sequence frame associated with the frame hierarchy.
    * Returns nullptr if not a paginated view.
    */
   virtual nsIPageSequenceFrame* GetPageSequenceFrame() const = 0;
 
   /**
+  * Returns the canvas frame associated with the frame hierarchy.
+  * Returns nullptr if is XUL document.
+  */
+  virtual nsCanvasFrame* GetCanvasFrame() const = 0;
+
+  /**
    * Gets the real primary frame associated with the content object.
    *
    * In the case of absolutely positioned elements and floated elements,
    * the real primary frame is the frame that is out of the flow and not the
    * placeholder frame.
    */
   virtual nsIFrame* GetRealPrimaryFrameFor(nsIContent* aContent) const = 0;
 
@@ -731,16 +738,21 @@ public:
   /**
    * Notification sent by a frame informing the pres shell that it is about to
    * be destroyed.
    * This allows any outstanding references to the frame to be cleaned up
    */
   virtual void NotifyDestroyingFrame(nsIFrame* aFrame) = 0;
 
   /**
+   * Returns the touch caret element of the presshell.
+   */
+  virtual mozilla::dom::Element* GetTouchCaretElement() const = 0;
+
+  /**
    * Get the caret, if it exists. AddRefs it.
    */
   virtual already_AddRefed<nsCaret> GetCaret() const = 0;
 
   /**
    * Invalidate the caret's current position if it's outside of its frame's
    * boundaries. This function is useful if you're batching selection
    * notifications and might remove the caret's frame out from under it.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -696,16 +696,28 @@ nsIPresShell::FrameSelection()
   return ret.forget();
 }
 
 //----------------------------------------------------------------------
 
 static bool sSynthMouseMove = true;
 static uint32_t sNextPresShellId;
 static bool sPointerEventEnabled = true;
+static bool sTouchCaretEnabled = false;
+
+/* static */ bool
+PresShell::TouchCaretPrefEnabled()
+{
+  static bool initialized = false;
+  if (!initialized) {
+    Preferences::AddBoolVarCache(&sTouchCaretEnabled, "touchcaret.enabled");
+    initialized = true;
+  }
+  return sTouchCaretEnabled;
+}
 
 PresShell::PresShell()
   : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
 {
   mSelection = nullptr;
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
@@ -2467,16 +2479,29 @@ nsIPresShell::GetRootScrollFrameAsScroll
 
 nsIPageSequenceFrame*
 PresShell::GetPageSequenceFrame() const
 {
   nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame();
   return do_QueryFrame(frame);
 }
 
+nsCanvasFrame*
+PresShell::GetCanvasFrame() const
+{
+  nsIFrame* frame = mFrameConstructor->GetDocElementContainingBlock();
+  return do_QueryFrame(frame);
+}
+
+Element*
+PresShell::GetTouchCaretElement() const
+{
+  return GetCanvasFrame() ? GetCanvasFrame()->GetTouchCaretElement() : nullptr;
+}
+
 void
 PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
 {
 #ifdef DEBUG
   mUpdateCount++;
 #endif
   mFrameConstructor->BeginUpdate();
 
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -62,16 +62,19 @@ class PresShell : public nsIPresShell,
 public:
   PresShell();
 
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
   // nsISupports
   NS_DECL_ISUPPORTS
 
+  // Touch caret preference
+  static bool TouchCaretPrefEnabled();
+
   void Init(nsIDocument* aDocument, nsPresContext* aPresContext,
             nsViewManager* aViewManager, nsStyleSet* aStyleSet,
             nsCompatibility aCompatMode);
   virtual void Destroy() MOZ_OVERRIDE;
   virtual void MakeZombie() MOZ_OVERRIDE;
 
   virtual nsresult SetPreferenceStyleRules(bool aForceReflow) MOZ_OVERRIDE;
 
@@ -85,16 +88,17 @@ public:
   NS_IMETHOD RepaintSelection(SelectionType aType) MOZ_OVERRIDE;
 
   virtual void BeginObservingDocument() MOZ_OVERRIDE;
   virtual void EndObservingDocument() MOZ_OVERRIDE;
   virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) MOZ_OVERRIDE;
   virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight) MOZ_OVERRIDE;
   virtual nsresult ResizeReflowOverride(nscoord aWidth, nscoord aHeight) MOZ_OVERRIDE;
   virtual nsIPageSequenceFrame* GetPageSequenceFrame() const MOZ_OVERRIDE;
+  virtual nsCanvasFrame* GetCanvasFrame() const MOZ_OVERRIDE;
   virtual nsIFrame* GetRealPrimaryFrameFor(nsIContent* aContent) const MOZ_OVERRIDE;
 
   virtual nsIFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const MOZ_OVERRIDE;
   virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
                                             nsFrameState aBitToAdd) MOZ_OVERRIDE;
   virtual void FrameNeedsToContinueReflow(nsIFrame *aFrame) MOZ_OVERRIDE;
   virtual void CancelAllPendingReflows() MOZ_OVERRIDE;
   virtual bool IsSafeToFlush() const MOZ_OVERRIDE;
@@ -202,16 +206,18 @@ public:
   virtual void WillPaintWindow() MOZ_OVERRIDE;
   virtual void DidPaintWindow() MOZ_OVERRIDE;
   virtual void ScheduleViewManagerFlush(PaintType aType = PAINT_DEFAULT) MOZ_OVERRIDE;
   virtual void DispatchSynthMouseMove(mozilla::WidgetGUIEvent* aEvent,
                                       bool aFlushOnHoverChange) MOZ_OVERRIDE;
   virtual void ClearMouseCaptureOnView(nsView* aView) MOZ_OVERRIDE;
   virtual bool IsVisible() MOZ_OVERRIDE;
 
+  // touch caret
+  virtual mozilla::dom::Element* GetTouchCaretElement() const MOZ_OVERRIDE;
   // caret handling
   virtual already_AddRefed<nsCaret> GetCaret() const MOZ_OVERRIDE;
   virtual void MaybeInvalidateCaretPosition() MOZ_OVERRIDE;
   NS_IMETHOD SetCaretEnabled(bool aInEnable) MOZ_OVERRIDE;
   NS_IMETHOD SetCaretReadOnly(bool aReadOnly) MOZ_OVERRIDE;
   NS_IMETHOD GetCaretEnabled(bool *aOutEnabled) MOZ_OVERRIDE;
   NS_IMETHOD SetCaretVisibilityDuringSelection(bool aVisibility) MOZ_OVERRIDE;
   NS_IMETHOD GetCaretVisible(bool *_retval) MOZ_OVERRIDE;
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -7,22 +7,27 @@
 
 #include "nsCanvasFrame.h"
 #include "nsContainerFrame.h"
 #include "nsCSSRendering.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsRenderingContext.h"
 #include "nsGkAtoms.h"
+#include "nsPresShell.h"
 #include "nsIPresShell.h"
 #include "nsDisplayList.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsFrameManager.h"
 #include "gfxPlatform.h"
-
+// for touchcaret
+#include "nsContentList.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsContentUtils.h"
+#include "nsStyleSet.h"
 // for focus
 #include "nsIScrollableFrame.h"
 #ifdef DEBUG_CANVAS_FOCUS
 #include "nsIDocShell.h"
 #endif
 
 //#define DEBUG_CANVAS_FOCUS
 
@@ -35,27 +40,73 @@ NS_NewCanvasFrame(nsIPresShell* aPresShe
 {
   return new (aPresShell) nsCanvasFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame)
 
 NS_QUERYFRAME_HEAD(nsCanvasFrame)
   NS_QUERYFRAME_ENTRY(nsCanvasFrame)
+  NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
+nsresult
+nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
+{
+  // We won't create touch caret element if preference is not enabled.
+  if (!PresShell::TouchCaretPrefEnabled()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDocument> doc = mContent->OwnerDoc();
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+
+  // Create and append touch caret frame.
+  nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nullptr,
+                                                 kNameSpaceID_XHTML,
+                                                 nsIDOMNode::ELEMENT_NODE);
+  NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
+
+  nsresult rv = NS_NewHTMLElement(getter_AddRefs(mTouchCaretElement), nodeInfo.forget(),
+                                mozilla::dom::NOT_FROM_PARSER);
+  NS_ENSURE_SUCCESS(rv, rv);
+  aElements.AppendElement(mTouchCaretElement);
+
+  // Add a _moz_anonclass attribute as touch caret selector.
+  ErrorResult er;
+  mTouchCaretElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
+                                   NS_LITERAL_STRING("mozTouchCaret"), er);
+  NS_ENSURE_SUCCESS(er.ErrorCode(), er.ErrorCode());
+
+  // Set touch caret to visibility: hidden by default.
+  nsAutoString classValue;
+  classValue.AppendLiteral("moz-touchcaret hidden");
+  rv = mTouchCaretElement->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
+                                   classValue, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+void
+nsCanvasFrame::AppendAnonymousContentTo(nsBaseContentList& aElements, uint32_t aFilter)
+{
+  aElements.MaybeAppendElement(mTouchCaretElement);
+}
+
 void
 nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsIScrollableFrame* sf =
     PresContext()->GetPresShell()->GetRootScrollFrameAsScrollable();
   if (sf) {
     sf->RemoveScrollPositionListener(this);
   }
 
+  nsContentUtils::DestroyAnonymousContent(&mTouchCaretElement);
   nsContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 void
 nsCanvasFrame::ScrollPositionWillChange(nscoord aX, nscoord aY)
 {
   if (mDoPaintFocus) {
     mDoPaintFocus = false;
@@ -93,19 +144,24 @@ nsCanvasFrame::SetInitialChildList(Child
   nsContainerFrame::SetInitialChildList(aListID, aChildList);
 }
 
 void
 nsCanvasFrame::AppendFrames(ChildListID     aListID,
                             nsFrameList&    aFrameList)
 {
   MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
-  MOZ_ASSERT(mFrames.IsEmpty(), "already have a child frame");
-  MOZ_ASSERT(aFrameList.FirstChild() == aFrameList.LastChild(),
-             "Only one principal child frame allowed");
+  if (!mFrames.IsEmpty()) {
+    for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
+      // We only allow native anonymous child frame for touch caret,
+      // which its placeholder is added to the Principal child lists.
+      MOZ_ASSERT(e.get()->GetContent()->IsInNativeAnonymousSubtree(),
+                 "invalid child list");
+    }
+  }
   nsFrame::VerifyDirtyBitSet(aFrameList);
   nsContainerFrame::AppendFrames(aListID, aFrameList);
 }
 
 void
 nsCanvasFrame::InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList)
@@ -116,17 +172,16 @@ nsCanvasFrame::InsertFrames(ChildListID 
   AppendFrames(aListID, aFrameList);
 }
 
 void
 nsCanvasFrame::RemoveFrame(ChildListID     aListID,
                            nsIFrame*       aOldFrame)
 {
   MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
-  MOZ_ASSERT(aOldFrame == mFrames.FirstChild(), "unknown aOldFrame");
   nsContainerFrame::RemoveFrame(aListID, aOldFrame);
 }
 #endif
 
 nsRect nsCanvasFrame::CanvasArea() const
 {
   // Not clear which overflow rect we want here, but it probably doesn't
   // matter.
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -8,29 +8,31 @@
 #ifndef nsCanvasFrame_h___
 #define nsCanvasFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "nsContainerFrame.h"
 #include "nsIScrollPositionListener.h"
 #include "nsDisplayList.h"
+#include "nsIAnonymousContentCreator.h"
 
 class nsPresContext;
 class nsRenderingContext;
 
 /**
  * Root frame class.
  *
  * The root frame is the parent frame for the document element's frame.
  * It only supports having a single child frame which must be an area
  * frame
  */
 class nsCanvasFrame : public nsContainerFrame,
-                      public nsIScrollPositionListener
+                      public nsIScrollPositionListener,
+                      public nsIAnonymousContentCreator
 {
 public:
   nsCanvasFrame(nsStyleContext* aContext)
   : nsContainerFrame(aContext),
     mDoPaintFocus(false),
     mAddedScrollPositionListener(false) {}
 
   NS_DECL_QUERYFRAME_TARGET(nsCanvasFrame)
@@ -59,16 +61,26 @@ public:
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus) MOZ_OVERRIDE;
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
              ~(nsIFrame::eCanContainOverflowContainers));
   }
 
+  // nsIAnonymousContentCreator
+  virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
+  virtual void AppendAnonymousContentTo(nsBaseContentList& aElements, uint32_t aFilter) MOZ_OVERRIDE;
+
+  // Touch caret handle function
+  mozilla::dom::Element* GetTouchCaretElement() const
+  {
+     return mTouchCaretElement;
+  }
+
   /** SetHasFocus tells the CanvasFrame to draw with focus ring
    *  @param aHasFocus true to show focus ring, false to hide it
    */
   NS_IMETHOD SetHasFocus(bool aHasFocus);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
@@ -106,16 +118,18 @@ public:
                                       nsIContent** aContent) MOZ_OVERRIDE;
 
   nsRect CanvasArea() const;
 
 protected:
   // Data members
   bool                      mDoPaintFocus;
   bool                      mAddedScrollPositionListener;
+
+  nsCOMPtr<mozilla::dom::Element> mTouchCaretElement;
 };
 
 /**
  * Override nsDisplayBackground methods so that we pass aBGClipRect to
  * PaintBackground, covering the whole overflow area.
  * We can also paint an "extra background color" behind the normal
  * background.
  */
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -278,8 +278,46 @@ parsererror|sourcetext {
   white-space: pre;
   font-family: -moz-fixed;
   margin-top: 2em;
   margin-bottom: 1em;
   color: red;
   font-weight: bold;
   font-size: 12pt;
 }
+
+div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+  background-image: url("resource://gre/res/text_selection_handle.png");
+  position: absolute;
+  width: 19px;
+  height: 24px;
+  margin-left: -10px;
+  background-position: center center;
+  z-index: 2147483647;
+}
+
+@media (min-resolution: 1.5dppx) {
+  div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+    background-image: url("resource://gre/res/text_selection_handle@1.5.png");
+    position: absolute;
+    width: 29px;
+    height: 36px;
+    margin-left: -15px;
+    background-position: center center;
+    z-index: 2147483647;
+  }
+}
+
+@media (min-resolution: 2dppx) {
+  div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+    background-image: url("resource://gre/res/text_selection_handle@2.png");
+    position: absolute;
+    width: 38px;
+    height: 48px;
+    margin-left: -19px;
+    background-position: center center;
+    z-index: 2147483647;
+  }
+}
+
+div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret.hidden {
+  visibility: hidden;
+}
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -2082,17 +2082,17 @@ pref("svg.marker-improvements.enabled", 
 #endif
 
 #ifdef RELEASE_BUILD
 pref("svg.svg-iframe.enabled", false);
 #else
 pref("svg.svg-iframe.enabled", false);
 #endif
 
-// Is support for the new getBBox method from SVG 2 enabled?  
+// Is support for the new getBBox method from SVG 2 enabled?
 // See https://svgwg.org/svg2-draft/single-page.html#types-SVGBoundingBoxOptions
 #ifdef RELEASE_BUILD
 pref("svg.new-getBBox.enabled", false);
 #else
 pref("svg.new-getBBox.enabled", true);
 #endif
 
 // Default font types and sizes by locale
@@ -4143,16 +4143,19 @@ pref("urlclassifier.malware_table", "goo
 pref("urlclassifier.phish_table", "goog-phish-shavar,test-phish-simple");
 pref("urlclassifier.downloadBlockTable", "");
 pref("urlclassifier.downloadAllowTable", "");
 pref("urlclassifier.disallow_completions", "test-malware-simple,test-phish-simple,goog-downloadwhite-digest256");
 
 // Turn off Spatial navigation by default.
 pref("snav.enabled", false);
 
+// Turn off touch caret by default.
+pref("touchcaret.enabled", false);
+
 // Wakelock is disabled by default.
 pref("dom.wakelock.enabled", false);
 
 // The URL of the Firefox Accounts auth server backend
 pref("identity.fxaccounts.auth.uri", "https://api.accounts.firefox.com/v1");
 
 // disable mozsample size for now
 pref("image.mozsamplesize.enabled", false);