From a160cc3e5841560214340a6aec0cb090a1232d98 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Thu, 23 Jul 2015 20:37:17 -0700 Subject: [PATCH 01/90] Bug 1187022 - Add hover tooltip for tracking protection shield icon;r=MattN --HG-- extra : commitid : KxZ3gqOI83Z --- .../content/browser-trackingprotection.js | 37 ++++++++++++------- .../test/general/browser_trackingUI_1.js | 5 +++ .../en-US/chrome/browser/browser.properties | 3 ++ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/browser/base/content/browser-trackingprotection.js b/browser/base/content/browser-trackingprotection.js index 933c60dd73c0..2d97dc858869 100644 --- a/browser/base/content/browser-trackingprotection.js +++ b/browser/base/content/browser-trackingprotection.js @@ -8,6 +8,11 @@ let TrackingProtection = { PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled", enabledGlobally: false, enabledInPrivateWindows: false, + container: null, + content: null, + icon: null, + activeTooltipText: null, + disabledTooltipText: null, init() { let $ = selector => document.querySelector(selector); @@ -19,6 +24,11 @@ let TrackingProtection = { Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this, false); Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this, false); + this.activeTooltipText = + gNavigatorBundle.getString("trackingProtection.icon.activeTooltip"); + this.disabledTooltipText = + gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip"); + this.enabledHistogram.add(this.enabledGlobally); }, @@ -66,21 +76,14 @@ let TrackingProtection = { this.icon.setAttribute("animate", "true"); } - let { - STATE_BLOCKED_TRACKING_CONTENT, STATE_LOADED_TRACKING_CONTENT - } = Ci.nsIWebProgressListener; + let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT; + let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT; - for (let element of [this.icon, this.content]) { - if (state & STATE_BLOCKED_TRACKING_CONTENT) { - element.setAttribute("state", "blocked-tracking-content"); - } else if (state & STATE_LOADED_TRACKING_CONTENT) { - element.setAttribute("state", "loaded-tracking-content"); - } else { - element.removeAttribute("state"); - } - } + if (isBlocking) { + this.icon.setAttribute("tooltiptext", this.activeTooltipText); + this.icon.setAttribute("state", "blocked-tracking-content"); + this.content.setAttribute("state", "blocked-tracking-content"); - if (state & STATE_BLOCKED_TRACKING_CONTENT) { // Open the tracking protection introduction panel, if applicable. let introCount = gPrefService.getIntPref("privacy.trackingprotection.introCount"); if (introCount < TrackingProtection.MAX_INTROS) { @@ -88,6 +91,14 @@ let TrackingProtection = { gPrefService.savePrefFile(null); this.showIntroPanel(); } + } else if (isAllowing) { + this.icon.setAttribute("tooltiptext", this.disabledTooltipText); + this.icon.setAttribute("state", "loaded-tracking-content"); + this.content.setAttribute("state", "loaded-tracking-content"); + } else { + this.icon.removeAttribute("tooltiptext"); + this.icon.removeAttribute("state"); + this.content.removeAttribute("state"); } // Telemetry for state change. diff --git a/browser/base/content/test/general/browser_trackingUI_1.js b/browser/base/content/test/general/browser_trackingUI_1.js index 370ac1e51591..d17f2733e785 100644 --- a/browser/base/content/test/general/browser_trackingUI_1.js +++ b/browser/base/content/test/general/browser_trackingUI_1.js @@ -46,6 +46,7 @@ function testBenignPage() { ok(!TrackingProtection.container.hidden, "The container is visible"); ok(!TrackingProtection.content.hasAttribute("state"), "content: no state"); ok(!TrackingProtection.icon.hasAttribute("state"), "icon: no state"); + ok(!TrackingProtection.icon.hasAttribute("tooltiptext"), "icon: no tooltip"); ok(hidden("#tracking-protection-icon"), "icon is hidden"); ok(hidden("#tracking-action-block"), "blockButton is hidden"); @@ -64,6 +65,8 @@ function testTrackingPage(window) { 'content: state="blocked-tracking-content"'); is(TrackingProtection.icon.getAttribute("state"), "blocked-tracking-content", 'icon: state="blocked-tracking-content"'); + is(TrackingProtection.icon.getAttribute("tooltiptext"), + gNavigatorBundle.getString("trackingProtection.icon.activeTooltip"), "correct tooltip"); ok(!hidden("#tracking-protection-icon"), "icon is visible"); ok(hidden("#tracking-action-block"), "blockButton is hidden"); @@ -90,6 +93,8 @@ function testTrackingPageUnblocked() { 'content: state="loaded-tracking-content"'); is(TrackingProtection.icon.getAttribute("state"), "loaded-tracking-content", 'icon: state="loaded-tracking-content"'); + is(TrackingProtection.icon.getAttribute("tooltiptext"), + gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip"), "correct tooltip"); ok(!hidden("#tracking-protection-icon"), "icon is visible"); ok(!hidden("#tracking-action-block"), "blockButton is visible"); diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index 766446fac755..1c27c2f8e6c3 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -343,6 +343,9 @@ trackingProtection.intro.description=When the shield is visible, that means Fire trackingProtection.intro.step1of3=1 of 3 trackingProtection.intro.nextButton.label=Next +trackingProtection.icon.activeTooltip=Tracking attempts blocked +trackingProtection.icon.disabledTooltip=Tracking content detected + # Edit Bookmark UI editBookmarkPanel.pageBookmarkedTitle=Page Bookmarked editBookmarkPanel.pageBookmarkedDescription=%S will always remember this page for you. From 29945a04cf66fa885ff67d462acf2892c572a2e5 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Thu, 23 Jul 2015 20:54:48 -0700 Subject: [PATCH 02/90] Bug 1181541 - Convert branding identity icons for internal pages to SVG. r=ttaubert --HG-- extra : commitid : geLylL1pjO extra : rebase_source : 1d820693803f9e6903d357d62ed001c5e8ce0c5b --- .../aurora/content/identity-icons-brand.png | Bin 1531 -> 0 bytes .../aurora/content/identity-icons-brand.svg | 13 +++++++++++++ .../aurora/content/identity-icons-brand@2x.png | Bin 3397 -> 0 bytes browser/branding/aurora/content/jar.mn | 3 +-- .../nightly/content/identity-icons-brand.png | Bin 1624 -> 0 bytes .../nightly/content/identity-icons-brand.svg | 13 +++++++++++++ .../nightly/content/identity-icons-brand@2x.png | Bin 4283 -> 0 bytes browser/branding/nightly/content/jar.mn | 3 +-- .../official/content/identity-icons-brand.png | Bin 1351 -> 0 bytes .../official/content/identity-icons-brand.svg | 13 +++++++++++++ .../official/content/identity-icons-brand@2x.png | Bin 3178 -> 0 bytes browser/branding/official/content/jar.mn | 3 +-- .../unofficial/content/identity-icons-brand.png | Bin 1624 -> 0 bytes .../unofficial/content/identity-icons-brand.svg | 13 +++++++++++++ .../content/identity-icons-brand@2x.png | Bin 4283 -> 0 bytes browser/branding/unofficial/content/jar.mn | 3 +-- .../shared/identity-block/identity-block.inc.css | 10 +--------- 17 files changed, 57 insertions(+), 17 deletions(-) delete mode 100644 browser/branding/aurora/content/identity-icons-brand.png create mode 100644 browser/branding/aurora/content/identity-icons-brand.svg delete mode 100644 browser/branding/aurora/content/identity-icons-brand@2x.png delete mode 100644 browser/branding/nightly/content/identity-icons-brand.png create mode 100644 browser/branding/nightly/content/identity-icons-brand.svg delete mode 100644 browser/branding/nightly/content/identity-icons-brand@2x.png delete mode 100644 browser/branding/official/content/identity-icons-brand.png create mode 100644 browser/branding/official/content/identity-icons-brand.svg delete mode 100644 browser/branding/official/content/identity-icons-brand@2x.png delete mode 100644 browser/branding/unofficial/content/identity-icons-brand.png create mode 100644 browser/branding/unofficial/content/identity-icons-brand.svg delete mode 100644 browser/branding/unofficial/content/identity-icons-brand@2x.png diff --git a/browser/branding/aurora/content/identity-icons-brand.png b/browser/branding/aurora/content/identity-icons-brand.png deleted file mode 100644 index bcad78dce9c3114a14280c969829ec397482420e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1531 zcmV-u_}aU1>_V&VA-YG zfK{qOrJR!81r|_P5td7+STVK*7FbpmFg2~Bef_@8Of#8c{YR2dc=P+cm-l`vO`9BU>cPwBw*n$Jgmd4l|!^a2%?1Yh^g{Len8?%1N#3B%b zd0zYI+^b#VvH3qg?to{k4#eW~+Kg|pg@^=;7J~&?dCQuX?31fy2eT`C4rMDRDB2E@ z*W`N0v@6*{%>Prsxm&|-Fc0$KBpe4V5S{@D0fvt*{L-Bw~_Kt{o1=xHntMh$N*0?5AURk|cuD-lWuFg9kSM_`;R}fCPTxr}Pt4%`x zcfj)B0y69M<}d_%Smm$_%wQ&Lf-)ei^B@9-%55H*nR91+IHzOmD+=u@{13}*el$C$ z)o7d3KDG_9N+2d3<3Hp!J)%X3Fu%w-t4$IrRgP|x)}5vHN-LX#q_y!&v)Y$?WHqny zm)<;tSkvcH1)+9JtCWse9kd8DQvs)I2NwVlSPk=m;fdtsw}NTUpVJzb$y-MW-?uHs z0I;Wbhh?4JGMd2Uvs;WiXq^6%-kG<2_or77zRj8SM>b??Jn6OqYmfwGRDaLq12Sq4 z)10Y*=qg^qKGEHlYOw}5R&>5}q3cGj)%wQ&BDmIse>nU_k`=70r z?mBaw2nDAp%IWq32Bv}wVz+57Fs-r>*Ke8%IHu^+01-$AF)%y_;4GW31-h_lry57J zv5g~yFRpP!cK)`(hPT(v5IYR#X&z%VbS&my5SVhkd;94!!nZY5S?DBfci{FqOh+uv zFI8De^MNT9o%C5S6%bzj`+Xohmp}rHfGe+0KhT9)MKl;59&0cVPGp1OT8zf9g8lWy zAOeeMjbS~n-yj`}`4{;mmFWT!O9;m|xuV81?WQ05>sx|3%vhCnBZTYYpIG{cjx`mq zx9H(LAUrCV0dwGeumn3e#_Q7!w1Da1b@~Tkb$Y@%Sf{T`)(lIc>xUf<-OvXlGz{Au zy{UIZJC5svF+FrF=C|7%SJLlus)%ql#h0}$%V^%>nx@&{ouvHKIlbv^&(mu6wTX%g zTpx_-qhn141Q$H`4v4^C@B-Sw0~qMw*MiFp@Gf+xgt&xOShG& zfQ=XLiJ=LIfD*zX1;%;t2JisWTR1~AY_mn7Yx7m;2;WwvuJ$9w2b-Sdi!I!+X>Y50NiUhighxql-{NNi~W%+WD?KqkLK$oG0HE{cRpB5`Z2du-f0eDP!GM(4b^ZO zoPl{6dM9FT=x41i?Tc7Z+}q?*)T?tX?(IRl-o2zx=5xK@OZYLzD?$WTlJpkGg;Av$ zc1H^C+8(}Yu>JaKAKD#ukwt}zVpQAMk2x{_WA3%$?gmT)D~fGT0W;y^h1fHH7A$~8 h6x)6SrgDqt`~xH4*BZ!KSgim6002ovPDHLkV1j5s-sJ!Q diff --git a/browser/branding/aurora/content/identity-icons-brand.svg b/browser/branding/aurora/content/identity-icons-brand.svg new file mode 100644 index 000000000000..b4bfe3987414 --- /dev/null +++ b/browser/branding/aurora/content/identity-icons-brand.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/browser/branding/aurora/content/identity-icons-brand@2x.png b/browser/branding/aurora/content/identity-icons-brand@2x.png deleted file mode 100644 index 3ee34b01b8e8ae5718994cc36d6879e32ff79c1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3397 zcmV-L4Z8A)P)DvAeIv1(gw)hb%gf4%WU!3v6kKmuqLXzKwe zXCNlwKEfr42wpurI0E4mwSPxZ-v9eL%S>E1$x?CV|DS1QK9kMc-+P&PZ}(lh|N7TI zpMO4lKEb&)?LZgwp(7Z=dkjM+O`nNr*Vg|(KzKt348Ryn!5juM%$YP}CPwF7Rl>*M z3aL;D&l#0W8a+4i9aMaK=ydVMqbZ>!jox85A7_CQUNGo!7CncUPiQQYr(GLW{Cm)M zUVwbr%7EmH8v+xGzYmnvZwZt(QS_Lm(Q^&~@}-FF!{lk3hB%v3GZnId@I+&$wn63V z&@1~wapQuEHy;-O;i-V;VeSf@zftM!7#+aG(LZDJhJb`STLPqn4;oAJ(7a3;t-BCT zXIC3C-|s;P5XM8ufSb^)lCDlLbZu=n^Gi`f7yA8kVSV>=#f_ooN*W2H9CG0Z}e(OtkgCIuT`c2R&Yu;4fF&!?(=wG6;rkV8)~kf+1i7{{f;!HTXa~9u3ewr09`j zNKxYk92?+!RmhFTi%2^dQrIvGX+7{g4s1iNH`wFcGay>jqMS3qc{QDBqiSh@&P#-; zYnBO<58$}xa$(YzRl)@ESHk4LPlP#(kT&I0VfHt6!mKash4PIXgp%hQg=iQJ)(fSN zP)^JsVNri(e9&AEewoTF_!YXc(uY7QD8ZCTGlb4C0G7accn*X^ICRs}0G)zvH0Hy- z;DUN{{5FEFR8V2Vc%)}RP0;m*L3F?kx>nx_K+y+$CduomXez;8&6|WUY8)gdRwn+QHMtIe7j45^=saTxMd~ zl0a8o_j9J8zR&6FkD7tN4Uj=0NT8Oc|5(_totf>lQ|Y$oSfNMz{4>|;ha)bIDT6ID z=xVJI*WgUMA6r45?OMMp%|KT9Nq=ANC(HfTPx>pqbDaDnk7)WrL5dGE+tFbfjdol5 zU_|@;$%33Yh?mn?wv~ReqM^d;^iF8cS$UqRmBWE(@DhypbY+O!&cw6JSfOsfJylRY zA>djA(ctBot99lo(@hrkgGFO*%{C*<~#7O+JeAT{tW4NV38jh!*}Z6Q)C7O^tx_>p1e~ zs_XxS`E_=_1@%M|zk>Ro1o?GK1o`y~5I=;gOJVMcj)-yQD5H>ebsP;~IL$Z1X~oHS zqRAp3nb_VpZPy&%l=ahnGse??oujPw&}*JgvXGsB*~u$+ajrLKg&j()I18i|0=3-< zhzVomX#xX|O6%yAUw`pLem&s}@gZDSvq~cvA|{rVuPHFEw!3OK#9X-_eeNww_}VL; z@U_TW8b!MvHDd~GguaN$VC8!`LQr7!#u{OttlR{efbdiVy|gs|V*0{!R^EQ>?&oA) zt%XNkT@w&Kj^@?fLY~1I?ts5m&4?L^_!p{qy^*HcebMe`oNt!hmnY(00^wt^m-zm8 z->gs6+yS~wSM)y0osak?)w~mYIe@n5PK*vx3;Ug84XSUA*XJ+drqALj=LYusk^OOhDT1_Qq?;LmC@DS zD?zx(Q$%=ZLhM-!LE&J!X5gAu(ngtkLb}n;D`^#uCpjLEf1p~%H1Cu>Z`?Us#iiju zcnIS&2qVr6o`65xW|a}osxSkW>{`+O>{_A?;$oToA016A=p#9`mWY3f_@54B*Z!tj z27V{e|5T~459fM{GaZk`5^WHdf%pNM7FP7?p5UE6Wx+Agv)RWb;`yF&WvXR3c#5ym zb;fI%HpV@?1VoES@Zh_$MeI>E!18mEvPTi7GP1M<%QT;pOj8Elg-d3QM@0s;ijQ+mN>gj6A z%3(Et=?ss!YqO8U5OwU`MdgSaJ4kTdSj*Mlewgo7x+XBTJ(0GWtE`#saV2jwz{;q5 zxj-~{0w3|Y@)7qfI6y}=Ww9He)5bJq;f6FN(ctN!%xX(!!PQP>m$U=3F3@S||2L;A z*KJ8xE;*T9-IuGZO=(Kn03B5uVA>C{cV`@qBI?*3j(%q4o$bIZxOA9-mhO0VqjyBh zrW@`5r?|)OoOo2aX^7voIb3Dozi0!PzE)|=BK`;mqQz~nW#aYVGdK@Ia7X#s`0vcIqC9Lu!8uBk^&w|#aRyi$C zt|EM_NUo~F_hVMtotCkI-cc))t5VeEUz<|3i8Tu{8si~#oqQ;Q@G;3XvTpLB$Uk3C zi@L|Gkm+5}XM$Tyfx7%Q?h=nTWDB#BQl-C|JWuzfD@|GJ0KH)+GN+AqiD(AW8siQ| z){k);BUJDf-tsL3x; zw-dTprnvUGOhL4Gyhx^KMC{G45)@urQmguLY|eH3GC>i{m48WsB89yb(Q?(=9E`d< z_P}MLS;U|4)W#+9-e|YD3qw!HCo*F|d!`&ZKA2d$isHEPk2x4!Kv&3|+tM@7-E{(@ zMIo4}8-Q`HEA)g?j=V(>qox7$zDTItHczS`n#`9fO1@968cSzH%o8tNm5SHflv34e zYigC{XHrE4N8VctWD2S30IbpoU98;1UZeM2BASdk5b=k_2{~P0*)q?84OA-L$l`eB zh#_8C3r6jasNu+a|6`ZvTsrOLth}i|-_eKrK(u%XV(71uR}aR)U8v*8^8}88zq;w8 zTc*-@mZYN8UQ$7{csWN}k+dqQay0VM2Q7vka;5RoM8&Mxl8Qf2MgvElr=LkH{2inf z!F1-tHGLf9lW%FY@3PWrZ#dE7)rbR;`4-307PdT;ALv^!Y^ZzE`Vspsms{<-^!Uv@ zm!1tj7#lI%B|4VQoYYPsCxzU00MZI&Pz;UmN<-WwsDa5E=J0xsQpK`q;tImoba92k zPF!&t$B*Hax;XnQ6>*5ITPRh`(eO~l$ihvsd)V$U!rPwknqhk{Js7q-{7?LDRu^Zv zKQa@sjVPbqJ)Jbp<86a(odWU>{K#Vk+i`k)`7e{>%1K*8x##Hst?q3JW^QjXcz?8H zh;tZeYlHVkN$9St*0&|B&)n1p5s)_00BeEIb77tR=~W+0iYrSPCn_UtVZ5lU(N0{x z!yhjjXnQ#S*V8SZe2am5BJu|A3?*%1SJ=~mE^#LZ2#Wf=u?wp1GxBta9{2)z3ojuJ zy0!9k6y1Y(JUUTSc6LlmDR~PoZDUKbS0^e4sLqslyd7bHMi^|qH%er_<05$rugsk< zmGt+NPi58!?OXkB&hS$ui=YNbD^x-RTnCG{c_--8__EcbVoK{iMuqZ)c%@BjX}oo8 z>CHJ;%5CVD#ou^0h(6~v>E|LoWVR!;(QNxg!rP9}`hL!rv&?pe-!ng)IG@?F`1>!3 zSp*b!gH!Mv2oDdzA3kh@x8n4d$rR?+F=f9Dk1BluM4J&&rR9hZ`CL-b|83roW5$H{ z&5veI>f;Am$r6A-Pog;pb8)XzPQKCf!B?QKgYc3qqH3WU{Etaeb1a2j7>m zc)le^H`;pk^GKV~dw10N-p-M6raQw6OtyvAnQjkzV7lvaDoyLXCnmU$%azUMUb$Ax z%UB)W>dOBgd_h-->B|jNUeN8t9CvufFXy&2L|3}iz%0Vdm{n~r=)tUr>4u!{Kd)2& bpM3rczs0U6Ci_j*00000NkvXXu0mjfqF0+( diff --git a/browser/branding/aurora/content/jar.mn b/browser/branding/aurora/content/jar.mn index 89cb85abc809..5fc46bc9294a 100644 --- a/browser/branding/aurora/content/jar.mn +++ b/browser/branding/aurora/content/jar.mn @@ -14,7 +14,6 @@ browser.jar: content/branding/icon16.png (../default16.png) content/branding/icon32.png (../default32.png) content/branding/icon128.png (../mozicon128.png) - content/branding/identity-icons-brand.png (identity-icons-brand.png) - content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png) + content/branding/identity-icons-brand.svg (identity-icons-brand.svg) content/branding/silhouette-40.svg (silhouette-40.svg) content/branding/aboutDialog.css (aboutDialog.css) diff --git a/browser/branding/nightly/content/identity-icons-brand.png b/browser/branding/nightly/content/identity-icons-brand.png deleted file mode 100644 index feba1607a9bb7fa8a5be6f335cdeb32fc3e70636..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1624 zcmV-e2B-OnP)RU8L!NkvDU```gD z6*UE?%+cIRO_Xylpa`ysxTOZeJ zKp!xGVK9srM;F%b{l4I>AO?vU`pW{rbI z`REH`wXPGA!HqdL_roG%oCi}va`Bn*SKkOWOU z=lAODi-9>o#6OENV&JV%qWZHGM^83+cBw7G3r9&ow_U`5>{Mi$+j2Q!d_TyCIG&0Z z=7duQ?UVWoBPxeFC4Pt6K=uF_v+KIq@C|1}6ia`&F3dgH!g9tA2?=boYbI#8A~pwb z*~W9ZxQ7Qt`Ac|ao1-sTJFNA_LMCw|u`j`u7=@@HAcR2lL6oSorblIo_7MNsZS z(LYNi?!S@Dvv>H@X_$Ooc&T6=fO{hJ;aK-8>!s-GkI-)jy`lez^+_v7Z_jWU`bGS4 z#p0-|EQ>K^Y;4;E?W3E30)gdVuARJnbT0^oLdb@Eo^9p}7(n)1ZU$-*c*{;Ykhxwu zkY&Rr&g#}NPx^~~*CL7UA0?0rg)9p#{1H1+u-exmSo+a1ZW-<))|~b+U3X>`ujyDs zR}UOyADyT_JD@^t8&o2<3B1p;7}LtewoP(DcoR@q0~L@AJ$bDsoPt)UgeyGTpk07x zdNWXI?=@HAb@7qted&VD(Psji!0aQ{{qXxN>aD0fCSDntEDO)I3m{%Cg1IL(aXJyM zXW?68WE+@iee5~gBfTtRY88q(!IuSdua~IR8d&?^VOg2z{i1yVwyGSU5Xg^=llCgu zs(Ql%xDOt@eoK1`Dbw=F?sHW1N{?hmM)LW6E5FBk+r&Oq5as!YP$_z6s5BX6T7mW! zlDtZVX*=lP&%%CUM`rlvNBsHAOPF=EVXB_FvRaQQtB2Z09A|Zmxz~ORS?%!w3Pn)G z+vh+R7DHdS36)UJ>+PFZnHEIclPTGmQcB!YYBcR#sTs2mKQR<{pIdGnRiPj|f6YVv zF;uWR#SjYsDVNiB*P%EhAb%OHI{kvMYb!|k+_^z z10^nrHKJS6g_*&5<0X&ZmJ!!8w}@+EMO*E(nq}X3ku8f<3S-x*fy%~jtTQrm%QRCJ ztRD4c+%EZK=VHByo2yujWmxuKFEZ^SCOa>NdZ1lkwXQ!U+>@Qi){_lDyU>74*Pjwg z4tdDNIQ=b*cA%YMHPa>EcK#`$UBtvqhTsRe&;rjP8}_hTw;yx+GfhO7#4zG~;ttso z*9whj=b|r|)w=zd^S&{|*wQ0GK5lK9FlyyX*@vrM$j7fMF}CuEXSKI}%>5rfr~d(2 WVxXp!azq>e0000 + + + + + diff --git a/browser/branding/nightly/content/identity-icons-brand@2x.png b/browser/branding/nightly/content/identity-icons-brand@2x.png deleted file mode 100644 index 9b2d6bc66f21ff97506d6f09497049c5af18e4ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4283 zcmV;s5Jc~ZP)U=zKuQVGIdlnK5T! z%p{$VV~m|z`1#o|t!{jNulF9Gi>uq68Xk}DAK%{}&&PdTpX>d8f9mtT@9Vzq>%NT` zWB*b8^ZvWN@B%8Q9eNS}=8rW76KD>vz-xM5;m1sPtkFv*<8xR*Tj&6GTn9d8!DD1E zy#ZJ(WAK1P_#UdDhO6RZNj%2*B{skqn)ciB;C1z~YyDMOm$QV-ONGLci#MQ_yFp_( zwv=KhmU3QFBbtDz@0N!h?LRA=Y(05To^s4r=S)A^cw0VvgO1QPjag6LokuYgOF5ML z!VORc=gVLmQ~+zF3Z5eaqi1O7pEvRSvgUPl*5wdk$%U)J;`6Lg5KB3fOEsQz;f>)H zpG~#4HX#R7%tmailn>2ejX|-LL%CD~jGwCk$|?KXLm{x|RLE->)#I7ZdhLo|oUx## z!lHBRxgeKnJjbg+2Bt3Y=LaZ9ZMq~MvX(s$%B31q3uOPQ0m@JJs^BItiTkh-J_aYS z;v8WaJOn1iYj}W>0rf3@b9L60fkMXFTfii$Rg2DVQ)gBLYqGC;c&@DML^R8;d8ig& z$ieZ4!1UbGEWI*-YBsV7CZM#BI6g%&blsnF|20gc7_zp;YHZ$-4j~7VyGECc?3wnX zhB(eE8`COa+it`>0wzT@93l%orJ7*Us0Jt}@9G0Jz$B_*AhZKxNvza7USE#7Bz=b?FO141G7$HN2kj_ zT&J(e{p{HU=p|B5rl&+;`DPwec?Kk1FJ_Nm`HN! zETYeb`wAiTRH=|s#w2dTBUSp@1)3!nyVY|pmEpJ_;%*}U0_7Qm+B8Q!uYxAtxz%>c zA!{zlKUl^@3cnS1@c8JhiQCsWgdKUGUPT6So8kCa(?Ki$F!x{m6Xh8~wP_BT%Wwn6 z<&6U-aS?jJdT`@$`Z*#K=mHaA2kZuBK!7Ai`cE`fr!}7P$8I); z3Sbic&=h8Y!cYS+{w&MkKCA}DRe-S=BQ9XS&AQixu@5~EB=<>YQWhVsC~=7`eV3Zqz*UqC=mQIsqs^!-^+f3S)Z8dyNzFqL%M7eK9jaZlFqB-j{z+%L@L||MEd;vC~g4Xpk zfbv8d_ysB`9-`qoFz5}NfN_aDNBjqxs}hT{goVc$SF1`W{8GE*l8ZXI#7CV{_Etkz zFNo_WEG(!L;tQ^NW?kv5N<5i_IyZr7GS2#;-Zx@>nv3R?G4%N5uLx7tL9>0mD}x1;&NKdteP2U{_BAD33IQE-(seU>$S^#w~`alKmq*@9{Gb z3v)tPaEuWwUbH6ll&^O21qW4pLAEBf%#pteOblHC^;z-j>za&mH#A`?@@tW^MVoQX z=W)G+6RXroMN#5D<|+`Mfm~bV2aC_jy%HE{H}1>N9YXd_cqg_*Z8>OZ4z>lvD4>O* zDKy~8G8^Kx+?bCn~nP2C0zSy=^) z>ju+cF!(}8mC*TRJ+VQF-_d3xoFP14H%qV1B`10b`S&);31p@6CN+kBd)Lq9sv{a{p)Za z+DOK0c;1r+%=@ku81c%y{I)jjOm}tsiAd}}fQLftkutm?%MH8&WN4HYi+TugkAR8z z{!OU%%DVEdWV}|d0d{hAoKCKaWyCGzqMvir@xeA@H)do1Av{v{O|I}>f6vexadW%C zZNn}4r595iFo{Q|+68|o)NwWLsTH4y<1`n|S+@ZLm(&2`+CU+c!=HR?7qsN@(mc^* zV0wOlUtkrl$+#Mx^P~aM2Wx>5&&3y=g_y&oLd>BH*uMiKam`Jx&cCrPVN!Sh+ES6kCc59FPVGA|D;gO`-{dbeN&4x zpWk%jc{05>U}d{eYtt!CO6i?=-c&RHW-GtU{cgz@Mv3E?%RmGAr&j^vdcsU#dd`9q z;-z__<`4kIlK3-l6W-@F8CS(~o-|-?{taR70YFUe5BJ%5K7z zFtK@hn!(#jZQMmM*3@Ip|GLcneiCv5JASeuT^z?;2Hu3dqA^7#Y?aMITQ7QV{VAiN$Y5n ziab;?`4OtQ`?pGJJbfAJmysuToyo`>eHI+=I5sDpw)I*2E&2-amVE9eAO{7sbO_A* zK<*ayKw8H+;_xSJ{j<`od=d^zY8bc-^^6mMan;a^KQcXgz+93S42yxbTf#g^>@~;* zYq&2N7kK=WE1B3M1BA$(jQd*?f1)2f0;^;8ou_q01#xTQj$?O8L9NjI`>zaJTD%((z`lGk>RjDf9QjuQ-Ptc#jsntzX6vn_4&mQaVxcGZUHMxx z$^D;}XrkORsn`h%9_^KOrUTee4XP#PVvhQ6#tqF*mAib(0H!>6JLv1#4imndqjaBj zk;X)(Jwk4_^Us{;`T0!+%?oDG8cpofeeUsrZ3d)fxy7IMaEm|X-X-Yk�D|i#ZJ6 zj3XAkBTV2VFzyyOzz6UbFbNgUAug~RN}(LuK~u2jH5gaK=MeMi-i}^(TOovPD-&jJ zWdL8_)+Q9bua3?ii~ak+M0nQs=ZoJ&6MgV~Vb(VXky{QIG;v3}crX81u3hkhE7cHl zaO@Q3sQ-3!&RsjD>x>GyQy?P>mrw6>kNSR+{kYsXg>%r~G$yhgwR${X{8t^uZyI9R zJEGXUSLhY9o*~zqrti^cmjB+)Wmf)2R71=$?=`&wbJTx3npn7pIlx_D+%52gK~M{& zFc6yXc(McT!*+;)mXyPD8F!c0Hj>g`1Z~{WUc!v8?g0bHyRC^iI1CFOfPEbnvRoat zXSDaSpI&|Z86fQIeK=OFnze18Dq=^nclNbb>bVE}DOapRHK}%kU&w^)@>e)bs+M<~ zz=*;*@J^RWo1^T*+8qcP8bEb*LuQHu!~%J`30BK2QUU(?J?|zyL6l#I}GaaOc~WJXR;kui-U~^ceg~ z5(_+Bn7+9d7^hQ(f3rdpb7-)7&fYPe$;EB?Ldv|-PAjnR3pCOB{raw~wDw9r)0tu^ zN0MJlH5>Vrq`BSbRbldO0Xlitag1R5!JA$&+qwpAjp+38nrPR!qVD`sw5fZ-={BuB zqnEuMxMiy6s{hgSPB}M-Vkt+GucMj`ekCbo(Q}#)+yy4_7v#cda0E-vk&or_7$$L- z*D^Ao{x9V}LlZ*2ya!C;zG_C^R&~VADRkQLOf0tbN-piBo%fwe9l0x*j!}$W&ONI2 zFTa$xup9Y#n4;^rYI&EjOoaWvt$NQo++j#&GMX{MHTI;+Z9$2bbLg(|9fxJ7(J_kA z%c-VXRI|}v%8M+zPjP@EV9%+D*D$Kbv+nOV)5aX?g#|n%Oxwtw3v#K3{xiRkO)z%~ z-tKSyPGE(+^Jw-wD3@wbEiiemA7)v+6C{Iia2Z%5UFJD5FnX2-zGP|QiyLt2S>J>R z(>7fbf;X^6K`iA^uJqo~za)cK@g1_Q&A^ltvu**u%k4+9#-LcrpMK z3_KtijzJaFa8-OPna9Y$s1X|d)5L!o5xKL!YWkLJJiAW{!MQhtsq1SAZPOSXqZo>P z**{IhV%ph{UN!km_3W)mm%#I;T|T~z#nutprZGB3F% zYm8K983*v+Idf*Ovt5MZ7PfR3C{U|35Fj*SHLcKUvWkkvP!l!jMQy~GXe_mZm&;fD$lrP?PR?@+dT_6)=t>iWBE+0FaoB0@h&- z76SI-F>FN9WPKt;h@CZ6(K?wA%DfFk_KR)PWurc)Q8Oq*V`wpQXsMOV8b9p|p=MPU z^g|RI&b4~6b(-%@oE^gG$U$|8vR?vNgroQ__9Mk=ECFcr@4#m701TsF;;^M!oHXVE zvDc6aZjiYO04F5A=~6#N#h@^9fbIpl#*SE#bQ&E$+M7A1bTR?)>u^#YI{0du8z*2k>1ArglR#(XkVTNu;9hA2L)D6h_txIfCR4`_l zn$O9s1hFk<<9Y_EujJd%ks=eTdLg8uqn%$tNM-?aLjP`avv3>O)eR%S%%CHUD$3)YeA- z-GIcH)dEdb@`RFmzyWoX&2}HQ3#hpUIds;}8JL`}9P_Q}Np~S0*{g`do&6q&b9M@Z zig%(tQ3sze8TVtoX18GoupE$6u|}p@&i7sBb_8|6Ki!N&Qlu6mMn_uoUg@NGhu?J0 zbvwqTATGY@<5A?elu$7rZHW|Itl7i(A%bQv;X%OVfLJh927uUO+HBIQ4Bjq6ti>xz zz6~O?5hJhWA_0K7)wB6-KaFyZL-!&Hl6;p}D@S}4WM&{q)Ird!2PZKdi|`yS!TSI( z3dq!j<^@bwaNd9QJMT&td&W64)LgF)h!l|_2r?-E>ZT-JLhXzt)l=rQ&Gh8NcW*l8 zS}A}sLSq3hVgUeF;RN#7i(9c1Hv(V>Ajs^LnhP}U$FM;pBKw_in}v4ys}IWni5Czs z9_0*XRlNYAY*BHK$B{%iLzUoU=N0y!f7yGaK-^{zDvbp^j+->wj)xk(8anY7KnZ^a z)Wv>h+*$w-dtR$wo9hV$C8tbN*DV8M5`RI8Qm);OP_(Kk-fDL;#nWy5wnlj;LfITO z1p$#tocA|W5-IpSUdA#244?%)=*KO%2(SmQ0aEjAwcBo)MF4`8g1iH!3udXg5nUiQ zh=T|yx6k!x{fwKlnt1@BY*{^(jE$R;RrRDL*UNN3ls6pZ45Auk_X1de=g{Mg)v>_` z+znp9H4=L*cFs0T|G)XX@3`8XsE#}+>%La!_#xLYRJNI`0$-S&FFvo;A9UoamzreK{Vp44~`3838C=P7(@{E+*zn)xOp zjdD)sXSk<*fk$v| + + + + + diff --git a/browser/branding/official/content/identity-icons-brand@2x.png b/browser/branding/official/content/identity-icons-brand@2x.png deleted file mode 100644 index 531ff5dec0cd353a41a0c7799bcefcc47fbcd8d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3178 zcmV-w43+bVP)Y&)qQkddyMu?1XUv4?CV*u29(XGunXRW z=CF1*RzuHryP56M!@BO2J}9$9RWeo!U!dT9m@14;grP%O8?1NQxW zuo_Zfu-$eE41ufQ6sQ;+gT)Z%!vKlu&+;1-_Xzi0Q1qXmn183K7v;ya^;LhBYj88e znBljo3aJGZgRdB4mD(@ewNYajpnGVcj0ip@)4A^#oG0T0bEGPiCAoEZ@;lnDuUjd9 z_*bsngONrX8BzzzlbK>L&SpHqMRt7f)`Kd-mlnwf&@-Za2<(8PFwk!62HoLexEnS= z9ViFN;G7r+=!(K#hr?<&f$e~#Ku?S9axLw9)D}68@-MLh?k)_nn`ORDuE21^nf1@| zydG2(l~REb2fG=;b~yu?-3QG~`LeN4ZsFfUbxhNs^n028@1W3=D1R7jXEVEp!c{!G zqh^t0uv&JY^adwGV94F|tC&2jEO!O0mtN2e3iiPkcn!+onB6|YQ;F;4e0au|jbu9{ zxVoPm1g~;_zZ}`k@-~Y53)eTfR@3&C)m|wR?QAD5%x&pdk!1P&?ecx(D=pbbHp_1H zx@FWjC-+mIFT;#9TuU16W~O`?m?e9;e!%rrBV7#L9$LU^Zpn7yZKG+o)d^Cx&u4|) zhWyJ~HWCcGzq!a-35m|iTgS_<<3-(RgcM({Y#oYfk&hhXkFEi?T7IIQL&lv(^|G}x zTGP#Vhj9|Dw6ubZOv^`(QAuz-5bck(5^I;rUB(QQ19Yp+mf^;96y-s1wp5*ZS{|=iD5H?SR{M2_u@a$w z=qXti+22ejfhd#nofWo5@tL21d%(BhZ|28gx z$ZUz|*T5?36YhrWnR{L!Q(iEpp(vjOX3BHg^|-_oZG=I{?272u$SS%#szy)+1hWEO zu7H>H$A0J^(*OmefdvHSwtX*%az9(;GPRN4-^g=6JR|SX=TeUq&{8#TC5Ub$Fo*Z8 zrY+2UY4=l?D>oZcr4f`L%<1xR-ExXP=M|7(yP{rPH?HF4 zVp9jHkm#xSRdNs9Xy3mbF~+YV6qbZ*nCi30t4B6n?X|Kaw}762f$nGa-_E_x!4I|> zqnv6rY~}F0XJ`)YVhRe1O#`y|O&c&iHG@-Hsf`kxDWhxVkw%xvb>=krBz%lhSu!PR z<*1dUi7R=z*p&JT!YfJnR!R_Z;9$fU&qpXs=f@R33Oj||7JL6E-m`+PAcZWE5Hr3I zrT;x*jP3e2!xVOIV212Ao}RzP1Y*Bg_iHkd9|=2ZE-%^1_+j6lh+T|^-f$Nnn zW9^JGKruz$2A;W5Bp)KzTkZ4SR(vMY3=B+_H;hRr$OUsU+aP6f zb#t**19;8;#KzTDP0+h`kv!-)))YAqZGdI$u`J`|+zG;YzGnV1c>r#QWS6maMpeM; zNe{hikPyLhs9kWyh3%4dw(ElU|M>qR(%({2)jcEtPGfDb43Hdd0P_hsWK2XsZagNn z^|@B?OtEKpg1zH;j$RS1n{Jl>pC*$+nKGtno!sU$7RJ;D7}!>6*~EZsUe23?FwB-u zf?vZ*m;?R7#_9ugFvDe>;;0y~o){3T23dlsSZw;lDef7 zku5}A-fte~Nj0sW`(RSFbko79~PT+Cb=hnX_ zL*_S%XwTB7vHO9-tJzd_q(WbMi;FAPkC;9PG+mL5%=0(R5 zwE*9^fS2^fgp=?VWPsxiC+$mJ`d7Q|gcisfKI)JFm@1!d5{0r5*K>ix=3Fu}eYIo% z0#-)ERz&NpWfmVY#-b!I9%be~Dj{=%91c#EqWTCpE*47W8r0EZc&M`(sDG{&GP56toM5lYtu)-d}!aF;N}r_?W# zA2j63o#vx*+@bHs7+|kXd!3axpP4kD9Cbb~>rEq6!9`(xli(US1ScH&1YthpxTcRg zQEDEBi(L#hqRj0C=gBDge}S?CQGLcxluedRfk_mSWgg!})Lc@nxxBD{ zK8JU}geDKUjc^=(=8?neRdAomMcywfh$p>luxhIHu4~NG5^5H%Xcl?-EMB@}I0+AdpYOu)d^$Xv z+4@3^!mvH)p#7M7!#Y0{A7dM#Q_~u`EHF-9Gag299l=Nmg{I2W%_Y`xl}`TlaWZiS znG`r2v-k!y!b@;YJCCCzsF%nrR`7jdDdU_zjVgyDGUZm0*2(WVAstwW2bTs@rNVd! z1)e@l<`_9Z(7wU05fa;fHYbDA02%mhJ}kF`Bd`hHg3G?qnV@`m5JjHwQKkQvrPKyF z@;o#DUA7*s(pwg%aW+VQ=N(WpP0~@MX$(i9etAf~4vdvO=14hQJ4f!Yw=7QokeEtm zzayQvkk0l(I{(4gdmZU>x->%>>A3sLAgwS?`3C5#`7Y&Onv_*$lqf_#G$a&}DU zRi7=_1;-N?M(|<9hXKroI9+7?K2sweWKVi1-z(AFu$7J=X88Wsp&#H?1oYtwh|M3I5 z@wPAT5_Ukht9{@33?I&IHAGLn)nFH4gYBxeKlHULV!a`k@a=Kx|C7Ie1AVlXp%`!( Qp8x;=07*qoM6N<$f=cuo$p8QV diff --git a/browser/branding/official/content/jar.mn b/browser/branding/official/content/jar.mn index 1a5ee9945f01..ba8b1ef18f41 100644 --- a/browser/branding/official/content/jar.mn +++ b/browser/branding/official/content/jar.mn @@ -13,7 +13,6 @@ browser.jar: content/branding/icon16.png (../default16.png) content/branding/icon32.png (../default32.png) content/branding/icon128.png (../mozicon128.png) - content/branding/identity-icons-brand.png (identity-icons-brand.png) - content/branding/identity-icons-brand@2x.png (identity-icons-brand@2x.png) + content/branding/identity-icons-brand.svg (identity-icons-brand.svg) content/branding/silhouette-40.svg (silhouette-40.svg) content/branding/aboutDialog.css (aboutDialog.css) diff --git a/browser/branding/unofficial/content/identity-icons-brand.png b/browser/branding/unofficial/content/identity-icons-brand.png deleted file mode 100644 index feba1607a9bb7fa8a5be6f335cdeb32fc3e70636..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1624 zcmV-e2B-OnP)RU8L!NkvDU```gD z6*UE?%+cIRO_Xylpa`ysxTOZeJ zKp!xGVK9srM;F%b{l4I>AO?vU`pW{rbI z`REH`wXPGA!HqdL_roG%oCi}va`Bn*SKkOWOU z=lAODi-9>o#6OENV&JV%qWZHGM^83+cBw7G3r9&ow_U`5>{Mi$+j2Q!d_TyCIG&0Z z=7duQ?UVWoBPxeFC4Pt6K=uF_v+KIq@C|1}6ia`&F3dgH!g9tA2?=boYbI#8A~pwb z*~W9ZxQ7Qt`Ac|ao1-sTJFNA_LMCw|u`j`u7=@@HAcR2lL6oSorblIo_7MNsZS z(LYNi?!S@Dvv>H@X_$Ooc&T6=fO{hJ;aK-8>!s-GkI-)jy`lez^+_v7Z_jWU`bGS4 z#p0-|EQ>K^Y;4;E?W3E30)gdVuARJnbT0^oLdb@Eo^9p}7(n)1ZU$-*c*{;Ykhxwu zkY&Rr&g#}NPx^~~*CL7UA0?0rg)9p#{1H1+u-exmSo+a1ZW-<))|~b+U3X>`ujyDs zR}UOyADyT_JD@^t8&o2<3B1p;7}LtewoP(DcoR@q0~L@AJ$bDsoPt)UgeyGTpk07x zdNWXI?=@HAb@7qted&VD(Psji!0aQ{{qXxN>aD0fCSDntEDO)I3m{%Cg1IL(aXJyM zXW?68WE+@iee5~gBfTtRY88q(!IuSdua~IR8d&?^VOg2z{i1yVwyGSU5Xg^=llCgu zs(Ql%xDOt@eoK1`Dbw=F?sHW1N{?hmM)LW6E5FBk+r&Oq5as!YP$_z6s5BX6T7mW! zlDtZVX*=lP&%%CUM`rlvNBsHAOPF=EVXB_FvRaQQtB2Z09A|Zmxz~ORS?%!w3Pn)G z+vh+R7DHdS36)UJ>+PFZnHEIclPTGmQcB!YYBcR#sTs2mKQR<{pIdGnRiPj|f6YVv zF;uWR#SjYsDVNiB*P%EhAb%OHI{kvMYb!|k+_^z z10^nrHKJS6g_*&5<0X&ZmJ!!8w}@+EMO*E(nq}X3ku8f<3S-x*fy%~jtTQrm%QRCJ ztRD4c+%EZK=VHByo2yujWmxuKFEZ^SCOa>NdZ1lkwXQ!U+>@Qi){_lDyU>74*Pjwg z4tdDNIQ=b*cA%YMHPa>EcK#`$UBtvqhTsRe&;rjP8}_hTw;yx+GfhO7#4zG~;ttso z*9whj=b|r|)w=zd^S&{|*wQ0GK5lK9FlyyX*@vrM$j7fMF}CuEXSKI}%>5rfr~d(2 WVxXp!azq>e0000 + + + + + diff --git a/browser/branding/unofficial/content/identity-icons-brand@2x.png b/browser/branding/unofficial/content/identity-icons-brand@2x.png deleted file mode 100644 index 9b2d6bc66f21ff97506d6f09497049c5af18e4ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4283 zcmV;s5Jc~ZP)U=zKuQVGIdlnK5T! z%p{$VV~m|z`1#o|t!{jNulF9Gi>uq68Xk}DAK%{}&&PdTpX>d8f9mtT@9Vzq>%NT` zWB*b8^ZvWN@B%8Q9eNS}=8rW76KD>vz-xM5;m1sPtkFv*<8xR*Tj&6GTn9d8!DD1E zy#ZJ(WAK1P_#UdDhO6RZNj%2*B{skqn)ciB;C1z~YyDMOm$QV-ONGLci#MQ_yFp_( zwv=KhmU3QFBbtDz@0N!h?LRA=Y(05To^s4r=S)A^cw0VvgO1QPjag6LokuYgOF5ML z!VORc=gVLmQ~+zF3Z5eaqi1O7pEvRSvgUPl*5wdk$%U)J;`6Lg5KB3fOEsQz;f>)H zpG~#4HX#R7%tmailn>2ejX|-LL%CD~jGwCk$|?KXLm{x|RLE->)#I7ZdhLo|oUx## z!lHBRxgeKnJjbg+2Bt3Y=LaZ9ZMq~MvX(s$%B31q3uOPQ0m@JJs^BItiTkh-J_aYS z;v8WaJOn1iYj}W>0rf3@b9L60fkMXFTfii$Rg2DVQ)gBLYqGC;c&@DML^R8;d8ig& z$ieZ4!1UbGEWI*-YBsV7CZM#BI6g%&blsnF|20gc7_zp;YHZ$-4j~7VyGECc?3wnX zhB(eE8`COa+it`>0wzT@93l%orJ7*Us0Jt}@9G0Jz$B_*AhZKxNvza7USE#7Bz=b?FO141G7$HN2kj_ zT&J(e{p{HU=p|B5rl&+;`DPwec?Kk1FJ_Nm`HN! zETYeb`wAiTRH=|s#w2dTBUSp@1)3!nyVY|pmEpJ_;%*}U0_7Qm+B8Q!uYxAtxz%>c zA!{zlKUl^@3cnS1@c8JhiQCsWgdKUGUPT6So8kCa(?Ki$F!x{m6Xh8~wP_BT%Wwn6 z<&6U-aS?jJdT`@$`Z*#K=mHaA2kZuBK!7Ai`cE`fr!}7P$8I); z3Sbic&=h8Y!cYS+{w&MkKCA}DRe-S=BQ9XS&AQixu@5~EB=<>YQWhVsC~=7`eV3Zqz*UqC=mQIsqs^!-^+f3S)Z8dyNzFqL%M7eK9jaZlFqB-j{z+%L@L||MEd;vC~g4Xpk zfbv8d_ysB`9-`qoFz5}NfN_aDNBjqxs}hT{goVc$SF1`W{8GE*l8ZXI#7CV{_Etkz zFNo_WEG(!L;tQ^NW?kv5N<5i_IyZr7GS2#;-Zx@>nv3R?G4%N5uLx7tL9>0mD}x1;&NKdteP2U{_BAD33IQE-(seU>$S^#w~`alKmq*@9{Gb z3v)tPaEuWwUbH6ll&^O21qW4pLAEBf%#pteOblHC^;z-j>za&mH#A`?@@tW^MVoQX z=W)G+6RXroMN#5D<|+`Mfm~bV2aC_jy%HE{H}1>N9YXd_cqg_*Z8>OZ4z>lvD4>O* zDKy~8G8^Kx+?bCn~nP2C0zSy=^) z>ju+cF!(}8mC*TRJ+VQF-_d3xoFP14H%qV1B`10b`S&);31p@6CN+kBd)Lq9sv{a{p)Za z+DOK0c;1r+%=@ku81c%y{I)jjOm}tsiAd}}fQLftkutm?%MH8&WN4HYi+TugkAR8z z{!OU%%DVEdWV}|d0d{hAoKCKaWyCGzqMvir@xeA@H)do1Av{v{O|I}>f6vexadW%C zZNn}4r595iFo{Q|+68|o)NwWLsTH4y<1`n|S+@ZLm(&2`+CU+c!=HR?7qsN@(mc^* zV0wOlUtkrl$+#Mx^P~aM2Wx>5&&3y=g_y&oLd>BH*uMiKam`Jx&cCrPVN!Sh+ES6kCc59FPVGA|D;gO`-{dbeN&4x zpWk%jc{05>U}d{eYtt!CO6i?=-c&RHW-GtU{cgz@Mv3E?%RmGAr&j^vdcsU#dd`9q z;-z__<`4kIlK3-l6W-@F8CS(~o-|-?{taR70YFUe5BJ%5K7z zFtK@hn!(#jZQMmM*3@Ip|GLcneiCv5JASeuT^z?;2Hu3dqA^7#Y?aMITQ7QV{VAiN$Y5n ziab;?`4OtQ`?pGJJbfAJmysuToyo`>eHI+=I5sDpw)I*2E&2-amVE9eAO{7sbO_A* zK<*ayKw8H+;_xSJ{j<`od=d^zY8bc-^^6mMan;a^KQcXgz+93S42yxbTf#g^>@~;* zYq&2N7kK=WE1B3M1BA$(jQd*?f1)2f0;^;8ou_q01#xTQj$?O8L9NjI`>zaJTD%((z`lGk>RjDf9QjuQ-Ptc#jsntzX6vn_4&mQaVxcGZUHMxx z$^D;}XrkORsn`h%9_^KOrUTee4XP#PVvhQ6#tqF*mAib(0H!>6JLv1#4imndqjaBj zk;X)(Jwk4_^Us{;`T0!+%?oDG8cpofeeUsrZ3d)fxy7IMaEm|X-X-Yk�D|i#ZJ6 zj3XAkBTV2VFzyyOzz6UbFbNgUAug~RN}(LuK~u2jH5gaK=MeMi-i}^(TOovPD-&jJ zWdL8_)+Q9bua3?ii~ak+M0nQs=ZoJ&6MgV~Vb(VXky{QIG;v3}crX81u3hkhE7cHl zaO@Q3sQ-3!&RsjD>x>GyQy?P>mrw6>kNSR+{kYsXg>%r~G$yhgwR${X{8t^uZyI9R zJEGXUSLhY9o*~zqrti^cmjB+)Wmf)2R71=$?=`&wbJTx3npn7pIlx_D+%52gK~M{& zFc6yXc(McT!*+;)mXyPD8F!c0Hj>g`1Z~{WUc!v8?g0bHyRC^iI1CFOfPEbnvRoat zXSDaSpI&|Z86fQIeK=OFnze18Dq=^nclNbb>bVE}DOapRHK}%kU&w^)@>e)bs+M<~ zz=*;*@J^RWo1^T*+8qcP8bEb*LuQHu!~%J`30BK2QUU(?J?|zyL6l#I}GaaOc~WJXR;kui-U~^ceg~ z5(_+Bn7+9d7^hQ(f3rdpb7-)7&fYPe$;EB?Ldv|-PAjnR3pCOB{raw~wDw9r)0tu^ zN0MJlH5>Vrq`BSbRbldO0Xlitag1R5!JA$&+qwpAjp+38nrPR!qVD`sw5fZ-={BuB zqnEuMxMiy6s{hgSPB}M-Vkt+GucMj`ekCbo(Q}#)+yy4_7v#cda0E-vk&or_7$$L- z*D^Ao{x9V}LlZ*2ya!C;zG_C^R&~VADRkQLOf0tbN-piBo%fwe9l0x*j!}$W&ONI2 zFTa$xup9Y#n4;^rYI&EjOoaWvt$NQo++j#&GMX{MHTI;+Z9$2bbLg(|9fxJ7(J_kA z%c-VXRI|}v%8M+zPjP@EV9%+D*D$Kbv+nOV)5aX?g#|n%Oxwtw3v#K3{xiRkO)z%~ z-tKSyPGE(+^Jw-wD3@wbEiiemA7)v+6C{Iia2Z%5UFJD5FnX2-zGP|QiyLt2S>J>R z(>7fbf;X^6K`iA^uJqo~za)cK@g1_Q&A^ltvu**u%k4+9#-LcrpMK z3_KtijzJaFa8-OPna9Y$s1X|d)5L!o5xKL!YWkLJJiAW{!MQhtsq1SAZPOSXqZo>P z**{IhV%ph{UN!km_3W)mm%#I;T|T~z#nutprZGB3F% #page-proxy-favicon[pageproxystate="valid"] { - list-style-image: url(chrome://branding/content/identity-icons-brand.png); - -moz-image-region: rect(0, 16px, 16px, 0); + list-style-image: url(chrome://branding/content/identity-icons-brand.svg); } .verifiedDomain > #page-proxy-favicon[pageproxystate="valid"], @@ -146,13 +145,6 @@ opacity: 0.3; } -@media (min-resolution: 1.1dppx) { - .chromeUI > #page-proxy-favicon[pageproxystate="valid"] { - list-style-image: url(chrome://branding/content/identity-icons-brand@2x.png); - -moz-image-region: rect(0, 32px, 32px, 0); - } -} - #urlbar[actiontype="searchengine"] > #identity-box > #page-proxy-favicon { -moz-image-region: inherit; list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon); From 03d909ad7d91efa3c61f6ef03652a21208e75752 Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Thu, 23 Jul 2015 20:54:30 -0700 Subject: [PATCH 03/90] Bug 1185956 - Windows 10: border-color and box-shadow of URL bar and search field should be animated. r=dao --HG-- extra : commitid : HCxWKlX74RY extra : rebase_source : f0aad85c2ca982b7e4d2334c16d936f0c884259c --- browser/themes/windows/browser.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index 3709470eae28..1487e380a16e 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -1261,6 +1261,8 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba .searchbar-textbox { font-size: 1.15em; min-height: 28px; + transition-property: border-color, box-shadow; + transition-duration: .1s; } :root { From 5fe4685be6053b485d987ed87ed799deca53544b Mon Sep 17 00:00:00 2001 From: Karim Benhmida Date: Mon, 20 Jul 2015 18:22:00 -0700 Subject: [PATCH 04/90] Bug 1132918 - Unrecognized words on direct voice input will display two error notifications. r=liuche --HG-- extra : transplant_source : %8D%12%18%CFWE%04%97PgO%5Bw%28-%06%B5%27%DB%E9 --- .../base/locales/en-US/android_strings.dtd | 4 -- mobile/android/base/strings.xml.in | 4 -- .../base/toolbar/ToolbarEditLayout.java | 43 ------------------- 3 files changed, 51 deletions(-) diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index ec31b1699874..71e002fdea8c 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -653,10 +653,6 @@ just addresses the organization to follow, e.g. "This site is run by " --> - - - - &voicesearch_prompt; - &voicesearch_failed_title; - &voicesearch_failed_message; - &voicesearch_failed_message_recoverable; - &voicesearch_failed_retry; &ellipsis; diff --git a/mobile/android/base/toolbar/ToolbarEditLayout.java b/mobile/android/base/toolbar/ToolbarEditLayout.java index 16a0cf5652ff..3bc8c5b5218b 100644 --- a/mobile/android/base/toolbar/ToolbarEditLayout.java +++ b/mobile/android/base/toolbar/ToolbarEditLayout.java @@ -237,22 +237,6 @@ public class ToolbarEditLayout extends ThemedLinearLayout { ActivityHandlerHelper.startIntentForActivity(activity, intent, new ActivityResultHandler() { @Override public void onActivityResult(int resultCode, Intent data) { - switch (resultCode) { - case RecognizerIntent.RESULT_CLIENT_ERROR: - case RecognizerIntent.RESULT_NETWORK_ERROR: - case RecognizerIntent.RESULT_SERVER_ERROR: - // We have an temporarily unrecoverable error. - handleVoiceSearchError(false); - break; - case RecognizerIntent.RESULT_AUDIO_ERROR: - case RecognizerIntent.RESULT_NO_MATCH: - // Maybe the user can say it differently? - handleVoiceSearchError(true); - break; - case Activity.RESULT_CANCELED: - break; - } - if (resultCode != Activity.RESULT_OK) { return; } @@ -272,33 +256,6 @@ public class ToolbarEditLayout extends ThemedLinearLayout { }); } - private void handleVoiceSearchError(boolean offerRetry) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()) - .setTitle(R.string.voicesearch_failed_title) - .setIcon(R.drawable.icon).setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - - if (offerRetry) { - builder.setMessage(R.string.voicesearch_failed_message_recoverable) - .setNegativeButton(R.string.voicesearch_failed_retry, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - launchVoiceRecognizer(); - } - }); - } else { - builder.setMessage(R.string.voicesearch_failed_message); - } - - AlertDialog dialog = builder.create(); - - dialog.show(); - } - private boolean qrCodeIsEnabled(Context context) { // QR code is enabled for nightly only if(!AppConstants.NIGHTLY_BUILD) { From bd94cd295f2f38a200dc2d07c1e90b283dd7c91b Mon Sep 17 00:00:00 2001 From: Karim Benhmida Date: Tue, 21 Jul 2015 13:16:46 -0700 Subject: [PATCH 05/90] Bug 1178500 - Remove nightly-only flag for voice input. r=liuche --HG-- extra : transplant_source : %40%8F%98Z%E4z%26%B3z%25%F2%3B%D7%0Ah%E6%B5Z%B7%D0 --- mobile/android/base/preferences/GeckoPreferences.java | 6 +++--- mobile/android/base/toolbar/ToolbarEditLayout.java | 4 ---- .../tests/browser/robocop/testSettingsMenuItems.java | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mobile/android/base/preferences/GeckoPreferences.java b/mobile/android/base/preferences/GeckoPreferences.java index 736def427020..7cc0d4bc3908 100644 --- a/mobile/android/base/preferences/GeckoPreferences.java +++ b/mobile/android/base/preferences/GeckoPreferences.java @@ -689,8 +689,8 @@ OnSharedPreferenceChangeListener pref.setSummary(getString(R.string.pref_category_customize_alt_summary)); } if (getResources().getString(R.string.pref_category_input_options).equals(key)) { - if (!AppConstants.NIGHTLY_BUILD || (!InputOptionsUtils.supportsVoiceRecognizer(getApplicationContext(), getResources().getString(R.string.voicesearch_prompt)) && - !InputOptionsUtils.supportsQrCodeReader(getApplicationContext()))) { + if (!InputOptionsUtils.supportsVoiceRecognizer(getApplicationContext(), getResources().getString(R.string.voicesearch_prompt)) && + !InputOptionsUtils.supportsQrCodeReader(getApplicationContext())) { preferences.removePreference(pref); i--; continue; @@ -824,7 +824,7 @@ OnSharedPreferenceChangeListener continue; } } else if (PREFS_VOICE_INPUT_ENABLED.equals(key)) { - if (!AppConstants.NIGHTLY_BUILD || !InputOptionsUtils.supportsVoiceRecognizer(getApplicationContext(), getResources().getString(R.string.voicesearch_prompt))) { + if (!InputOptionsUtils.supportsVoiceRecognizer(getApplicationContext(), getResources().getString(R.string.voicesearch_prompt))) { // Remove UI for voice input on non nightly builds. preferences.removePreference(pref); i--; diff --git a/mobile/android/base/toolbar/ToolbarEditLayout.java b/mobile/android/base/toolbar/ToolbarEditLayout.java index 3bc8c5b5218b..e11d256c5c53 100644 --- a/mobile/android/base/toolbar/ToolbarEditLayout.java +++ b/mobile/android/base/toolbar/ToolbarEditLayout.java @@ -218,10 +218,6 @@ public class ToolbarEditLayout extends ThemedLinearLayout { } private boolean voiceIsEnabled(Context context, String prompt) { - // Voice input is enabled for nightly only - if(!AppConstants.NIGHTLY_BUILD) { - return false; - } final boolean voiceIsSupported = InputOptionsUtils.supportsVoiceRecognizer(context, prompt); if (!voiceIsSupported) { return false; diff --git a/mobile/android/tests/browser/robocop/testSettingsMenuItems.java b/mobile/android/tests/browser/robocop/testSettingsMenuItems.java index e007a9e6a1f2..30c62b213aeb 100644 --- a/mobile/android/tests/browser/robocop/testSettingsMenuItems.java +++ b/mobile/android/tests/browser/robocop/testSettingsMenuItems.java @@ -229,7 +229,7 @@ public class testSettingsMenuItems extends PixelTest { } // Voice input - if (AppConstants.NIGHTLY_BUILD && InputOptionsUtils.supportsVoiceRecognizer(this.getActivity().getApplicationContext(), this.getActivity().getResources().getString(R.string.voicesearch_prompt))) { + if (InputOptionsUtils.supportsVoiceRecognizer(this.getActivity().getApplicationContext(), this.getActivity().getResources().getString(R.string.voicesearch_prompt))) { String[] voiceInputUi = { mStringHelper.VOICE_INPUT_TITLE_LABEL, mStringHelper.VOICE_INPUT_SUMMARY_LABEL }; settingsMap.get(PATH_DISPLAY).add(voiceInputUi); } From f5c221730a996085fc13d377b2d134a1afaa9282 Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Fri, 24 Jul 2015 09:01:58 +0100 Subject: [PATCH 06/90] Bug 1186541 - Fix a warning in StandaloneRoomView.shouldRenderRemoteVideo when the roomState is gather. r=mikedeboer --- browser/components/loop/content/js/roomViews.js | 1 + browser/components/loop/content/js/roomViews.jsx | 1 + .../components/loop/standalone/content/js/standaloneRoomViews.js | 1 + .../loop/standalone/content/js/standaloneRoomViews.jsx | 1 + 4 files changed, 4 insertions(+) diff --git a/browser/components/loop/content/js/roomViews.js b/browser/components/loop/content/js/roomViews.js index 109e58e9eac3..abaa1b3b3165 100644 --- a/browser/components/loop/content/js/roomViews.js +++ b/browser/components/loop/content/js/roomViews.js @@ -638,6 +638,7 @@ loop.roomViews = (function(mozL10n) { return true; case ROOM_STATES.READY: + case ROOM_STATES.GATHER: case ROOM_STATES.INIT: case ROOM_STATES.JOINING: case ROOM_STATES.SESSION_CONNECTED: diff --git a/browser/components/loop/content/js/roomViews.jsx b/browser/components/loop/content/js/roomViews.jsx index 02c679bbe133..ced81c562c61 100644 --- a/browser/components/loop/content/js/roomViews.jsx +++ b/browser/components/loop/content/js/roomViews.jsx @@ -638,6 +638,7 @@ loop.roomViews = (function(mozL10n) { return true; case ROOM_STATES.READY: + case ROOM_STATES.GATHER: case ROOM_STATES.INIT: case ROOM_STATES.JOINING: case ROOM_STATES.SESSION_CONNECTED: diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.js b/browser/components/loop/standalone/content/js/standaloneRoomViews.js index 57c63121c7e6..746bb8413a3a 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js @@ -372,6 +372,7 @@ loop.standaloneRoomViews = (function(mozL10n) { return true; case ROOM_STATES.READY: + case ROOM_STATES.GATHER: case ROOM_STATES.INIT: case ROOM_STATES.JOINING: case ROOM_STATES.SESSION_CONNECTED: diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx index 1b557af28acc..02a78c95752c 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx @@ -372,6 +372,7 @@ loop.standaloneRoomViews = (function(mozL10n) { return true; case ROOM_STATES.READY: + case ROOM_STATES.GATHER: case ROOM_STATES.INIT: case ROOM_STATES.JOINING: case ROOM_STATES.SESSION_CONNECTED: From e542ba93f79eb227c5c30d7eeccafeda28b5c5a5 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 23 Jul 2015 18:37:47 +0900 Subject: [PATCH 07/90] Bug 1063359 - Unconditionally use -Wl,--no-as-needed when building with GNU ld/gold. r=mshal --- widget/gtk/mozgtk/gtk2/moz.build | 14 +++++++++----- widget/gtk/mozgtk/gtk3/moz.build | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/widget/gtk/mozgtk/gtk2/moz.build b/widget/gtk/mozgtk/gtk2/moz.build index acc9fbf76dd5..9b2b68bac13c 100644 --- a/widget/gtk/mozgtk/gtk2/moz.build +++ b/widget/gtk/mozgtk/gtk2/moz.build @@ -14,11 +14,15 @@ SharedLibrary('mozgtk2') SONAME = 'mozgtk' -# If LDFLAGS contains -Wl,--as-needed, we need to add -Wl,--no-as-needed -# before the gtk libraries, otherwise the linker will drop those dependencies -# because no symbols are used from them. But those dependencies need to be -# kept for things to work properly. -if '-Wl,--as-needed' in CONFIG['OS_LDFLAGS']: +# If LDFLAGS contains -Wl,--as-needed or if it's the default for the toolchain, +# we need to add -Wl,--no-as-needed before the gtk libraries, otherwise the +# linker will drop those dependencies because no symbols are used from them. +# But those dependencies need to be kept for things to work properly. +# Ideally, we'd only add -Wl,--no-as-needed if necessary, but it's just simpler +# to add it unconditionally. This library is also simple enough that forcing +# -Wl,--as-needed after the gtk libraries is not going to make a significant +# difference. +if CONFIG['GCC_USE_GNU_LD']: no_as_needed = ['-Wl,--no-as-needed'] as_needed = ['-Wl,--as-needed'] else: diff --git a/widget/gtk/mozgtk/gtk3/moz.build b/widget/gtk/mozgtk/gtk3/moz.build index fb62856b1ee4..81c4ceac7ed1 100644 --- a/widget/gtk/mozgtk/gtk3/moz.build +++ b/widget/gtk/mozgtk/gtk3/moz.build @@ -14,11 +14,15 @@ SharedLibrary('mozgtk') SONAME = 'mozgtk' -# If LDFLAGS contains -Wl,--as-needed, we need to add -Wl,--no-as-needed -# before the gtk libraries, otherwise the linker will drop those dependencies -# because no symbols are used from them. But those dependencies need to be -# kept for things to work properly. -if '-Wl,--as-needed' in CONFIG['OS_LDFLAGS']: +# If LDFLAGS contains -Wl,--as-needed or if it's the default for the toolchain, +# we need to add -Wl,--no-as-needed before the gtk libraries, otherwise the +# linker will drop those dependencies because no symbols are used from them. +# But those dependencies need to be kept for things to work properly. +# Ideally, we'd only add -Wl,--no-as-needed if necessary, but it's just simpler +# to add it unconditionally. This library is also simple enough that forcing +# -Wl,--as-needed after the gtk libraries is not going to make a significant +# difference. +if CONFIG['GCC_USE_GNU_LD']: no_as_needed = ['-Wl,--no-as-needed'] as_needed = ['-Wl,--as-needed'] else: From ca419bead3bb2e5c0dc2370d56d6aa7c1f0f891e Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Thu, 23 Jul 2015 08:40:00 +0200 Subject: [PATCH 08/90] Bug 1186871 - Don't wait for "shutdown" ping saving before creating "saved-session" payloads. r=gfritzsche --- .../components/telemetry/TelemetrySession.jsm | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm index dc8f17e8feed..73cdf9ab258f 100644 --- a/toolkit/components/telemetry/TelemetrySession.jsm +++ b/toolkit/components/telemetry/TelemetrySession.jsm @@ -1614,40 +1614,42 @@ let Impl = { /** * Save both the "saved-session" and the "shutdown" pings to disk. */ - saveShutdownPings: Task.async(function*() { + saveShutdownPings: function() { this._log.trace("saveShutdownPings"); - if (IS_UNIFIED_TELEMETRY) { - try { - let shutdownPayload = this.getSessionPayload(REASON_SHUTDOWN, false); + // We don't wait for "shutdown" pings to be written to disk before gathering the + // "saved-session" payload. Instead we append the promises to this list and wait + // on both to be saved after kicking off their collection. + let p = []; - let options = { - addClientId: true, - addEnvironment: true, - overwrite: true, - }; - yield TelemetryController.addPendingPing(getPingType(shutdownPayload), shutdownPayload, options); - } catch (ex) { - this._log.error("saveShutdownPings - failed to submit shutdown ping", ex); - } + if (IS_UNIFIED_TELEMETRY) { + let shutdownPayload = this.getSessionPayload(REASON_SHUTDOWN, false); + + let options = { + addClientId: true, + addEnvironment: true, + overwrite: true, + }; + p.push(TelemetryController.addPendingPing(getPingType(shutdownPayload), shutdownPayload, options) + .catch(e => this._log.error("saveShutdownPings - failed to submit shutdown ping", e))); } // As a temporary measure, we want to submit saved-session too if extended Telemetry is enabled // to keep existing performance analysis working. if (Telemetry.canRecordExtended) { - try { - let payload = this.getSessionPayload(REASON_SAVED_SESSION, false); + let payload = this.getSessionPayload(REASON_SAVED_SESSION, false); - let options = { - addClientId: true, - addEnvironment: true, - }; - yield TelemetryController.addPendingPing(getPingType(payload), payload, options); - } catch (ex) { - this._log.error("saveShutdownPings - failed to submit saved-session ping", ex); - } + let options = { + addClientId: true, + addEnvironment: true, + }; + p.push(TelemetryController.addPendingPing(getPingType(payload), payload, options) + .catch (e => this._log.error("saveShutdownPings - failed to submit saved-session ping", e))); } - }), + + // Wait on pings to be saved. + return Promise.all(p); + }, testSavePendingPing: function testSaveHistograms() { From 104a7c3e6544f40606e73258643c65f922448e28 Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Fri, 26 Jun 2015 16:31:00 +0200 Subject: [PATCH 09/90] Bug 1137355 - Refactor the logic to show TelemetryInfobar in TelemetryInfobarController. r=gfritzsche --- .../telemetry/TelemetryController.jsm | 8 + .../telemetry/TelemetryReportingPolicy.jsm | 379 ++++++++++++++++++ .../components/telemetry/TelemetrySend.jsm | 48 ++- toolkit/components/telemetry/moz.build | 1 + 4 files changed, 428 insertions(+), 8 deletions(-) create mode 100644 toolkit/components/telemetry/TelemetryReportingPolicy.jsm diff --git a/toolkit/components/telemetry/TelemetryController.jsm b/toolkit/components/telemetry/TelemetryController.jsm index 7c5eabb8bcad..7788a8ae3294 100644 --- a/toolkit/components/telemetry/TelemetryController.jsm +++ b/toolkit/components/telemetry/TelemetryController.jsm @@ -87,6 +87,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySession", "resource://gre/modules/TelemetrySession.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySend", "resource://gre/modules/TelemetrySend.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "TelemetryReportingPolicy", + "resource://gre/modules/TelemetryReportingPolicy.jsm"); /** * Setup Telemetry logging. This function also gets called when loggin related @@ -651,6 +653,9 @@ let Impl = { this._sessionRecorder.onStartup(); } + // This will trigger displaying the datachoices infobar. + TelemetryReportingPolicy.setup(); + if (!this.enableTelemetryRecording()) { this._log.config("setupChromeProcess - Telemetry recording is disabled, skipping Chrome process setup."); return Promise.resolve(); @@ -726,6 +731,9 @@ let Impl = { // Now do an orderly shutdown. try { + // Stop the datachoices infobar display. + TelemetryReportingPolicy.shutdown(); + // Stop any ping sending. yield TelemetrySend.shutdown(); diff --git a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm new file mode 100644 index 000000000000..400155cbd7cf --- /dev/null +++ b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm @@ -0,0 +1,379 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = [ + "TelemetryReportingPolicy" +]; + +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Log.jsm", this); +Cu.import("resource://gre/modules/Preferences.jsm", this); +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/Timer.jsm", this); +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); +Cu.import("resource://services-common/observers.js", this); + +XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySend", + "resource://gre/modules/TelemetrySend.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel", + "resource://gre/modules/UpdateChannel.jsm"); + +const LOGGER_NAME = "Toolkit.Telemetry"; +const LOGGER_PREFIX = "TelemetryReportingPolicy::"; + +// Oldest year to allow in date preferences. The FHR infobar was implemented in +// 2012 and no dates older than that should be encountered. +const OLDEST_ALLOWED_ACCEPTANCE_YEAR = 2012; + +const PREF_BRANCH = "datareporting.policy."; +// Indicates whether this is the first run or not. This is used to decide when to display +// the policy. +const PREF_FIRST_RUN = "toolkit.telemetry.reportingpolicy.firstRun"; +// Allows to skip the datachoices infobar. This should only be used in tests. +const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification"; +// The submission kill switch: if this preference is disable, no submission will ever take place. +const PREF_DATA_SUBMISSION_ENABLED = PREF_BRANCH + "dataSubmissionEnabled"; +// This preference holds the current policy version, which overrides +// DEFAULT_DATAREPORTING_POLICY_VERSION +const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion"; +// This indicates the minimum required policy version. If the accepted policy version +// is lower than this, the notification bar must be showed again. +const PREF_MINIMUM_POLICY_VERSION = PREF_BRANCH + "minimumPolicyVersion"; +// The version of the accepted policy. +const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion"; +// The date user accepted the policy. +const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime"; +// The following preferences are deprecated and will be purged during the preferences +// migration process. +const DEPRECATED_FHR_PREFS = [ + PREF_BRANCH + "dataSubmissionPolicyAccepted", + PREF_BRANCH + "dataSubmissionPolicyBypassAcceptance", + PREF_BRANCH + "dataSubmissionPolicyResponseType", + PREF_BRANCH + "dataSubmissionPolicyResponseTime" +]; + +// How much time until we display the data choices notification bar, on the first run. +const NOTIFICATION_DELAY_FIRST_RUN_MSEC = 60 * 1000; // 60s +// Same as above, for the next runs. +const NOTIFICATION_DELAY_NEXT_RUNS_MSEC = 10 * 1000; // 10s + +/** + * Represents a request to display data policy. + * + * Receivers of these instances are expected to call one or more of the on* + * functions when events occur. + * + * When one of these requests is received, the first thing a callee should do + * is present notification to the user of the data policy. When the notice + * is displayed to the user, the callee should call `onUserNotifyComplete`. + * + * If for whatever reason the callee could not display a notice, + * it should call `onUserNotifyFailed`. + * + * @param {Object} aLog The log object used to log the error in case of failures. + */ +function NotifyPolicyRequest(aLog) { + this._log = aLog; +} + +NotifyPolicyRequest.prototype = Object.freeze({ + /** + * Called when the user is notified of the policy. + */ + onUserNotifyComplete: function () { + return TelemetryReportingPolicyImpl._infobarShownCallback(); + }, + + /** + * Called when there was an error notifying the user about the policy. + * + * @param error + * (Error) Explains what went wrong. + */ + onUserNotifyFailed: function (error) { + this._log.error("onUserNotifyFailed - " + error); + }, +}); + +this.TelemetryReportingPolicy = { + // The current policy version number. If the version number stored in the prefs + // is smaller than this, data upload will be disabled until the user is re-notified + // about the policy changes. + DEFAULT_DATAREPORTING_POLICY_VERSION: 1, + + /** + * Setup the policy. + */ + setup: function() { + return TelemetryReportingPolicyImpl.setup(); + }, + + /** + * Shutdown and clear the policy. + */ + shutdown: function() { + return TelemetryReportingPolicyImpl.shutdown(); + }, + + /** + * Check if we are allowed to upload data. In order to submit data both these conditions + * should be true: + * - The data submission preference should be true. + * - The datachoices infobar should have been displayed. + * + * @return {Boolean} True if we are allowed to upload data, false otherwise. + */ + canUpload: function() { + return TelemetryReportingPolicyImpl.canUpload(); + }, +}; + +let TelemetryReportingPolicyImpl = { + _logger: null, + // Keep track of the notification status if user wasn't notified already. + _notificationInProgress: false, + // The timer used to show the datachoices notification at startup. + _startupNotificationTimerId: null, + + get _log() { + if (!this._logger) { + this._logger = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX); + } + + return this._logger; + }, + + /** + * Get the date the policy was notified. + * @return {Object} A date object or null on errors. + */ + get dataSubmissionPolicyNotifiedDate() { + let prefString = Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0); + let valueInteger = parseInt(prefString, 10); + + // If nothing or an invalid value is saved in the prefs, bail out. + if (Number.isNaN(valueInteger) || valueInteger == 0) { + this._log.error("get dataSubmissionPolicyNotifiedDate - Invalid date stored."); + return null; + } + + // Make sure the notification date is newer then the oldest allowed date. + let date = new Date(valueInteger); + if (date.getFullYear() < OLDEST_ALLOWED_ACCEPTANCE_YEAR) { + this._log.error("get dataSubmissionPolicyNotifiedDate - The stored date is too old."); + return null; + } + + return date; + }, + + /** + * Set the date the policy was notified. + * @param {Object} aDate A valid date object. + */ + set dataSubmissionPolicyNotifiedDate(aDate) { + this._log.trace("set dataSubmissionPolicyNotifiedDate - aDate: " + aDate); + + if (!aDate || aDate.getFullYear() < OLDEST_ALLOWED_ACCEPTANCE_YEAR) { + this._log.error("set dataSubmissionPolicyNotifiedDate - Invalid notification date."); + return; + } + + Preferences.set(PREF_ACCEPTED_POLICY_DATE, aDate.getTime().toString()); + }, + + /** + * Whether submission of data is allowed. + * + * This is the master switch for remote server communication. If it is + * false, we never request upload or deletion. + */ + get dataSubmissionEnabled() { + // Default is true because we are opt-out. + return Preferences.get(PREF_DATA_SUBMISSION_ENABLED, true); + }, + + get currentPolicyVersion() { + return Preferences.get(PREF_CURRENT_POLICY_VERSION, + TelemetryReportingPolicy.DEFAULT_DATAREPORTING_POLICY_VERSION); + }, + + /** + * The minimum policy version which for dataSubmissionPolicyAccepted to + * to be valid. + */ + get minimumPolicyVersion() { + const minPolicyVersion = Preferences.get(PREF_MINIMUM_POLICY_VERSION, 1); + + // First check if the current channel has a specific minimum policy version. If not, + // use the general minimum policy version. + let channel = ""; + try { + channel = UpdateChannel.get(false); + } catch(e) { + this._log.error("minimumPolicyVersion - Unable to retrieve the current channel."); + return minPolicyVersion; + } + const channelPref = PREF_MINIMUM_POLICY_VERSION + ".channel-" + channel; + return Preferences.get(channelPref, minPolicyVersion); + }, + + get dataSubmissionPolicyAcceptedVersion() { + return Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0); + }, + + set dataSubmissionPolicyAcceptedVersion(value) { + Preferences.set(PREF_ACCEPTED_POLICY_VERSION, value); + }, + + /** + * Checks to see if the user has been notified about data submission + * @return {Bool} True if user has been notified and the notification is still valid, + * false otherwise. + */ + get isUserNotifiedOfCurrentPolicy() { + // If we don't have a sane notification date, the user was not notified yet. + if (!this.dataSubmissionPolicyNotifiedDate || + this.dataSubmissionPolicyNotifiedDate.getTime() <= 0) { + return false; + } + + // The accepted policy version should not be less than the minimum policy version. + if (this.dataSubmissionPolicyAcceptedVersion < this.minimumPolicyVersion) { + return false; + } + + // Otherwise the user was already notified. + return true; + }, + + /** + * Setup the policy. + */ + setup: function() { + this._log.trace("setup"); + + // Migrate the data choices infobar, if needed. + this._migratePreferences(); + + // Add the event observers. + Services.obs.addObserver(this, "sessionstore-windows-restored", false); + }, + + /** + * Clean up the reporting policy. + */ + shutdown: function() { + this._log.trace("shutdown"); + + this._detachObservers(); + + clearTimeout(this._startupNotificationTimerId); + }, + + /** + * Detach the observers that were attached during setup. + */ + _detachObservers: function() { + Services.obs.removeObserver(this, "sessionstore-windows-restored"); + }, + + /** + * Check if we are allowed to upload data. In order to submit data both these conditions + * should be true: + * - The data submission preference should be true. + * - The datachoices infobar should have been displayed. + * + * @return {Boolean} True if we are allowed to upload data, false otherwise. + */ + canUpload: function() { + // If data submission is disabled, there's no point in showing the infobar. Just + // forbid to upload. + if (!this.dataSubmissionEnabled) { + return false; + } + + // Make sure the user is notified of the current policy. If he isn't, don't try + // to upload anything. + if (!this._ensureUserNotified()) { + return false; + } + + // Submission is enabled and user is notified: upload is allowed. + return true; + }, + + /** + * Migrate the data policy preferences, if needed. + */ + _migratePreferences: function() { + // Current prefs are mostly the same than the old ones, except for some deprecated ones. + for (let pref of DEPRECATED_FHR_PREFS) { + Preferences.reset(pref); + } + }, + + /** + * Make sure the user is notified about the policy before allowing upload. + * @return {Boolean} True if the user was notified, false otherwise. + */ + _ensureUserNotified: function() { + const BYPASS_NOTIFICATION = Preferences.get(PREF_BYPASS_NOTIFICATION, false); + if (this.isUserNotifiedOfCurrentPolicy || BYPASS_NOTIFICATION) { + return true; + } + + this._log.trace("ensureUserNotified - User not notified, notifying now."); + if (this._notificationInProgress) { + this._log.trace("ensureUserNotified - User not notified, notification in progress."); + return false; + } + + this._notificationInProgress = true; + let request = new NotifyPolicyRequest(this._log); + Observers.notify("datareporting:notify-data-policy:request", request); + + return false; + }, + + /** + * Called when the user is notified with the infobar. + */ + _infobarShownCallback: function() { + this._log.trace("_infobarShownCallback"); + this._recordNotificationData(); + TelemetrySend.notifyCanUpload(); + }, + + /** + * Record date and the version of the accepted policy. + */ + _recordNotificationData: function() { + this._log.trace("_recordNotificationData"); + this.dataSubmissionPolicyNotifiedDate = new Date(); + this.dataSubmissionPolicyAcceptedVersion = this.currentPolicyVersion; + // The user was notified and the notification data saved: the notification + // is no longer in progress. + this._notificationInProgress = false; + }, + + observe: function(aSubject, aTopic, aData) { + if (aTopic != "sessionstore-windows-restored") { + return; + } + + const isFirstRun = Preferences.get(PREF_FIRST_RUN, true); + const delay = + isFirstRun ? NOTIFICATION_DELAY_FIRST_RUN_MSEC: NOTIFICATION_DELAY_NEXT_RUNS_MSEC; + + this._startupNotificationTimerId = setTimeout( + // Calling |canUpload| eventually shows the infobar, if needed. + () => this.canUpload(), delay); + // We performed at least a run, flip the firstRun preference. + Preferences.set(PREF_FIRST_RUN, false); + }, +}; diff --git a/toolkit/components/telemetry/TelemetrySend.jsm b/toolkit/components/telemetry/TelemetrySend.jsm index 4579f7815455..a2801737ddff 100644 --- a/toolkit/components/telemetry/TelemetrySend.jsm +++ b/toolkit/components/telemetry/TelemetrySend.jsm @@ -30,6 +30,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", "resource://gre/modules/AsyncShutdown.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStorage", "resource://gre/modules/TelemetryStorage.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "TelemetryReportingPolicy", + "resource://gre/modules/TelemetryReportingPolicy.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", "@mozilla.org/base/telemetry;1", "nsITelemetry"); @@ -198,6 +200,13 @@ this.TelemetrySend = { return TelemetrySendImpl.overduePingsCount; }, + /** + * Notify that we can start submitting data to the servers. + */ + notifyCanUpload: function() { + return TelemetrySendImpl.notifyCanUpload(); + }, + /** * Only used in tests. Used to reset the module data to emulate a restart. */ @@ -382,8 +391,8 @@ let SendScheduler = { let pending = TelemetryStorage.getPendingPingList(); let current = TelemetrySendImpl.getUnpersistedPings(); this._log.trace("_doSendTask - pending: " + pending.length + ", current: " + current.length); - pending = pending.filter(p => TelemetrySendImpl.canSend(p)); - current = current.filter(p => TelemetrySendImpl.canSend(p)); + pending = pending.filter(p => TelemetrySendImpl.sendingEnabled(p)); + current = current.filter(p => TelemetrySendImpl.sendingEnabled(p)); this._log.trace("_doSendTask - can send - pending: " + pending.length + ", current: " + current.length); // Bail out if there is nothing to send. @@ -632,6 +641,15 @@ let TelemetrySendImpl = { return SendScheduler.reset(); }, + /** + * Notify that we can start submitting data to the servers. + */ + notifyCanUpload: function() { + // Let the scheduler trigger sending pings if possible. + SendScheduler.triggerSendingPings(true); + return this.promisePendingPingActivity(); + }, + observe: function(subject, topic, data) { switch(topic) { case TOPIC_IDLE_DAILY: @@ -643,15 +661,15 @@ let TelemetrySendImpl = { submitPing: function(ping) { this._log.trace("submitPing - ping id: " + ping.id); - if (!this.canSend(ping)) { + if (!this.sendingEnabled(ping)) { this._log.trace("submitPing - Telemetry is not allowed to send pings."); return Promise.resolve(); } - if (!this._sendingEnabled) { + if (!this.canSendNow) { // Sending is disabled or throttled, add this to the persisted pending pings. this._log.trace("submitPing - can't send ping now, persisting to disk - " + - "sendingEnabled: " + this._sendingEnabled); + "canSendNow: " + this.canSendNow); return TelemetryStorage.savePendingPing(ping); } @@ -806,7 +824,7 @@ let TelemetrySendImpl = { }, _doPing: function(ping, id, isPersisted) { - if (!this.canSend(ping)) { + if (!this.sendingEnabled(ping)) { // We can't send the pings to the server, so don't try to. this._log.trace("_doPing - Can't send ping " + ping.id); return Promise.resolve(); @@ -910,7 +928,21 @@ let TelemetrySendImpl = { }, /** - * Check if pings can be sent to the server. If FHR is not allowed to upload, + * Check if sending is temporarily disabled. + * @return {Boolean} True if we can send pings to the server right now, false if + * sending is temporarily disabled. + */ + get canSendNow() { + // If the reporting policy was not accepted yet, don't send pings. + if (!TelemetryReportingPolicy.canUpload()) { + return false; + } + + return this._sendingEnabled; + }, + + /** + * Check if sending is disabled. If FHR is not allowed to upload, * pings are not sent to the server (Telemetry is a sub-feature of FHR). If trying * to send a deletion ping, don't block it. * If unified telemetry is off, don't send pings if Telemetry is disabled. @@ -918,7 +950,7 @@ let TelemetrySendImpl = { * @param {Object} [ping=null] A ping to be checked. * @return {Boolean} True if pings can be send to the servers, false otherwise. */ - canSend: function(ping = null) { + sendingEnabled: function(ping = null) { // We only send pings from official builds, but allow overriding this for tests. if (!Telemetry.isOfficialTelemetry && !this._testMode) { return false; diff --git a/toolkit/components/telemetry/moz.build b/toolkit/components/telemetry/moz.build index 49d225069028..83609d887467 100644 --- a/toolkit/components/telemetry/moz.build +++ b/toolkit/components/telemetry/moz.build @@ -32,6 +32,7 @@ EXTRA_COMPONENTS += [ EXTRA_JS_MODULES += [ 'TelemetryArchive.jsm', 'TelemetryLog.jsm', + 'TelemetryReportingPolicy.jsm', 'TelemetrySend.jsm', 'TelemetryStopwatch.jsm', 'TelemetryStorage.jsm', From 5d6bd5529573dca311e5e0e64f7c47f762e65bc7 Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Fri, 26 Jun 2015 16:31:00 +0200 Subject: [PATCH 10/90] Bug 1137355 - Add test coverage for the Data Choices notification bar in Telemetry. r=gfritzsche --- browser/base/content/test/general/browser.ini | 2 + .../browser_datachoices_notification.js | 213 +++++++++++++++ .../browser_datareporting_notification.js | 24 -- browser/base/content/test/general/head.js | 21 ++ .../telemetry/TelemetryReportingPolicy.jsm | 46 +++- .../components/telemetry/tests/unit/head.js | 3 + .../unit/test_TelemetryReportingPolicy.js | 255 ++++++++++++++++++ .../telemetry/tests/unit/xpcshell.ini | 1 + 8 files changed, 538 insertions(+), 27 deletions(-) create mode 100644 browser/base/content/test/general/browser_datachoices_notification.js create mode 100644 toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index ed0f6c8b7952..f4998abb1c0d 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -278,6 +278,8 @@ skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the ne [browser_ctrlTab.js] [browser_datareporting_notification.js] skip-if = !datareporting +[browser_datachoices_notification.js] +skip-if = !datareporting [browser_devedition.js] [browser_devices_get_user_media.js] skip-if = buildapp == 'mulet' || (os == "linux" && debug) || e10s # linux: bug 976544; e10s: bug 1071623 diff --git a/browser/base/content/test/general/browser_datachoices_notification.js b/browser/base/content/test/general/browser_datachoices_notification.js new file mode 100644 index 000000000000..641fcffae095 --- /dev/null +++ b/browser/base/content/test/general/browser_datachoices_notification.js @@ -0,0 +1,213 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +// Pass an empty scope object to the import to prevent "leaked window property" +// errors in tests. +let Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences; +let TelemetryReportingPolicy = + Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", {}).TelemetryReportingPolicy; + +XPCOMUtils.defineLazyGetter(this, "gDatareportingService", + () => Cc["@mozilla.org/datareporting/service;1"] + .getService(Ci.nsISupports) + .wrappedJSObject); + +const PREF_BRANCH = "datareporting.policy."; +const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled"; +const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification"; +const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion"; +const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion"; +const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime"; + +const TEST_POLICY_VERSION = 37; + +/** + * Wait for a tick. + */ +function promiseNextTick() { + return new Promise(resolve => executeSoon(resolve)); +} + +/** + * Wait for a notification to be shown in a notification box. + * @param {Object} aNotificationBox The notification box. + * @return {Promise} Resolved when the notification is displayed. + */ +function promiseWaitForAlertActive(aNotificationBox) { + let deferred = PromiseUtils.defer(); + aNotificationBox.addEventListener("AlertActive", function onActive() { + aNotificationBox.removeEventListener("AlertActive", onActive, true); + deferred.resolve(); + }); + return deferred.promise; +} + +/** + * Wait for a notification to be closed. + * @param {Object} aNotification The notification. + * @return {Promise} Resolved when the notification is closed. + */ +function promiseWaitForNotificationClose(aNotification) { + let deferred = PromiseUtils.defer(); + waitForNotificationClose(aNotification, deferred.resolve); + return deferred.promise; +} + +let checkInfobarButton = Task.async(function* (aNotification) { + // Check that the button on the data choices infobar does the right thing. + let buttons = aNotification.getElementsByTagName("button"); + Assert.equal(buttons.length, 1, "There is 1 button in the data reporting notification."); + let button = buttons[0]; + + // Add an observer to ensure the "advanced" pane opened (but don't bother + // closing it - we close the entire window when done.) + let paneLoadedPromise = promiseTopicObserved("advanced-pane-loaded"); + + // Click on the button. + button.click(); + + // Wait for the preferences panel to open. + let preferenceWindow = yield paneLoadedPromise; + yield promiseNextTick(); + // If the prefs are being displayed in a dialog we need to close it. + // If in a tab (ie, in-content prefs) it closes with the window. + if (!Services.prefs.getBoolPref("browser.preferences.inContent")) { + prefWin.close(); + } +}); + +add_task(function* setup(){ + const drsEnabled = Preferences.get(PREF_DRS_ENABLED, true); + const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, true); + const currentPolicyVersion = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1); + + // Register a cleanup function to reset our preferences. + registerCleanupFunction(() => { + Preferences.set(PREF_DRS_ENABLED, drsEnabled); + Preferences.set(PREF_BYPASS_NOTIFICATION, bypassNotification); + Preferences.set(PREF_CURRENT_POLICY_VERSION, currentPolicyVersion); + + // Start polling again. + gDatareportingService.policy.startPolling(); + + return closeAllNotifications(); + }); + + // Disable Healthreport/Data reporting service. + Preferences.set(PREF_DRS_ENABLED, false); + // Don't skip the infobar visualisation. + Preferences.set(PREF_BYPASS_NOTIFICATION, false); + // Set the current policy version. + Preferences.set(PREF_CURRENT_POLICY_VERSION, TEST_POLICY_VERSION); + + // Stop the polling to make sure no policy gets displayed by FHR. + gDatareportingService.policy.stopPolling(); +}); + +function clearAcceptedPolicy() { + // Reset the accepted policy. + Preferences.reset(PREF_ACCEPTED_POLICY_VERSION); + Preferences.reset(PREF_ACCEPTED_POLICY_DATE); +} + +add_task(function* test_single_window(){ + clearAcceptedPolicy(); + + // Close all the notifications, then try to trigger the data choices infobar. + yield closeAllNotifications(); + + let notificationBox = document.getElementById("global-notificationbox"); + + // Make sure that we have a coherent initial state. + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, + "No version should be set on init."); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, + "No date should be set on init."); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "User not notified about datareporting policy."); + + let alertShownPromise = promiseWaitForAlertActive(notificationBox); + // This should be false and trigger the Infobar. + Assert.ok(!TelemetryReportingPolicy.canUpload(), + "User should not be allowed to upload and the infobar should be triggered."); + + // Wait for the infobar to be displayed. + yield alertShownPromise; + + Assert.equal(notificationBox.allNotifications.length, 1, "Notification Displayed."); + Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now."); + + yield promiseNextTick(); + let promiseClosed = promiseWaitForNotificationClose(notificationBox.currentNotification); + yield checkInfobarButton(notificationBox.currentNotification); + yield promiseClosed; + + Assert.equal(notificationBox.allNotifications.length, 0, "No notifications remain."); + + // Check that we are still clear to upload and that the policy data is saved. + Assert.ok(TelemetryReportingPolicy.canUpload()); + Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true, + "User notified about datareporting policy."); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION, + "Version pref set."); + Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1, + "Date pref set."); +}); + +add_task(function* test_multiple_windows(){ + clearAcceptedPolicy(); + + // Close all the notifications, then try to trigger the data choices infobar. + yield closeAllNotifications(); + + // Ensure we see the notification on all windows and that action on one window + // results in dismiss on every window. + let otherWindow = yield BrowserTestUtils.openNewBrowserWindow(); + + // Get the notification box for both windows. + let notificationBoxes = [ + document.getElementById("global-notificationbox"), + otherWindow.document.getElementById("global-notificationbox") + ]; + + Assert.ok(notificationBoxes[1], "2nd window has a global notification box."); + + // Make sure that we have a coherent initial state. + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, "No version should be set on init."); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init."); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy."); + + let showAlertPromises = [ + promiseWaitForAlertActive(notificationBoxes[0]), + promiseWaitForAlertActive(notificationBoxes[1]) + ]; + + // This should be false and trigger the Infobar. + Assert.ok(!TelemetryReportingPolicy.canUpload(), + "User should not be allowed to upload and the infobar should be triggered."); + + yield Promise.all(showAlertPromises); + + // Both notification were displayed. Close one and check that both gets closed. + let closeAlertPromises = [ + promiseWaitForNotificationClose(notificationBoxes[0].currentNotification), + promiseWaitForNotificationClose(notificationBoxes[1].currentNotification) + ]; + notificationBoxes[0].currentNotification.close(); + yield Promise.all(closeAlertPromises); + + // Close the second window we opened. + yield BrowserTestUtils.closeWindow(otherWindow); + + // Check that we are clear to upload and that the policy data us saved. + Assert.ok(TelemetryReportingPolicy.canUpload(),"User should be allowed to upload now."); + Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true, + "User notified about datareporting policy."); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION, + "Version pref set."); + Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1, + "Date pref set."); +}); diff --git a/browser/base/content/test/general/browser_datareporting_notification.js b/browser/base/content/test/general/browser_datareporting_notification.js index c695a9fc21b1..85861d70568f 100644 --- a/browser/base/content/test/general/browser_datareporting_notification.js +++ b/browser/base/content/test/general/browser_datareporting_notification.js @@ -47,30 +47,6 @@ function sendNotifyRequest(name) { return [policy, deferred.promise]; } -/** - * Wait for a to be closed then call the specified callback. - */ -function waitForNotificationClose(notification, cb) { - let parent = notification.parentNode; - - let observer = new MutationObserver(function onMutatations(mutations) { - for (let mutation of mutations) { - for (let i = 0; i < mutation.removedNodes.length; i++) { - let node = mutation.removedNodes.item(i); - - if (node != notification) { - continue; - } - - observer.disconnect(); - cb(); - } - } - }); - - observer.observe(parent, {childList: true}); -} - let dumpAppender, rootLogger; function test() { diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index db2be4ddb754..ff6136a14934 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -9,6 +9,27 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", "resource://testing-common/PlacesTestUtils.jsm"); +/** + * Wait for a to be closed then call the specified callback. + */ +function waitForNotificationClose(notification, cb) { + let parent = notification.parentNode; + + let observer = new MutationObserver(function onMutatations(mutations) { + for (let mutation of mutations) { + for (let i = 0; i < mutation.removedNodes.length; i++) { + let node = mutation.removedNodes.item(i); + if (node != notification) { + continue; + } + observer.disconnect(); + cb(); + } + } + }); + observer.observe(parent, {childList: true}); +} + function closeAllNotifications () { let notificationBox = document.getElementById("global-notificationbox"); diff --git a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm index 400155cbd7cf..945f34f95de4 100644 --- a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm +++ b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm @@ -61,6 +61,17 @@ const NOTIFICATION_DELAY_FIRST_RUN_MSEC = 60 * 1000; // 60s // Same as above, for the next runs. const NOTIFICATION_DELAY_NEXT_RUNS_MSEC = 10 * 1000; // 10s +/** + * This is a policy object used to override behavior within this module. + * Tests override properties on this object to allow for control of behavior + * that would otherwise be very hard to cover. + */ +let Policy = { + now: () => new Date(), + setShowInfobarTimeout: (callback, delayMs) => setTimeout(callback, delayMs), + clearShowInfobarTimeout: (id) => clearTimeout(id), +}; + /** * Represents a request to display data policy. * @@ -130,6 +141,27 @@ this.TelemetryReportingPolicy = { canUpload: function() { return TelemetryReportingPolicyImpl.canUpload(); }, + + /** + * Test only method, restarts the policy. + */ + reset: function() { + return TelemetryReportingPolicyImpl.reset(); + }, + + /** + * Test only method, used to check if user is notified of the policy in tests. + */ + testIsUserNotified: function() { + return TelemetryReportingPolicyImpl.isUserNotifiedOfCurrentPolicy; + }, + + /** + * Test only method, used to simulate the infobar being shown in xpcshell tests. + */ + testInfobarShown: function() { + return TelemetryReportingPolicyImpl._infobarShownCallback(); + }, }; let TelemetryReportingPolicyImpl = { @@ -251,6 +283,14 @@ let TelemetryReportingPolicyImpl = { return true; }, + /** + * Test only method, restarts the policy. + */ + reset: function() { + this.shutdown(); + return this.setup(); + }, + /** * Setup the policy. */ @@ -272,7 +312,7 @@ let TelemetryReportingPolicyImpl = { this._detachObservers(); - clearTimeout(this._startupNotificationTimerId); + Policy.clearShowInfobarTimeout(this._startupNotificationTimerId); }, /** @@ -354,7 +394,7 @@ let TelemetryReportingPolicyImpl = { */ _recordNotificationData: function() { this._log.trace("_recordNotificationData"); - this.dataSubmissionPolicyNotifiedDate = new Date(); + this.dataSubmissionPolicyNotifiedDate = Policy.now(); this.dataSubmissionPolicyAcceptedVersion = this.currentPolicyVersion; // The user was notified and the notification data saved: the notification // is no longer in progress. @@ -370,7 +410,7 @@ let TelemetryReportingPolicyImpl = { const delay = isFirstRun ? NOTIFICATION_DELAY_FIRST_RUN_MSEC: NOTIFICATION_DELAY_NEXT_RUNS_MSEC; - this._startupNotificationTimerId = setTimeout( + this._startupNotificationTimerId = Policy.setShowInfobarTimeout( // Calling |canUpload| eventually shows the infobar, if needed. () => this.canUpload(), delay); // We performed at least a run, flip the firstRun preference. diff --git a/toolkit/components/telemetry/tests/unit/head.js b/toolkit/components/telemetry/tests/unit/head.js index e717440af61d..fd6f2ea29a52 100644 --- a/toolkit/components/telemetry/tests/unit/head.js +++ b/toolkit/components/telemetry/tests/unit/head.js @@ -238,6 +238,7 @@ function fakeNow(...args) { Cu.import("resource://gre/modules/TelemetryController.jsm"), Cu.import("resource://gre/modules/TelemetryStorage.jsm"), Cu.import("resource://gre/modules/TelemetrySend.jsm"), + Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm"), ]; for (let m of modules) { @@ -285,6 +286,8 @@ if (runningInParent) { Services.prefs.setCharPref("toolkit.telemetry.log.level", "Trace"); // Telemetry archiving should be on. Services.prefs.setBoolPref("toolkit.telemetry.archive.enabled", true); + // Telemetry xpcshell tests cannot show the infobar. + Services.prefs.setBoolPref("datareporting.policy.dataSubmissionPolicyBypassNotification", true); fakePingSendTimer((callback, timeout) => { Services.tm.mainThread.dispatch(() => callback(), Ci.nsIThread.DISPATCH_NORMAL); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js new file mode 100644 index 000000000000..e2bf87dab013 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js @@ -0,0 +1,255 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that TelemetryController sends close to shutdown don't lead +// to AsyncShutdown timeouts. + +"use strict"; + +Cu.import("resource://gre/modules/Preferences.jsm", this); +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/TelemetryController.jsm", this); +Cu.import("resource://gre/modules/TelemetrySend.jsm", this); +Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", this); +Cu.import("resource://gre/modules/TelemetryUtils.jsm", this); +Cu.import("resource://gre/modules/Timer.jsm", this); +Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); + +const PREF_BRANCH = "toolkit.telemetry."; +const PREF_ENABLED = PREF_BRANCH + "enabled"; +const PREF_SERVER = PREF_BRANCH + "server"; +const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled"; + +const TEST_CHANNEL = "TestChannelABC"; + +const PREF_POLICY_BRANCH = "datareporting.policy."; +const PREF_BYPASS_NOTIFICATION = PREF_POLICY_BRANCH + "dataSubmissionPolicyBypassNotification"; +const PREF_DATA_SUBMISSION_ENABLED = PREF_POLICY_BRANCH + "dataSubmissionEnabled"; +const PREF_CURRENT_POLICY_VERSION = PREF_POLICY_BRANCH + "currentPolicyVersion"; +const PREF_MINIMUM_POLICY_VERSION = PREF_POLICY_BRANCH + "minimumPolicyVersion"; +const PREF_MINIMUM_CHANNEL_POLICY_VERSION = PREF_MINIMUM_POLICY_VERSION + ".channel-" + TEST_CHANNEL; +const PREF_ACCEPTED_POLICY_VERSION = PREF_POLICY_BRANCH + "dataSubmissionPolicyAcceptedVersion"; +const PREF_ACCEPTED_POLICY_DATE = PREF_POLICY_BRANCH + "dataSubmissionPolicyNotifiedTime"; + +function fakeShowPolicyTimeout(set, clear) { + let reportingPolicy = Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm"); + reportingPolicy.Policy.setShowInfobarTimeout = set; + reportingPolicy.Policy.clearShowInfobarTimeout = clear; +} + +function fakeResetAcceptedPolicy() { + Preferences.reset(PREF_ACCEPTED_POLICY_DATE); + Preferences.reset(PREF_ACCEPTED_POLICY_VERSION); +} + +function run_test() { + // Addon manager needs a profile directory + do_get_profile(true); + loadAddonManager("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + + Services.prefs.setBoolPref(PREF_ENABLED, true); + // We need to disable FHR in order to use the policy from telemetry. + Services.prefs.setBoolPref(PREF_DRS_ENABLED, false); + // Don't bypass the notifications in this test, we'll fake it. + Services.prefs.setBoolPref(PREF_BYPASS_NOTIFICATION, false); + + TelemetryReportingPolicy.setup(); + + run_next_test(); +} + +add_task(function* test_firstRun() { + const PREF_FIRST_RUN = "toolkit.telemetry.reportingpolicy.firstRun"; + const FIRST_RUN_TIMEOUT_MSEC = 60 * 1000; // 60s + const OTHER_RUNS_TIMEOUT_MSEC = 10 * 1000; // 10s + + Preferences.reset(PREF_FIRST_RUN); + + let startupTimeout = 0; + fakeShowPolicyTimeout((callback, timeout) => startupTimeout = timeout, () => {}); + TelemetryReportingPolicy.reset(); + + Services.obs.notifyObservers(null, "sessionstore-windows-restored", null); + Assert.equal(startupTimeout, FIRST_RUN_TIMEOUT_MSEC, + "The infobar display timeout should be 60s on the first run."); + + // Run again, and check that we actually wait only 10 seconds. + TelemetryReportingPolicy.reset(); + Services.obs.notifyObservers(null, "sessionstore-windows-restored", null); + Assert.equal(startupTimeout, OTHER_RUNS_TIMEOUT_MSEC, + "The infobar display timeout should be 10s on other runs."); +}); + +add_task(function* test_prefs() { + TelemetryReportingPolicy.reset(); + + let now = fakeNow(2009, 11, 18); + + // If the date is not valid (earlier than 2012), we don't regard the policy as accepted. + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified()); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 0, + "Invalid dates should not make the policy accepted."); + + // Check that the notification date and version are correctly saved to the prefs. + now = fakeNow(2012, 11, 18); + TelemetryReportingPolicy.testInfobarShown(); + Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), now.getTime(), + "A valid date must correctly be saved."); + + // Now that user is notified, check if we are allowed to upload. + Assert.ok(TelemetryReportingPolicy.canUpload(), + "We must be able to upload after the policy is accepted."); + + // Disable submission and check that we're no longer allowed to upload. + Preferences.set(PREF_DATA_SUBMISSION_ENABLED, false); + Assert.ok(!TelemetryReportingPolicy.canUpload(), + "We must not be able to upload if data submission is disabled."); + + // Turn the submission back on. + Preferences.set(PREF_DATA_SUBMISSION_ENABLED, true); + Assert.ok(TelemetryReportingPolicy.canUpload(), + "We must be able to upload if data submission is enabled and the policy was accepted."); + + // Set a new minimum policy version and check that user is no longer notified. + let newMinimum = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) + 1; + Preferences.set(PREF_MINIMUM_POLICY_VERSION, newMinimum); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "A greater minimum policy version must invalidate the policy and disable upload."); + + // Eventually accept the policy and make sure user is notified. + Preferences.set(PREF_CURRENT_POLICY_VERSION, newMinimum); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok(TelemetryReportingPolicy.testIsUserNotified(), + "Accepting the policy again should show the user as notified."); + Assert.ok(TelemetryReportingPolicy.canUpload(), + "Accepting the policy again should let us upload data."); + + // Set a new, per channel, minimum policy version. Start by setting a test current channel. + let defaultPrefs = new Preferences({ defaultBranch: true }); + defaultPrefs.set("app.update.channel", TEST_CHANNEL); + + // Increase and set the new minimum version, then check that we're not notified anymore. + newMinimum++; + Preferences.set(PREF_MINIMUM_CHANNEL_POLICY_VERSION, newMinimum); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "Increasing the minimum policy version should invalidate the policy."); + + // Eventually accept the policy and make sure user is notified. + Preferences.set(PREF_CURRENT_POLICY_VERSION, newMinimum); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok(TelemetryReportingPolicy.testIsUserNotified(), + "Accepting the policy again should show the user as notified."); + Assert.ok(TelemetryReportingPolicy.canUpload(), + "Accepting the policy again should let us upload data."); +}); + +add_task(function* test_migratePrefs() { + const DEPRECATED_FHR_PREFS = { + "datareporting.policy.dataSubmissionPolicyAccepted": true, + "datareporting.policy.dataSubmissionPolicyBypassAcceptance": true, + "datareporting.policy.dataSubmissionPolicyResponseType": "foxyeah", + "datareporting.policy.dataSubmissionPolicyResponseTime": Date.now().toString(), + }; + + // Make sure the preferences are set before setting up the policy. + for (let name in DEPRECATED_FHR_PREFS) { + Preferences.set(name, DEPRECATED_FHR_PREFS[name]); + } + // Set up the policy. + TelemetryReportingPolicy.reset(); + // They should have been removed by now. + for (let name in DEPRECATED_FHR_PREFS) { + Assert.ok(!Preferences.has(name), name + " should have been removed."); + } +}); + +add_task(function* test_userNotifiedOfCurrentPolicy() { + fakeResetAcceptedPolicy(); + TelemetryReportingPolicy.reset(); + + // User should be reported as not notified by default. + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "The initial state should be unnotified."); + + // Forcing a policy version should not automatically make the user notified. + Preferences.set(PREF_ACCEPTED_POLICY_VERSION, + TelemetryReportingPolicy.DEFAULT_DATAREPORTING_POLICY_VERSION); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "The default state of the date should have a time of 0 and it should therefore fail"); + + // Showing the notification bar should make the user notified. + let now = fakeNow(2012, 11, 11); + TelemetryReportingPolicy.testInfobarShown(); + Assert.ok(TelemetryReportingPolicy.testIsUserNotified(), + "Using the proper API causes user notification to report as true."); + + // It is assumed that later versions of the policy will incorporate previous + // ones, therefore this should also return true. + let newVersion = + Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) + 1; + Preferences.set(PREF_ACCEPTED_POLICY_VERSION, newVersion); + Assert.ok(TelemetryReportingPolicy.testIsUserNotified(), + "A future version of the policy should pass."); + + newVersion = + Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) - 1; + Preferences.set(PREF_ACCEPTED_POLICY_VERSION, newVersion); + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "A previous version of the policy should fail."); +}); + +add_task(function* test_canSend() { + const TEST_PING_TYPE = "test-ping"; + + PingServer.start(); + Preferences.set(PREF_SERVER, "http://localhost:" + PingServer.port); + + yield TelemetryController.reset(); + TelemetryReportingPolicy.reset(); + + // User should be reported as not notified by default. + Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), + "The initial state should be unnotified."); + + // Assert if we receive any ping before the policy is accepted. + PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now")); + yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Reset the ping handler. + PingServer.resetPingHandler(); + + // Fake the infobar: this should also trigger the ping send task. + TelemetryReportingPolicy.testInfobarShown(); + let ping = yield PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal(ping[0].type, TEST_PING_TYPE, + "We should have received the previous ping."); + + // Submit another ping, to make sure it gets sent. + yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Get the ping and check its type. + ping = yield PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the new ping."); + + // Fake a restart with a pending ping. + yield TelemetryController.addPendingPing(TEST_PING_TYPE, {}); + yield TelemetryController.reset(); + + // We should be immediately sending the ping out. + ping = yield PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the pending ping."); + + // Submit another ping, to make sure it gets sent. + yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {}); + + // Get the ping and check its type. + ping = yield PingServer.promiseNextPings(1); + Assert.equal(ping.length, 1, "We should have received one ping."); + Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the new ping."); + + yield PingServer.stop(); +}); diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.ini b/toolkit/components/telemetry/tests/unit/xpcshell.ini index 54600c0674a7..941050457170 100644 --- a/toolkit/components/telemetry/tests/unit/xpcshell.ini +++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini @@ -53,3 +53,4 @@ run-sequentially = Bug 1046307, test can fail intermittently when CPU load is hi [test_TelemetrySend.js] [test_ChildHistograms.js] skip-if = os == "android" +[test_TelemetryReportingPolicy.js] From 033560bf9ff0e4e7c2f2b9bee97910e921fe46f7 Mon Sep 17 00:00:00 2001 From: Alessio Placitelli Date: Fri, 26 Jun 2015 16:33:00 +0200 Subject: [PATCH 11/90] Bug 1137355 - Document the preferences used by the data choices infobar. r=gfritzsche --- .../components/telemetry/docs/preferences.rst | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/toolkit/components/telemetry/docs/preferences.rst b/toolkit/components/telemetry/docs/preferences.rst index ed80f250ad29..ddcba12bb3f2 100644 --- a/toolkit/components/telemetry/docs/preferences.rst +++ b/toolkit/components/telemetry/docs/preferences.rst @@ -44,3 +44,38 @@ Sending only happens on official builds with ``MOZ_TELEMETRY_REPORTING`` defined ``toolkit.telemetry.log.dump`` Sets whether to dump Telemetry log messages to ``stdout`` too. + +Data-choices notification +------------------------- + +``toolkit.telemetry.reportingpolicy.firstRun`` + + This preference is not present until the first run. After, its value is set to false. This is used to show the infobar with a more aggressive timeout if it wasn't shown yet. + +``datareporting.policy.dataSubmissionEnabled`` + + This is the data submission master kill switch. If disabled, no policy is shown or upload takes place, ever. + +``datareporting.policy.dataSubmissionPolicyNotifiedTime`` + + Records the date user was shown the policy. This preference is also used on Android. + +``datareporting.policy.dataSubmissionPolicyAcceptedVersion`` + + Records the version of the policy notified to the user. This preference is also used on Android. + +``datareporting.policy.dataSubmissionPolicyBypassNotification`` + + Used in tests, it allows to skip the notification check. + +``datareporting.policy.currentPolicyVersion`` + + Stores the current policy version, overrides the default value defined in TelemetryReportingPolicy.jsm. + +``datareporting.policy.minimumPolicyVersion`` + + The minimum policy version that is accepted for the current policy. This can be set per channel. + +``datareporting.policy.minimumPolicyVersion.channel-NAME`` + + This is the only channel-specific version that we currently use for the minimum policy version. From 8e3d94436ae3cc0a6073fb564f3eee9444dc8749 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Thu, 23 Jul 2015 16:38:49 -0700 Subject: [PATCH 12/90] Bug 1164325 - Fix uninverting the profiler call tree. (r=jsantell) --- .../performance/modules/logic/tree-model.js | 59 ++++++++---- .../test/unit/test_tree-model-12.js | 93 +++++++++++++++++++ .../test/unit/test_tree-model-13.js | 85 +++++++++++++++++ .../performance/test/unit/xpcshell.ini | 2 + 4 files changed, 222 insertions(+), 17 deletions(-) create mode 100644 browser/devtools/performance/test/unit/test_tree-model-12.js create mode 100644 browser/devtools/performance/test/unit/test_tree-model-13.js diff --git a/browser/devtools/performance/modules/logic/tree-model.js b/browser/devtools/performance/modules/logic/tree-model.js index 2ab1d4acb60f..d7438eec5aae 100644 --- a/browser/devtools/performance/modules/logic/tree-model.js +++ b/browser/devtools/performance/modules/logic/tree-model.js @@ -251,18 +251,18 @@ ThreadNode.prototype = { * Uninverts the call tree after its having been built. */ _uninvert: function uninvert() { - function mergeOrAddFrameNode(calls, node) { + function mergeOrAddFrameNode(calls, node, samples) { // Unlike the inverted call tree, we don't use a root table for the top // level, as in general, there are many fewer entry points than // leaves. Instead, linear search is used regardless of level. for (let i = 0; i < calls.length; i++) { if (calls[i].key === node.key) { let foundNode = calls[i]; - foundNode._merge(node); + foundNode._merge(node, samples); return foundNode.calls; } } - let copy = node._clone(); + let copy = node._clone(samples); calls.push(copy); return copy.calls; } @@ -280,19 +280,42 @@ ThreadNode.prototype = { let node = entry.node; let calls = node.calls; + let callSamples = 0; - if (calls.length === 0) { - // We've bottomed out. Reverse the spine and add them to the - // uninverted call tree. + // Continue the depth-first walk. + for (let i = 0; i < calls.length; i++) { + workstack.push({ node: calls[i], level: entry.level + 1 }); + callSamples += calls[i].samples; + } + + // The sample delta is used to distinguish stacks. + // + // Suppose we have the following stack samples: + // + // A -> B + // A -> C + // A + // + // The inverted tree is: + // + // A + // / \ + // B C + // + // with A.samples = 3, B.samples = 1, C.samples = 1. + // + // A is distinguished as being its own stack because + // A.samples - (B.samples + C.samples) > 0. + // + // Note that bottoming out is a degenerate where callSamples = 0. + + let samplesDelta = node.samples - callSamples; + if (samplesDelta > 0) { + // Reverse the spine and add them to the uninverted call tree. let uninvertedCalls = rootCalls; for (let level = entry.level; level > 0; level--) { let callee = spine[level]; - uninvertedCalls = mergeOrAddFrameNode(uninvertedCalls, callee.node); - } - } else { - // We still have children. Continue the depth-first walk. - for (let i = 0; i < calls.length; i++) { - workstack.push({ node: calls[i], level: entry.level + 1 }); + uninvertedCalls = mergeOrAddFrameNode(uninvertedCalls, callee.node, samplesDelta); } } } @@ -410,19 +433,21 @@ FrameNode.prototype = { } }, - _clone: function () { + _clone: function (samples) { let newNode = new FrameNode(this.key, this, this.isMetaCategory); - newNode._merge(this); + newNode._merge(this, samples); return newNode; }, - _merge: function (otherNode) { + _merge: function (otherNode, samples) { if (this === otherNode) { return; } - this.samples += otherNode.samples; - this.youngestFrameSamples += otherNode.youngestFrameSamples; + this.samples += samples; + if (otherNode.youngestFrameSamples > 0) { + this.youngestFrameSamples += samples; + } if (otherNode._optimizations) { let opts = this._optimizations; diff --git a/browser/devtools/performance/test/unit/test_tree-model-12.js b/browser/devtools/performance/test/unit/test_tree-model-12.js new file mode 100644 index 000000000000..79ab395bdb43 --- /dev/null +++ b/browser/devtools/performance/test/unit/test_tree-model-12.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that uninverting the call tree works correctly when there are stacks +// in the profile that prefixes of other stacks. + +function run_test() { + run_next_test(); +} + +add_task(function () { + let { ThreadNode } = devtools.require("devtools/performance/tree-model"); + let thread = new ThreadNode(gThread, { startTime: 0, endTime: 50 }); + let root = getFrameNodePath(thread, "(root)"); + + /** + * Samples + * + * A->B + * C->B + * B + * A + * Z->Y->X + * W->Y->X + * Y->X + */ + + equal(getFrameNodePath(root, "A > B").youngestFrameSamples, 1, + "A > B has the correct self count"); + equal(getFrameNodePath(root, "C > B").youngestFrameSamples, 1, + "C > B has the correct self count"); + equal(getFrameNodePath(root, "B").youngestFrameSamples, 1, + "B has the correct self count"); + equal(getFrameNodePath(root, "A").youngestFrameSamples, 1, + "A has the correct self count"); + equal(getFrameNodePath(root, "Z > Y > X").youngestFrameSamples, 1, + "Z > Y > X has the correct self count"); + equal(getFrameNodePath(root, "W > Y > X").youngestFrameSamples, 1, + "W > Y > X has the correct self count"); + equal(getFrameNodePath(root, "Y > X").youngestFrameSamples, 1, + "Y > X has the correct self count"); +}); + +let gThread = synthesizeProfileForTest([{ + time: 5, + frames: [ + { location: "(root)" }, + { location: "A" }, + { location: "B" }, + ] +}, { + time: 10, + frames: [ + { location: "(root)" }, + { location: "C" }, + { location: "B" }, + ] +}, { + time: 15, + frames: [ + { location: "(root)" }, + { location: "B" }, + ] +},{ + time: 20, + frames: [ + { location: "(root)" }, + { location: "A" }, + ] +}, { + time: 21, + frames: [ + { location: "(root)" }, + { location: "Z" }, + { location: "Y" }, + { location: "X" }, + ] +}, { + time: 22, + frames: [ + { location: "(root)" }, + { location: "W" }, + { location: "Y" }, + { location: "X" }, + ] +}, { + time: 23, + frames: [ + { location: "(root)" }, + { location: "Y" }, + { location: "X" }, + ] +}]); diff --git a/browser/devtools/performance/test/unit/test_tree-model-13.js b/browser/devtools/performance/test/unit/test_tree-model-13.js new file mode 100644 index 000000000000..3ef78d83a87e --- /dev/null +++ b/browser/devtools/performance/test/unit/test_tree-model-13.js @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Like test_tree-model-12, but inverted. + +function run_test() { + run_next_test(); +} + +add_task(function () { + let { ThreadNode } = devtools.require("devtools/performance/tree-model"); + let root = new ThreadNode(gThread, { invertTree: true, startTime: 0, endTime: 50 }); + + /** + * Samples + * + * A->B + * C->B + * B + * A + * Z->Y->X + * W->Y->X + * Y->X + */ + + equal(getFrameNodePath(root, "B").youngestFrameSamples, 3, + "B has the correct self count"); + equal(getFrameNodePath(root, "A").youngestFrameSamples, 1, + "A has the correct self count"); + equal(getFrameNodePath(root, "X").youngestFrameSamples, 3, + "X has the correct self count"); + equal(getFrameNodePath(root, "X > Y").samples, 3, + "X > Y has the correct total count"); +}); + +let gThread = synthesizeProfileForTest([{ + time: 5, + frames: [ + { location: "(root)" }, + { location: "A" }, + { location: "B" }, + ] +}, { + time: 10, + frames: [ + { location: "(root)" }, + { location: "C" }, + { location: "B" }, + ] +}, { + time: 15, + frames: [ + { location: "(root)" }, + { location: "B" }, + ] +},{ + time: 20, + frames: [ + { location: "(root)" }, + { location: "A" }, + ] +}, { + time: 21, + frames: [ + { location: "(root)" }, + { location: "Z" }, + { location: "Y" }, + { location: "X" }, + ] +}, { + time: 22, + frames: [ + { location: "(root)" }, + { location: "W" }, + { location: "Y" }, + { location: "X" }, + ] +}, { + time: 23, + frames: [ + { location: "(root)" }, + { location: "Y" }, + { location: "X" }, + ] +}]); diff --git a/browser/devtools/performance/test/unit/xpcshell.ini b/browser/devtools/performance/test/unit/xpcshell.ini index e4ee2923e918..59814cc093ad 100644 --- a/browser/devtools/performance/test/unit/xpcshell.ini +++ b/browser/devtools/performance/test/unit/xpcshell.ini @@ -24,6 +24,8 @@ skip-if = toolkit == 'android' || toolkit == 'gonk' [test_tree-model-09.js] [test_tree-model-10.js] [test_tree-model-11.js] +[test_tree-model-12.js] +[test_tree-model-13.js] [test_waterfall-utils-collapse-01.js] [test_waterfall-utils-collapse-02.js] [test_waterfall-utils-collapse-03.js] From 798b7bf08b79bdc09a6d859d7a2d692b0c0d8ba4 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:08:59 -0700 Subject: [PATCH 13/90] Bug 1184199 - Use a Map instead of a plain object to avoid the "constructor" property, r=jonco --HG-- extra : commitid : C4mNPyL6sQC extra : rebase_source : 1fceec4e2c1a1a8b12afa1a1770309775c2da9bb --- js/src/devtools/rootAnalysis/computeGCTypes.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index 97d60d843d49..d72d2f223672 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -74,7 +74,7 @@ var gcTypes = {}; // map from parent struct => Set of GC typed children var gcPointers = {}; // map from parent struct => Set of GC typed children var nonGCTypes = {}; // set of types that would ordinarily be GC types but we are suppressing var nonGCPointers = {}; // set of types that would ordinarily be GC pointers but we are suppressing -var gcFields = {}; +var gcFields = new Map; // "typeName is a (pointer to a)*'depth' GC type because it contains a field // named 'child' of type 'why' (or pointer to 'why' if ptrdness == 1), which @@ -119,9 +119,9 @@ function markGCType(typeName, child, why, depth, ptrdness) gcPointers[typeName].add(why); } - if (!(typeName in gcFields)) - gcFields[typeName] = new Map(); - gcFields[typeName].set(why, [ child, ptrdness ]); + if (!gcFields.has(typeName)) + gcFields.set(typeName, new Map()); + gcFields.get(typeName).set(child, [ why, ptrdness ]); if (typeName in structureParents) { for (var field of structureParents[typeName]) { @@ -163,17 +163,19 @@ function explain(csu, indent, seen) { if (!seen) seen = new Set(); seen.add(csu); - if (!(csu in gcFields)) + if (!gcFields.has(csu)) return; - if (gcFields[csu].has('')) { + var fields = gcFields.get(csu); + + if (fields.has('')) { print(indent + "which is a GCThing because I said so"); return; } - if (gcFields[csu].has('')) { + if (fields.has('')) { print(indent + "which is a GCPointer because I said so"); return; } - for (var [ field, [ child, ptrdness ] ] of gcFields[csu]) { + for (var [ field, [ child, ptrdness ] ] of fields) { var inherit = ""; if (field == "field:0") inherit = " (probably via inheritance)"; From 0854f1474322b8c8e5812ea130f46d6dbbfdc684 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:09:11 -0700 Subject: [PATCH 14/90] Bug 1184199 - Add an explanation only if there is something to explain, r=jonco --HG-- extra : commitid : ABeyzTPRuce extra : rebase_source : d7ca70912e6c5e1edaa313651ac9233318c1df66 --- js/src/devtools/rootAnalysis/computeGCTypes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index d72d2f223672..9b995a1518e0 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -119,9 +119,11 @@ function markGCType(typeName, child, why, depth, ptrdness) gcPointers[typeName].add(why); } + if (depth < 2) { if (!gcFields.has(typeName)) gcFields.set(typeName, new Map()); gcFields.get(typeName).set(child, [ why, ptrdness ]); + } if (typeName in structureParents) { for (var field of structureParents[typeName]) { From 7fda7ed1f24cd2bd66660592ba700cf52ce64c73 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:09:25 -0700 Subject: [PATCH 15/90] Bug 1182428 - Improve naming, r=jonco --HG-- extra : commitid : DJf4Fed6IcS extra : rebase_source : 5c647ec9baf626ef46237475dfb4e9d21b1dab11 --- .../devtools/rootAnalysis/computeGCTypes.js | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index 9b995a1518e0..a975ce43d8dc 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -76,42 +76,58 @@ var nonGCTypes = {}; // set of types that would ordinarily be GC types but we ar var nonGCPointers = {}; // set of types that would ordinarily be GC pointers but we are suppressing var gcFields = new Map; -// "typeName is a (pointer to a)*'depth' GC type because it contains a field -// named 'child' of type 'why' (or pointer to 'why' if ptrdness == 1), which +function stars(n) { return n ? '*' + stars(n-1) : '' }; + +// "typeName is a (pointer to a)^'typePtrLevel' GC type because it contains a field +// named 'child' of type 'why' (or pointer to 'why' if fieldPtrLevel == 1), which is // itself a GCThing or GCPointer." -function markGCType(typeName, child, why, depth, ptrdness) +function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent) { + //printErr(`${indent}${typeName}${stars(typePtrLevel)} may be a gctype/ptr because of its child '${child}' of type ${why}${stars(fieldPtrLevel)}`); + // Some types, like UniquePtr, do not mark/trace/relocate their contained // pointers and so should not hold them live across a GC. UniquePtr in // particular should be the only thing pointing to a structure containing a - // GCPointer, so nothing else can be tracing it and it'll die when the - // UniquePtr goes out of scope. So we say that a UniquePtr's memory is just - // as unsafe as the stack for storing GC pointers. - if (!ptrdness && isUnsafeStorage(typeName)) { + // GCPointer, so nothing else can possibly trace it and it'll die when the + // UniquePtr goes out of scope. So we say that memory pointed to by a + // UniquePtr is just as unsafe as the stack for storing GC pointers. + if (!fieldPtrLevel && isUnsafeStorage(typeName)) { // The UniquePtr itself is on the stack but when you dereference the // contained pointer, you get to the unsafe memory that we are treating - // as if it were the stack (aka depth 0). Note that + // as if it were the stack (aka ptrLevel 0). Note that // UniquePtr> is fine, so we don't want to just - // hardcode the depth. - ptrdness = -1; + // hardcode the ptrLevel. + fieldPtrLevel = -1; } - depth += ptrdness; - if (depth > 2) + // Example: with: + // struct Pair { JSObject* foo; int bar; }; + // struct { Pair** info }*** + // make a call to: + // child='info' typePtrLevel=3 fieldPtrLevel=2 + // for a final ptrLevel of 5, used to later call: + // child='foo' typePtrLevel=5 fieldPtrLevel=1 + // + var ptrLevel = typePtrLevel + fieldPtrLevel; + + // ...except when > 2 levels of pointers away from an actual GC thing, stop + // searching the graph. (This would just be > 1, except that a UniquePtr + // field might still have a GC pointer.) + if (ptrLevel > 2) return; - if (depth == 0 && isRootedTypeName(typeName)) + if (ptrLevel == 0 && isRootedTypeName(typeName)) return; - if (depth == 1 && isRootedPointerTypeName(typeName)) + if (ptrLevel == 1 && isRootedPointerTypeName(typeName)) return; - if (depth == 0) { + if (ptrLevel == 0) { if (typeName in nonGCTypes) return; if (!(typeName in gcTypes)) gcTypes[typeName] = new Set(); gcTypes[typeName].add(why); - } else if (depth == 1) { + } else if (ptrLevel == 1) { if (typeName in nonGCPointers) return; if (!(typeName in gcPointers)) @@ -119,34 +135,34 @@ function markGCType(typeName, child, why, depth, ptrdness) gcPointers[typeName].add(why); } - if (depth < 2) { + if (ptrLevel < 2) { if (!gcFields.has(typeName)) gcFields.set(typeName, new Map()); - gcFields.get(typeName).set(child, [ why, ptrdness ]); + gcFields.get(typeName).set(child, [ why, fieldPtrLevel ]); } if (typeName in structureParents) { for (var field of structureParents[typeName]) { var [ holderType, fieldName ] = field; - markGCType(holderType, typeName, fieldName, depth, 0); + markGCType(holderType, fieldName, typeName, ptrLevel, 0, indent + " "); } } if (typeName in pointerParents) { for (var field of pointerParents[typeName]) { var [ holderType, fieldName ] = field; - markGCType(holderType, typeName, fieldName, depth, 1); + markGCType(holderType, fieldName, typeName, ptrLevel, 1, indent + " "); } } } -function addGCType(typeName, child, why, depth, ptrdness) +function addGCType(typeName, child, why, depth, fieldPtrLevel) { - markGCType(typeName, 'annotation', '', 0, 0); + markGCType(typeName, '', '(annotation)', 0, 0, ""); } function addGCPointer(typeName) { - markGCType(typeName, 'annotation', '', 1, 0); + markGCType(typeName, '', '(annotation)', 1, 0, ""); } for (var type of listNonGCTypes()) From 8db39947288b4d4d510eee24997d127a62812689 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:09:40 -0700 Subject: [PATCH 16/90] Bug 1182428 - Accept more edge types in edgeCanGC, r=jonco --HG-- extra : commitid : 6E8adRfKL88 extra : rebase_source : b7c1bb5a0698809a916ddbae2e59d956ccab4fb7 --- js/src/devtools/rootAnalysis/analyzeRoots.js | 29 ++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/js/src/devtools/rootAnalysis/analyzeRoots.js b/js/src/devtools/rootAnalysis/analyzeRoots.js index 48e94be158e8..d76b120a09a6 100644 --- a/js/src/devtools/rootAnalysis/analyzeRoots.js +++ b/js/src/devtools/rootAnalysis/analyzeRoots.js @@ -280,27 +280,34 @@ function edgeCanGC(edge) { if (edge.Kind != "Call") return false; + var callee = edge.Exp[0]; + + while (callee.Kind == "Drf") + callee = callee.Exp[0]; + if (callee.Kind == "Var") { var variable = callee.Variable; - assert(variable.Kind == "Func"); - var callee = mangled(variable.Name[0]); - if ((callee in gcFunctions) || ((callee + internalMarker) in gcFunctions)) - return "'" + variable.Name[0] + "'"; - return null; + + if (variable.Kind == "Func") { + var callee = mangled(variable.Name[0]); + if ((callee in gcFunctions) || ((callee + internalMarker) in gcFunctions)) + return "'" + variable.Name[0] + "'"; + return null; + } + + var varName = variable.Name[0]; + return indirectCallCannotGC(functionName, varName) ? null : "*" + varName; } - assert(callee.Kind == "Drf"); - if (callee.Exp[0].Kind == "Fld") { - var field = callee.Exp[0].Field; + + if (callee.Kind == "Fld") { + var field = callee.Field; var csuName = field.FieldCSU.Type.Name; var fullFieldName = csuName + "." + field.Name[0]; if (fieldCallCannotGC(csuName, fullFieldName)) return null; return (fullFieldName in suppressedFunctions) ? null : fullFieldName; } - assert(callee.Exp[0].Kind == "Var"); - var varName = callee.Exp[0].Variable.Name[0]; - return indirectCallCannotGC(functionName, varName) ? null : "*" + varName; } // Search recursively through predecessors from a variable use, returning From cfd09bd6f82006053e4ea63c6d1fbede623a2dda Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:09:58 -0700 Subject: [PATCH 17/90] Bug 1182428 - Recognize more rooted type names, r=jonco --HG-- extra : commitid : 7EiE2xX8BQt extra : rebase_source : 7a53c758eb19d39463c0664892ad06615fc454c2 --- js/src/devtools/rootAnalysis/annotations.js | 37 +++++++++++-------- .../devtools/rootAnalysis/computeGCTypes.js | 4 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 9ab6908009c5..d047545abad6 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -245,21 +245,6 @@ function ignoreGCFunction(mangled) return false; } -function isRootedTypeName(name) -{ - if (name == "mozilla::ErrorResult" || - name == "JSErrorResult" || - name == "WrappableJSErrorResult" || - name == "js::frontend::TokenStream" || - name == "js::frontend::TokenStream::Position" || - name == "ModuleCompiler" || - name == "JSAddonId") - { - return true; - } - return false; -} - function stripUCSAndNamespace(name) { if (name.startsWith('struct ')) @@ -282,16 +267,36 @@ function stripUCSAndNamespace(name) return name; } -function isRootedPointerTypeName(name) +function isRootedGCTypeName(name) +{ + return (name == "JSAddonId"); +} + +function isRootedGCPointerTypeName(name) { name = stripUCSAndNamespace(name); if (name.startsWith('MaybeRooted<')) return /\(js::AllowGC\)1u>::RootType/.test(name); + if (name == "ErrorResult" || + name == "JSErrorResult" || + name == "WrappableJSErrorResult" || + name == "frontend::TokenStream" || + name == "frontend::TokenStream::Position" || + name == "ModuleCompiler") + { + return true; + } + return name.startsWith('Rooted') || name.startsWith('PersistentRooted'); } +function isRootedTypeName(name) +{ + return isRootedGCTypeName(name) || isRootedGCPointerTypeName(name); +} + function isUnsafeStorage(typeName) { typeName = stripUCSAndNamespace(typeName); diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index a975ce43d8dc..610b2a1c6a62 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -116,9 +116,9 @@ function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent) if (ptrLevel > 2) return; - if (ptrLevel == 0 && isRootedTypeName(typeName)) + if (ptrLevel == 0 && isRootedGCTypeName(typeName)) return; - if (ptrLevel == 1 && isRootedPointerTypeName(typeName)) + if (ptrLevel == 1 && isRootedGCPointerTypeName(typeName)) return; if (ptrLevel == 0) { From b1a58dcb1455c57940f583c173c251a6a492c21a Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 13:10:33 -0700 Subject: [PATCH 18/90] Bug 1182428 - Fix the ObjectGroup hazards, r=jonco --HG-- extra : commitid : 87RBt2lJOzb extra : rebase_source : 00919ace203d0604dc8666f6841959a1153dd577 --- js/src/vm/ObjectGroup.cpp | 4 ++-- js/src/vm/TypeInference.h | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index e400eded326c..70b6a4478442 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -803,7 +803,7 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, } // Get a type which captures all the elements in the array to be created. - TypeSet::Type elementType = TypeSet::UnknownType(); + Rooted elementType(cx, TypeSet::UnknownType()); if (arrayKind != NewArrayKind::UnknownIndex && length != 0) { elementType = GetValueTypeForTable(vp[0]); for (unsigned i = 1; i < length; i++) { @@ -860,7 +860,7 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, group->setPreliminaryObjects(preliminaryObjects); } - if (!p.add(cx, *table, key, group)) + if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group)) return nullptr; } diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index fff951f462fc..9837ef51d1a6 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -272,7 +272,7 @@ class TypeSet // Information about a single concrete type. We pack this into one word, // where small values are particular primitive or other singleton types and // larger values are either specific JS objects or object groups. - class Type + class Type : public JS::StaticTraceable { friend class TypeSet; @@ -350,6 +350,10 @@ class TypeSet inline ObjectGroup* group() const; inline ObjectGroup* groupNoBarrier() const; + static void trace(Type* v, JSTracer* trc) { + MarkTypeUnbarriered(trc, v, "TypeSet::Type"); + } + bool operator == (Type o) const { return data == o.data; } bool operator != (Type o) const { return data != o.data; } }; From dcb4db6433c82d3da83fdfa0505bedeb18167e5d Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 14 Jul 2015 16:34:48 -0700 Subject: [PATCH 19/90] Bug 1182428 - Consider TypeSet stuff to be GCPointers, since they can contain them, r=jonco --HG-- extra : commitid : AThLO9udO2Y extra : rebase_source : 0f481fc390d6dfba25c613aac12a628410f19c32 --- js/src/devtools/rootAnalysis/annotations.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index d047545abad6..719b3c138803 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -362,6 +362,10 @@ function listGCPointers() { 'JS::Value', 'jsid', + 'js::TypeSet', + 'js::TypeSet::ObjectKey', + 'js::TypeSet::Type', + // AutoCheckCannotGC should also not be held live across a GC function. 'JS::AutoCheckCannotGC', ]; From 2b769d805bec88d6bba0bc276ced5838712c1dab Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 23 Jul 2015 16:35:08 -0700 Subject: [PATCH 20/90] Bug 1186259 - Record the path to GCC to avoid mismatched gcc/plugin versions, r=terrence --HG-- extra : commitid : AwF7F0XJvv extra : rebase_source : 678e5719494d0b5f8cb5d396ac0f1159442da1d7 --- js/src/devtools/rootAnalysis/analyze.py | 2 +- testing/mozharness/mozharness/mozilla/building/hazards.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/devtools/rootAnalysis/analyze.py b/js/src/devtools/rootAnalysis/analyze.py index e4de4f1c4f9b..109cc7d713e6 100755 --- a/js/src/devtools/rootAnalysis/analyze.py +++ b/js/src/devtools/rootAnalysis/analyze.py @@ -18,7 +18,7 @@ import re def env(config): e = dict(os.environ) - e['PATH'] = '%s:%s' % (e['PATH'], config['sixgill_bin']) + e['PATH'] = ':'.join(p for p in (config.get('gcc_bin'), config.get('sixgill_bin'), e['PATH']) if p) e['XDB'] = '%(sixgill_bin)s/xdb.so' % config e['SOURCE'] = config['source'] e['ANALYZED_OBJDIR'] = config['objdir'] diff --git a/testing/mozharness/mozharness/mozilla/building/hazards.py b/testing/mozharness/mozharness/mozilla/building/hazards.py index d6f4f282dec3..79bfb3efcc69 100644 --- a/testing/mozharness/mozharness/mozilla/building/hazards.py +++ b/testing/mozharness/mozharness/mozilla/building/hazards.py @@ -85,6 +85,7 @@ class HazardAnalysis(object): 'source': os.path.join(dirs['abs_work_dir'], 'source'), 'sixgill': os.path.join(dirs['abs_work_dir'], builder.config['sixgill']), 'sixgill_bin': os.path.join(dirs['abs_work_dir'], builder.config['sixgill_bin']), + 'gcc_bin': os.path.join(dirs['abs_work_dir'], 'gcc'), } defaults = """ js = '%(js)s' @@ -93,7 +94,8 @@ objdir = '%(source_objdir)s' source = '%(source)s' sixgill = '%(sixgill)s' sixgill_bin = '%(sixgill_bin)s' -jobs = 2 +gcc_bin = '%(gcc_bin)s' +jobs = 4 """ % values defaults_path = os.path.join(analysis_dir, 'defaults.py') From 76b36e0a0567885253f1eb45c2167d0a814ea5c9 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 24 Jul 2015 09:45:00 +1000 Subject: [PATCH 21/90] Bug 1160014 part 5 - Implement fullscreen transition on Mac. r=smichaud --HG-- extra : source : 3ff3e6db3475b98f9b873d01f70f6b12bce1d44d --- widget/cocoa/nsCocoaWindow.h | 6 +++ widget/cocoa/nsCocoaWindow.mm | 86 +++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index cc7660fc9240..ce895c60a6cd 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -285,7 +285,13 @@ public: nsIWidget *aWidget, bool aActivate) override; NS_IMETHOD SetSizeMode(int32_t aMode) override; NS_IMETHOD HideWindowChrome(bool aShouldHide) override; + void EnteredFullScreen(bool aFullScreen, bool aNativeMode = true); + virtual bool PrepareForFullscreenTransition(nsISupports** aData) override; + virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage, + uint16_t aDuration, + nsISupports* aData, + nsIRunnable* aCallback) override; NS_IMETHOD MakeFullScreen( bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override final; NS_IMETHOD MakeFullScreenWithNativeTransition( diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 0a570f174a86..ca22ad837064 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -1,4 +1,5 @@ /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -33,6 +34,7 @@ #include "nsIScreenManager.h" #include "nsIWidgetListener.h" #include "nsIPresShell.h" +#include "nsScreenCocoa.h" #include "gfxPlatform.h" #include "qcms.h" @@ -1265,6 +1267,90 @@ NS_IMETHODIMP nsCocoaWindow::HideWindowChrome(bool aShouldHide) NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } +class FullscreenTransitionData : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + explicit FullscreenTransitionData(NSWindow* aWindow) + : mTransitionWindow(aWindow) { } + + NSWindow* mTransitionWindow; + +private: + virtual ~FullscreenTransitionData() + { + [mTransitionWindow close]; + } +}; + +NS_IMPL_ISUPPORTS0(FullscreenTransitionData) + +@interface FullscreenTransitionDelegate : NSObject +{ +@public + nsIRunnable* mCallback; +} +@end + +@implementation FullscreenTransitionDelegate +- (void)animationDidEnd:(NSAnimation *)animation +{ + [animation setDelegate:nil]; + [self autorelease]; + // The caller should have added ref for us. + NS_DispatchToMainThread(already_AddRefed(mCallback)); +} +@end + +/* virtual */ bool +nsCocoaWindow::PrepareForFullscreenTransition(nsISupports** aData) +{ + nsCOMPtr widgetScreen = GetWidgetScreen(); + nsScreenCocoa* screen = static_cast(widgetScreen.get()); + NSScreen* cocoaScreen = screen->CocoaScreen(); + + NSWindow* win = + [[NSWindow alloc] initWithContentRect:[cocoaScreen frame] + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + [win setBackgroundColor:[NSColor blackColor]]; + [win setAlphaValue:0]; + [win setIgnoresMouseEvents:YES]; + [win setLevel:NSScreenSaverWindowLevel]; + [win makeKeyAndOrderFront:nil]; + + auto data = new FullscreenTransitionData(win); + *aData = data; + NS_ADDREF(data); + return true; +} + +/* virtual */ void +nsCocoaWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage, + uint16_t aDuration, + nsISupports* aData, + nsIRunnable* aCallback) +{ + auto data = static_cast(aData); + FullscreenTransitionDelegate* delegate = + [[FullscreenTransitionDelegate alloc] init]; + // Storing already_AddRefed directly could cause static checking fail. + delegate->mCallback = nsCOMPtr(aCallback).forget().take(); + + NSDictionary* dict = @{ + NSViewAnimationTargetKey: data->mTransitionWindow, + NSViewAnimationEffectKey: aStage == eBeforeFullscreenToggle ? + NSViewAnimationFadeInEffect : NSViewAnimationFadeOutEffect + }; + NSAnimation* animation = + [[[NSViewAnimation alloc] initWithViewAnimations:@[dict]] autorelease]; + [animation setDelegate:delegate]; + [animation setDuration:aDuration / 1000.0]; + [animation startAnimation]; +} + void nsCocoaWindow::EnteredFullScreen(bool aFullScreen, bool aNativeMode) { mInFullScreenTransition = false; From 7ec583cc8f41cc5af9c338bfe2f2d47532860024 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 24 Jul 2015 09:45:00 +1000 Subject: [PATCH 22/90] Bug 1160014 part 6 - Implement fullscreen transition for GTK. r=roc --HG-- extra : source : ae8bf45b7efcd297ad92039b5ea6985dbfa725e9 --- widget/gtk/mozgtk/mozgtk.c | 4 ++ widget/gtk/nsWindow.cpp | 111 +++++++++++++++++++++++++++++++++++++ widget/gtk/nsWindow.h | 5 ++ 3 files changed, 120 insertions(+) diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index 697de376cec9..00e60834b51b 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -61,6 +61,7 @@ STUB(gdk_screen_get_resolution) STUB(gdk_screen_get_rgba_visual) STUB(gdk_screen_get_root_window) STUB(gdk_screen_get_system_visual) +STUB(gdk_screen_get_width) STUB(gdk_screen_height) STUB(gdk_screen_is_composited) STUB(gdk_screen_width) @@ -437,11 +438,14 @@ STUB(gtk_widget_hide) STUB(gtk_widget_is_focus) STUB(gtk_widget_is_toplevel) STUB(gtk_widget_map) +STUB(gtk_widget_modify_bg) STUB(gtk_widget_realize) STUB(gtk_widget_reparent) STUB(gtk_widget_set_allocation) STUB(gtk_widget_set_app_paintable) STUB(gtk_window_set_auto_startup_notification) +STUB(gtk_window_set_opacity) +STUB(gtk_window_set_screen) STUB(gtk_widget_set_can_focus) STUB(gtk_widget_set_direction) STUB(gtk_widget_set_double_buffered) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 32b60f837b0d..15ffdafc0b96 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -4611,6 +4611,117 @@ nsWindow::ConvertBorderStyles(nsBorderStyle aStyle) return w; } +class FullscreenTransitionWindow final : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + explicit FullscreenTransitionWindow(GtkWidget* aWidget); + + GtkWidget* mWindow; + +private: + ~FullscreenTransitionWindow(); +}; + +NS_IMPL_ISUPPORTS0(FullscreenTransitionWindow) + +FullscreenTransitionWindow::FullscreenTransitionWindow(GtkWidget* aWidget) +{ + mWindow = gtk_window_new(GTK_WINDOW_POPUP); + GtkWindow* gtkWin = GTK_WINDOW(mWindow); + + gtk_window_set_type_hint(gtkWin, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); + gtk_window_set_transient_for(gtkWin, GTK_WINDOW(aWidget)); + gtk_window_set_decorated(gtkWin, false); + + GdkScreen* screen = gtk_widget_get_screen(aWidget); + gint width = gdk_screen_get_width(screen); + gint height = gdk_screen_get_height(screen); + gtk_window_set_screen(gtkWin, screen); + gtk_window_move(gtkWin, 0, 0); + gtk_window_resize(gtkWin, width, height); + + GdkColor bgColor; + bgColor.red = bgColor.green = bgColor.blue = 0; + gtk_widget_modify_bg(mWindow, GTK_STATE_NORMAL, &bgColor); + + gtk_window_set_opacity(gtkWin, 0.0); + gtk_widget_show(mWindow); +} + +FullscreenTransitionWindow::~FullscreenTransitionWindow() +{ + gtk_widget_destroy(mWindow); +} + +class FullscreenTransitionData +{ +public: + FullscreenTransitionData(nsIWidget::FullscreenTransitionStage aStage, + uint16_t aDuration, nsIRunnable* aCallback, + FullscreenTransitionWindow* aWindow) + : mStage(aStage) + , mStep(0) + , mTotalSteps(aDuration / sInterval) + , mCallback(aCallback) + , mWindow(aWindow) { } + + static const guint sInterval = 10; // 10ms + static gboolean TimeoutCallback(gpointer aData); + +private: + nsIWidget::FullscreenTransitionStage mStage; + uint16_t mStep, mTotalSteps; + nsCOMPtr mCallback; + nsRefPtr mWindow; +}; + +/* static */ gboolean +FullscreenTransitionData::TimeoutCallback(gpointer aData) +{ + auto data = static_cast(aData); + data->mStep++; + gdouble opacity = data->mStep / gdouble(data->mTotalSteps); + if (data->mStage == nsIWidget::eAfterFullscreenToggle) { + opacity = 1.0 - opacity; + } + gtk_window_set_opacity(GTK_WINDOW(data->mWindow->mWindow), opacity); + + if (data->mStep != data->mTotalSteps) { + return TRUE; + } + NS_DispatchToMainThread(data->mCallback.forget()); + delete data; + return FALSE; +} + +/* virtual */ bool +nsWindow::PrepareForFullscreenTransition(nsISupports** aData) +{ + GdkScreen* screen = gtk_widget_get_screen(mShell); + if (!gdk_screen_is_composited(screen)) { + return false; + } + *aData = do_AddRef(new FullscreenTransitionWindow(mShell)).take(); + return true; +} + +/* virtual */ void +nsWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage, + uint16_t aDuration, nsISupports* aData, + nsIRunnable* aCallback) +{ + auto data = static_cast(aData); + // This will be released at the end of the last timeout callback for it. + auto transitionData = new FullscreenTransitionData(aStage, aDuration, + aCallback, data); + g_timeout_add_full(G_PRIORITY_HIGH, + FullscreenTransitionData::sInterval, + FullscreenTransitionData::TimeoutCallback, + transitionData, nullptr); +} + NS_IMETHODIMP nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen) { diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index 05ed0e4113ae..59656e40c647 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -147,6 +147,11 @@ public: bool aIntersectWithExisting) override; virtual bool HasPendingInputEvent() override; + virtual bool PrepareForFullscreenTransition(nsISupports** aData) override; + virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage, + uint16_t aDuration, + nsISupports* aData, + nsIRunnable* aCallback) override; NS_IMETHOD MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override; NS_IMETHOD HideWindowChrome(bool aShouldHide) override; From fe4ce5eb681252d100004e039b8c83ffec424527 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 17 Jul 2015 15:21:29 +1200 Subject: [PATCH 23/90] Bug 1172239. Expand height change hint to its components. r=heycam --HG-- extra : commitid : 1x3Ur8KQLSa extra : rebase_source : feea69537a27535fad8e4187f3318f3e2c1a7c7a --- layout/style/nsStyleStruct.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 2fe8e80a0ee3..eed6e90c5008 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1602,7 +1602,10 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons // in nsHTMLReflowState, they do need to force reflow of the whole subtree. // XXXbz due to XUL caching heights as well, height changes also need to // clear ancestor intrinsics! - return NS_CombineHint(hint, nsChangeHint_AllReflowHints); + return NS_CombineHint(hint, nsChangeHint_NeedReflow | + nsChangeHint_ClearAncestorIntrinsics | + nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_NeedDirtyReflow | + nsChangeHint_ReflowChangesSizeOrPosition); } if (mWidth != aOther.mWidth || From 7dd9009ba5922eb30b63e03e42488183d4991041 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 17 Jul 2015 17:08:54 +1200 Subject: [PATCH 24/90] Bug 1172239. Make vertically-resizing scrollframes reflow their percent-height descendants if necessary, and remove nsChangeHint_NeedDirtyReflow for height changes. r=bz --HG-- extra : commitid : Hbu6gzLSBUp extra : rebase_source : 4d0b03a0ff2e53ea262ef6c17630b450b535dc3c --- layout/generic/nsGfxScrollFrame.cpp | 3 +++ layout/style/nsStyleStruct.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index ded1c5c5bb1b..58074312017d 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -505,6 +505,9 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState, kidReflowState.SetComputedBSize(computedBSize); kidReflowState.ComputedMinBSize() = computedMinBSize; kidReflowState.ComputedMaxBSize() = computedMaxBSize; + if (aState->mReflowState.IsBResize()) { + kidReflowState.SetBResize(true); + } // Temporarily set mHasHorizontalScrollbar/mHasVerticalScrollbar to // reflect our assumptions while we reflow the child. diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index eed6e90c5008..cbca3fcc1de9 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1604,7 +1604,7 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons // clear ancestor intrinsics! return NS_CombineHint(hint, nsChangeHint_NeedReflow | nsChangeHint_ClearAncestorIntrinsics | - nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_NeedDirtyReflow | + nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_ReflowChangesSizeOrPosition); } From 501665ec2f5efb5f957b64787af5f6005b8b31bd Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 18 Jul 2015 12:24:53 +1200 Subject: [PATCH 25/90] Bug 1172239. Add NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE. r=bz --HG-- extra : commitid : DK71qQdcp6s extra : rebase_source : a06ac45a67ab18254b815445fd1c8b6ae54390d3 --- layout/base/nsLayoutUtils.cpp | 14 ++++++++++++++ layout/generic/nsFrame.cpp | 20 +++++++++++++++++++- layout/generic/nsFrameStateBits.h | 5 +++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 19f4eebea839..1cff827bccc0 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4459,6 +4459,17 @@ AddIntrinsicSizeOffset(nsRenderingContext* aRenderingContext, return result; } +static void +AddStateBitToAncestors(nsIFrame* aFrame, nsFrameState aBit) +{ + for (nsIFrame* f = aFrame; f; f = f->GetParent()) { + if (f->HasAnyStateBits(aBit)) { + break; + } + f->AddStateBits(aBit); + } +} + /* static */ nscoord nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, nsRenderingContext* aRenderingContext, @@ -4594,6 +4605,9 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis, nscoord ratioISize = (horizontalAxis ? ratio.width : ratio.height); nscoord ratioBSize = (horizontalAxis ? ratio.height : ratio.width); if (ratioBSize != 0) { + AddStateBitToAncestors(aFrame, + NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE); + nscoord bSizeTakenByBoxSizing = 0; switch (boxSizing) { case NS_STYLE_BOX_SIZING_BORDER: { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c44f4fcc53c2..b1f7ad84c752 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -8815,7 +8815,25 @@ nsIFrame::SetParent(nsContainerFrame* aParent) f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW); } } - + + if (HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { + for (nsIFrame* f = aParent; f; f = f->GetParent()) { + if (f->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) { + break; + } + f->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE); + } + } + + if (HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) { + for (nsIFrame* f = aParent; f; f = f->GetParent()) { + if (f->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) { + break; + } + f->AddStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE); + } + } + if (HasInvalidFrameInSubtree()) { for (nsIFrame* f = aParent; f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index eda65bc3b7b4..3e721d6ef29a 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -175,6 +175,11 @@ FRAME_STATE_BIT(Generic, 32, NS_FRAME_IS_PUSHED_FLOAT) // This bit acts as a loop flag for recursive paint server drawing. FRAME_STATE_BIT(Generic, 33, NS_FRAME_DRAWING_AS_PAINTSERVER) +// Intrinsic ISize depending on the frame's BSize is rare but possible. +// This flag indicates that the frame has (or once had) a descendant in that +// situation (possibly the frame itself). +FRAME_STATE_BIT(Generic, 34, NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE) + // Frame is a display root and the retained layer tree needs to be updated // at the next paint via display list construction. // Only meaningful for display roots, so we don't really need a global state From 148e0aa7695ff841601dce7a90bb68f9bc1e4fe6 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 22 Jul 2015 16:36:56 +1200 Subject: [PATCH 26/90] Bug 1172239. Use nsChangeHint_UpdateComputedBSize to only dirty intrinsic sizes when necessary. r=bz --HG-- extra : commitid : 48WN0ELkG8f extra : rebase_source : 25524e9b82251263a88584d81b31f522a3ab5709 --- layout/base/RestyleManager.cpp | 26 ++++++++++++++++++++++++-- layout/base/nsChangeHint.h | 11 +++++++++-- layout/style/nsStyleStruct.cpp | 9 +++------ layout/style/nsStyleStruct.h | 3 ++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index f59f1049ee64..411a1b877f15 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -550,6 +550,17 @@ RestyleManager::RecomputePosition(nsIFrame* aFrame) return false; } +static bool +HasBoxAncestor(nsIFrame* aFrame) +{ + for (nsIFrame* f = aFrame; f; f = f->GetParent()) { + if (f->IsBoxFrame()) { + return true; + } + } + return false; +} + void RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) { @@ -557,9 +568,19 @@ RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) if (aHint & nsChangeHint_ClearDescendantIntrinsics) { NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics, "Please read the comments in nsChangeHint.h"); + NS_ASSERTION(aHint & nsChangeHint_NeedDirtyReflow, + "ClearDescendantIntrinsics requires NeedDirtyReflow"); + dirtyType = nsIPresShell::eStyleChange; + } else if ((aHint & nsChangeHint_UpdateComputedBSize) && + aFrame->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) { dirtyType = nsIPresShell::eStyleChange; } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) { dirtyType = nsIPresShell::eTreeChange; + } else if ((aHint & nsChangeHint_UpdateComputedBSize) && + HasBoxAncestor(aFrame)) { + // The frame's computed BSize is changing, and we have a box ancestor + // whose cached intrinsic height may need to be updated. + dirtyType = nsIPresShell::eTreeChange; } else { dirtyType = nsIPresShell::eResize; } @@ -567,7 +588,8 @@ RestyleManager::StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint) nsFrameState dirtyBits; if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) { dirtyBits = nsFrameState(0); - } else if (aHint & nsChangeHint_NeedDirtyReflow) { + } else if ((aHint & nsChangeHint_NeedDirtyReflow) || + dirtyType == nsIPresShell::eStyleChange) { dirtyBits = NS_FRAME_IS_DIRTY; } else { dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN; @@ -4245,7 +4267,7 @@ RestyleManager::ChangeHintToString(nsChangeHint aHint) "ChildrenOnlyTransform", "RecomputePosition", "AddOrRemoveTransform", "BorderStyleNoneChange", "UpdateTextPath", "SchedulePaint", "NeutralChange", "InvalidateRenderingObservers", - "ReflowChangesSizeOrPosition" + "ReflowChangesSizeOrPosition", "UpdateComputedBSize" }; uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1); uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1); diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h index a3d81f005fdb..ab7ae4aeb3c9 100644 --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -176,6 +176,11 @@ enum nsChangeHint { */ nsChangeHint_ReflowChangesSizeOrPosition = 0x800000, + /** + * Indicates that the style changes the computed BSize --- e.g. 'height'. + */ + nsChangeHint_UpdateComputedBSize = 0x1000000, + // IMPORTANT NOTE: When adding new hints, consider whether you need to // add them to NS_HintsNotHandledForDescendantsIn() below. Please also // add them to RestyleManager::ChangeHintToString. @@ -283,7 +288,8 @@ inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight) nsChangeHint_BorderStyleNoneChange | \ nsChangeHint_NeedReflow | \ nsChangeHint_ReflowChangesSizeOrPosition | \ - nsChangeHint_ClearAncestorIntrinsics) + nsChangeHint_ClearAncestorIntrinsics | \ + nsChangeHint_UpdateComputedBSize) inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) { nsChangeHint result = nsChangeHint(aChangeHint & ( @@ -297,7 +303,8 @@ inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) nsChangeHint_ChildrenOnlyTransform | nsChangeHint_RecomputePosition | nsChangeHint_AddOrRemoveTransform | - nsChangeHint_BorderStyleNoneChange)); + nsChangeHint_BorderStyleNoneChange | + nsChangeHint_UpdateComputedBSize)); if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aChangeHint)) { if (NS_IsHintSubset(nsChangeHint_NeedReflow, aChangeHint)) { diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index cbca3fcc1de9..a019e79b3f1c 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1598,13 +1598,10 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons mMaxHeight != aOther.mMaxHeight) { // Height changes can affect descendant intrinsic sizes due to replaced // elements with percentage heights in descendants which also have - // percentage heights. And due to our not-so-great computation of mVResize - // in nsHTMLReflowState, they do need to force reflow of the whole subtree. - // XXXbz due to XUL caching heights as well, height changes also need to - // clear ancestor intrinsics! + // percentage heights. This is handled via nsChangeHint_UpdateComputedBSize + // which clears intrinsic sizes for frames that have such replaced elements. return NS_CombineHint(hint, nsChangeHint_NeedReflow | - nsChangeHint_ClearAncestorIntrinsics | - nsChangeHint_ClearDescendantIntrinsics | + nsChangeHint_UpdateComputedBSize | nsChangeHint_ReflowChangesSizeOrPosition); } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 206d91e2078c..c5c0e6c4d7a6 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1355,7 +1355,8 @@ struct nsStylePosition { static nsChangeHint MaxDifference() { return NS_CombineHint(NS_STYLE_HINT_REFLOW, nsChangeHint(nsChangeHint_RecomputePosition | - nsChangeHint_UpdateParentOverflow)); + nsChangeHint_UpdateParentOverflow | + nsChangeHint_UpdateComputedBSize)); } static nsChangeHint DifferenceAlwaysHandledForDescendants() { // CalcDifference can return all of the reflow hints that are From dae16893fee5872dbe10d9e80a4d4ffa500912c8 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 22 Jul 2015 16:37:00 +1200 Subject: [PATCH 27/90] Bug 1172239. Ensure nested overflow:auto elements are tested. r=bz --HG-- extra : commitid : DoIuHjOVpv extra : rebase_source : 695167a656e8b9d90835677e4812cb3c4a220259 --- .../percent-overflow-sizing/nestedHeight-ref.html | 8 ++++++++ layout/reftests/percent-overflow-sizing/nestedHeight.html | 8 ++++++++ .../percent-overflow-sizing/nestedHeightQuirks-ref.html | 8 ++++++++ .../percent-overflow-sizing/nestedHeightQuirks.html | 8 ++++++++ layout/reftests/percent-overflow-sizing/reftest.list | 2 ++ 5 files changed, 34 insertions(+) create mode 100644 layout/reftests/percent-overflow-sizing/nestedHeight-ref.html create mode 100644 layout/reftests/percent-overflow-sizing/nestedHeight.html create mode 100644 layout/reftests/percent-overflow-sizing/nestedHeightQuirks-ref.html create mode 100644 layout/reftests/percent-overflow-sizing/nestedHeightQuirks.html diff --git a/layout/reftests/percent-overflow-sizing/nestedHeight-ref.html b/layout/reftests/percent-overflow-sizing/nestedHeight-ref.html new file mode 100644 index 000000000000..2a2539429f3f --- /dev/null +++ b/layout/reftests/percent-overflow-sizing/nestedHeight-ref.html @@ -0,0 +1,8 @@ + + +
+
+
+
+
+ diff --git a/layout/reftests/percent-overflow-sizing/nestedHeight.html b/layout/reftests/percent-overflow-sizing/nestedHeight.html new file mode 100644 index 000000000000..a4939e902163 --- /dev/null +++ b/layout/reftests/percent-overflow-sizing/nestedHeight.html @@ -0,0 +1,8 @@ + + +
+
+
+
+
+ diff --git a/layout/reftests/percent-overflow-sizing/nestedHeightQuirks-ref.html b/layout/reftests/percent-overflow-sizing/nestedHeightQuirks-ref.html new file mode 100644 index 000000000000..c48bbb72a92c --- /dev/null +++ b/layout/reftests/percent-overflow-sizing/nestedHeightQuirks-ref.html @@ -0,0 +1,8 @@ + + +
+
+
+
+
+ diff --git a/layout/reftests/percent-overflow-sizing/nestedHeightQuirks.html b/layout/reftests/percent-overflow-sizing/nestedHeightQuirks.html new file mode 100644 index 000000000000..5b369b3fb6d8 --- /dev/null +++ b/layout/reftests/percent-overflow-sizing/nestedHeightQuirks.html @@ -0,0 +1,8 @@ + + +
+
+
+
+
+ diff --git a/layout/reftests/percent-overflow-sizing/reftest.list b/layout/reftests/percent-overflow-sizing/reftest.list index abc337794594..12286c2ab32c 100644 --- a/layout/reftests/percent-overflow-sizing/reftest.list +++ b/layout/reftests/percent-overflow-sizing/reftest.list @@ -22,3 +22,5 @@ skip-if(B2G||Mulet) random-if(transparentScrollbars) fails-if(Android&&browserIs skip-if(B2G||Mulet) random-if(transparentScrollbars) fails-if(Android&&browserIsRemote) == hScrollAbsMinHeightD.html greenboxhbar.html # bug 650591, 732565 # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) random-if(transparentScrollbars) fails-if(Android&&browserIsRemote) == hScrollAbsMinHeightQuirksD.html greenboxhbar.html # bug 650591, 732565 # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop == dynamicHeight100.html dynamicHeight100-ref.html +== nestedHeight.html nestedHeight-ref.html +== nestedHeightQuirks.html nestedHeightQuirks-ref.html From 3b3a40486f44b976f4b3039a0717ea9f1abdbd3b Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Thu, 23 Jul 2015 19:00:49 -0700 Subject: [PATCH 28/90] Bug 1186920 - Fix b2g applications that use cookies. r=gwagner --- netwerk/cookie/CookieServiceParent.cpp | 32 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/netwerk/cookie/CookieServiceParent.cpp b/netwerk/cookie/CookieServiceParent.cpp index 4a929b5ca2e3..467eeba8cf98 100644 --- a/netwerk/cookie/CookieServiceParent.cpp +++ b/netwerk/cookie/CookieServiceParent.cpp @@ -21,27 +21,39 @@ using mozilla::net::NeckoParent; namespace { -bool -CreateDummyChannel(nsIURI* aHostURI, bool aIsPrivate, nsIChannel **aChannel) +// Ignore failures from this function, as they only affect whether we do or +// don't show a dialog box in private browsing mode if the user sets a pref. +void +CreateDummyChannel(nsIURI* aHostURI, uint32_t aAppId, bool aInMozBrowser, + bool aIsPrivate, nsIChannel **aChannel) { + MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); + nsCOMPtr principal; nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); - nsresult rv = ssm->GetNoAppCodebasePrincipal(aHostURI, getter_AddRefs(principal)); + nsresult rv = ssm->GetAppCodebasePrincipal(aHostURI, aAppId, aInMozBrowser, + getter_AddRefs(principal)); if (NS_FAILED(rv)) { - return false; + return; + } + + nsCOMPtr dummyURI; + rv = NS_NewURI(getter_AddRefs(dummyURI), "about:blank"); + if (NS_FAILED(rv)) { + return; } nsCOMPtr dummyChannel; - NS_NewChannel(getter_AddRefs(dummyChannel), aHostURI, principal, + NS_NewChannel(getter_AddRefs(dummyChannel), dummyURI, principal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_INVALID); nsCOMPtr pbChannel = do_QueryInterface(dummyChannel); if (!pbChannel) { - return false; + return; } pbChannel->SetPrivate(aIsPrivate); dummyChannel.forget(aChannel); - return true; + return; } } @@ -163,10 +175,10 @@ CookieServiceParent::RecvSetCookieString(const URIParams& aHost, // with aIsForeign before we have to worry about nsCookiePermission trying // to use the channel to inspect it. nsCOMPtr dummyChannel; - if (!CreateDummyChannel(hostURI, isPrivate, getter_AddRefs(dummyChannel))) { - return false; - } + CreateDummyChannel(hostURI, appId, isInBrowserElement, + isPrivate, getter_AddRefs(dummyChannel)); + // NB: dummyChannel could be null if something failed in CreateDummyChannel. nsDependentCString cookieString(aCookieString, 0); mCookieService->SetCookieStringInternal(hostURI, aIsForeign, cookieString, aServerTime, aFromHttp, appId, From b755ef234b4b71f99af45791f3d242ffc6df170e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Jul 2015 20:49:25 -0700 Subject: [PATCH 29/90] Bug 1182969 - Use nsTHashTable::Iterator in accessible/. r=tbsaunde. --HG-- extra : rebase_source : 548f1b49bcbfee3aca9642cdc2fa00e86dd3ee2e --- accessible/base/NotificationController.cpp | 177 ++++++++++----------- accessible/base/NotificationController.h | 6 - accessible/ipc/DocAccessibleParent.cpp | 12 +- accessible/ipc/DocAccessibleParent.h | 2 - 4 files changed, 87 insertions(+), 110 deletions(-) diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp index 0bae0db3a00f..6ca5280ec105 100644 --- a/accessible/base/NotificationController.cpp +++ b/accessible/base/NotificationController.cpp @@ -204,7 +204,89 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) } // Process rendered text change notifications. - mTextHash.EnumerateEntries(TextEnumerator, mDocument); + for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) { + nsCOMPtrHashKey* entry = iter.Get(); + nsIContent* textNode = entry->GetKey(); + Accessible* textAcc = mDocument->GetAccessible(textNode); + + // If the text node is not in tree or doesn't have frame then this case should + // have been handled already by content removal notifications. + nsINode* containerNode = textNode->GetParentNode(); + if (!containerNode) { + NS_ASSERTION(!textAcc, + "Text node was removed but accessible is kept alive!"); + continue; + } + + nsIFrame* textFrame = textNode->GetPrimaryFrame(); + if (!textFrame) { + NS_ASSERTION(!textAcc, + "Text node isn't rendered but accessible is kept alive!"); + continue; + } + + nsIContent* containerElm = containerNode->IsElement() ? + containerNode->AsElement() : nullptr; + + nsAutoString text; + textFrame->GetRenderedText(&text); + + // Remove text accessible if rendered text is empty. + if (textAcc) { + if (text.IsEmpty()) { + #ifdef A11Y_LOG + if (logging::IsEnabled(logging::eTree | logging::eText)) { + logging::MsgBegin("TREE", "text node lost its content"); + logging::Node("container", containerElm); + logging::Node("content", textNode); + logging::MsgEnd(); + } + #endif + + mDocument->ContentRemoved(containerElm, textNode); + continue; + } + + // Update text of the accessible and fire text change events. + #ifdef A11Y_LOG + if (logging::IsEnabled(logging::eText)) { + logging::MsgBegin("TEXT", "text may be changed"); + logging::Node("container", containerElm); + logging::Node("content", textNode); + logging::MsgEntry("old text '%s'", + NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get()); + logging::MsgEntry("new text: '%s'", + NS_ConvertUTF16toUTF8(text).get()); + logging::MsgEnd(); + } + #endif + + TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text); + continue; + } + + // Append an accessible if rendered text is not empty. + if (!text.IsEmpty()) { + #ifdef A11Y_LOG + if (logging::IsEnabled(logging::eTree | logging::eText)) { + logging::MsgBegin("TREE", "text node gains new content"); + logging::Node("container", containerElm); + logging::Node("content", textNode); + logging::MsgEnd(); + } + #endif + + // Make sure the text node is in accessible document still. + Accessible* container = mDocument->GetAccessibleOrContainer(containerNode); + NS_ASSERTION(container, + "Text node having rendered text hasn't accessible document!"); + if (container) { + nsTArray > insertedContents; + insertedContents.AppendElement(textNode); + mDocument->ProcessContentInserted(container, &insertedContents); + } + } + } mTextHash.Clear(); // Bind hanging child documents. @@ -314,99 +396,6 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) } } -//////////////////////////////////////////////////////////////////////////////// -// Notification controller: text leaf accessible text update - -PLDHashOperator -NotificationController::TextEnumerator(nsCOMPtrHashKey* aEntry, - void* aUserArg) -{ - DocAccessible* document = static_cast(aUserArg); - nsIContent* textNode = aEntry->GetKey(); - Accessible* textAcc = document->GetAccessible(textNode); - - // If the text node is not in tree or doesn't have frame then this case should - // have been handled already by content removal notifications. - nsINode* containerNode = textNode->GetParentNode(); - if (!containerNode) { - NS_ASSERTION(!textAcc, - "Text node was removed but accessible is kept alive!"); - return PL_DHASH_NEXT; - } - - nsIFrame* textFrame = textNode->GetPrimaryFrame(); - if (!textFrame) { - NS_ASSERTION(!textAcc, - "Text node isn't rendered but accessible is kept alive!"); - return PL_DHASH_NEXT; - } - - nsIContent* containerElm = containerNode->IsElement() ? - containerNode->AsElement() : nullptr; - - nsAutoString text; - textFrame->GetRenderedText(&text); - - // Remove text accessible if rendered text is empty. - if (textAcc) { - if (text.IsEmpty()) { -#ifdef A11Y_LOG - if (logging::IsEnabled(logging::eTree | logging::eText)) { - logging::MsgBegin("TREE", "text node lost its content"); - logging::Node("container", containerElm); - logging::Node("content", textNode); - logging::MsgEnd(); - } -#endif - - document->ContentRemoved(containerElm, textNode); - return PL_DHASH_NEXT; - } - - // Update text of the accessible and fire text change events. -#ifdef A11Y_LOG - if (logging::IsEnabled(logging::eText)) { - logging::MsgBegin("TEXT", "text may be changed"); - logging::Node("container", containerElm); - logging::Node("content", textNode); - logging::MsgEntry("old text '%s'", - NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get()); - logging::MsgEntry("new text: '%s'", - NS_ConvertUTF16toUTF8(text).get()); - logging::MsgEnd(); - } -#endif - - TextUpdater::Run(document, textAcc->AsTextLeaf(), text); - return PL_DHASH_NEXT; - } - - // Append an accessible if rendered text is not empty. - if (!text.IsEmpty()) { -#ifdef A11Y_LOG - if (logging::IsEnabled(logging::eTree | logging::eText)) { - logging::MsgBegin("TREE", "text node gains new content"); - logging::Node("container", containerElm); - logging::Node("content", textNode); - logging::MsgEnd(); - } -#endif - - // Make sure the text node is in accessible document still. - Accessible* container = document->GetAccessibleOrContainer(containerNode); - NS_ASSERTION(container, - "Text node having rendered text hasn't accessible document!"); - if (container) { - nsTArray > insertedContents; - insertedContents.AppendElement(textNode); - document->ProcessContentInserted(container, &insertedContents); - } - } - - return PL_DHASH_NEXT; -} - - //////////////////////////////////////////////////////////////////////////////// // NotificationController: content inserted notification diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h index d4f7c98208bf..fcb41e0308c6 100644 --- a/accessible/base/NotificationController.h +++ b/accessible/base/NotificationController.h @@ -297,12 +297,6 @@ private: */ nsTHashtable > mTextHash; - /** - * Update the accessible tree for pending rendered text change notifications. - */ - static PLDHashOperator TextEnumerator(nsCOMPtrHashKey* aEntry, - void* aUserArg); - /** * Other notifications like DOM events. Don't make this an nsAutoTArray; we * use SwapElements() on it. diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index 8246b860bf2d..d8d3180d2ecd 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -221,13 +221,6 @@ DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc, return true; } -PLDHashOperator -DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*) -{ - ProxyDestroyed(entry->mProxy); - return PL_DHASH_REMOVE; -} - bool DocAccessibleParent::RecvShutdown() { @@ -252,7 +245,10 @@ DocAccessibleParent::Destroy() for (uint32_t i = childDocCount - 1; i < childDocCount; i--) mChildDocs[i]->Destroy(); - mAccessibles.EnumerateEntries(ShutdownAccessibles, nullptr); + for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) { + ProxyDestroyed(iter.Get()->mProxy); + iter.Remove(); + } ProxyDestroyed(this); if (mParentDoc) mParentDoc->RemoveChildDoc(this); diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index 7d59582e7758..095cb9570a23 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -152,8 +152,6 @@ private: uint32_t aIdxInParent); void CheckDocTree() const; - static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused); - nsTArray mChildDocs; DocAccessibleParent* mParentDoc; From 3e2de4702c70fb8908f4570c5eca302f7eb20e6f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Jul 2015 02:35:27 -0700 Subject: [PATCH 30/90] Bug 1181443 (part 1) - Use nsTHashtable::Iterator in nsCheapSet. r=froydnj. nsCheapSet is used little enough that I didn't bother creating an iterator for it. I removed the dependency on PLDHashOperator by introducing nsCheapSetOperator, which is equivalent. --HG-- extra : rebase_source : 8a15ae2ee0949a241f6417bfab614affbec2987c --- dom/base/DirectionalityUtils.cpp | 12 ++++++------ xpcom/ds/nsCheapSets.h | 22 ++++++++++++++++++---- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/dom/base/DirectionalityUtils.cpp b/dom/base/DirectionalityUtils.cpp index 753ddbaf31e7..09f4b199fdfa 100644 --- a/dom/base/DirectionalityUtils.cpp +++ b/dom/base/DirectionalityUtils.cpp @@ -490,15 +490,15 @@ private: return map; } - static PLDHashOperator SetNodeDirection(nsPtrHashKey* aEntry, void* aDir) + static nsCheapSetOperator SetNodeDirection(nsPtrHashKey* aEntry, void* aDir) { MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element"); aEntry->GetKey()->SetDirectionality(*reinterpret_cast(aDir), true); - return PL_DHASH_NEXT; + return OpNext; } - static PLDHashOperator ResetNodeDirection(nsPtrHashKey* aEntry, void* aData) + static nsCheapSetOperator ResetNodeDirection(nsPtrHashKey* aEntry, void* aData) { MOZ_ASSERT(aEntry->GetKey()->IsElement(), "Must be an Element"); // run the downward propagation algorithm @@ -516,15 +516,15 @@ private: rootNode->ClearHasDirAutoSet(); rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy); } - return PL_DHASH_REMOVE; + return OpRemove; } - static PLDHashOperator ClearEntry(nsPtrHashKey* aEntry, void* aData) + static nsCheapSetOperator ClearEntry(nsPtrHashKey* aEntry, void* aData) { Element* rootNode = aEntry->GetKey(); rootNode->ClearHasDirAutoSet(); rootNode->UnsetProperty(nsGkAtoms::dirAutoSetBy); - return PL_DHASH_REMOVE; + return OpRemove; } public: diff --git a/xpcom/ds/nsCheapSets.h b/xpcom/ds/nsCheapSets.h index 2ebcc012ab67..e61febffe5a6 100644 --- a/xpcom/ds/nsCheapSets.h +++ b/xpcom/ds/nsCheapSets.h @@ -10,6 +10,12 @@ #include "nsTHashtable.h" #include +enum nsCheapSetOperator +{ + OpNext = 0, // enumerator says continue + OpRemove = 1, // enumerator says remove and continue +}; + /** * A set that takes up minimal size when there are 0 or 1 entries in the set. * Use for cases where sizes of 0 and 1 are even slightly common. @@ -19,7 +25,7 @@ class nsCheapSet { public: typedef typename EntryType::KeyType KeyType; - typedef PLDHashOperator (*Enumerator)(EntryType* aEntry, void* userArg); + typedef nsCheapSetOperator (*Enumerator)(EntryType* aEntry, void* userArg); nsCheapSet() : mState(ZERO) {} ~nsCheapSet() { Clear(); } @@ -70,13 +76,21 @@ public: case ZERO: return 0; case ONE: - if (aEnumFunc(GetSingleEntry(), aUserArg) == PL_DHASH_REMOVE) { + if (aEnumFunc(GetSingleEntry(), aUserArg) == OpRemove) { GetSingleEntry()->~EntryType(); mState = ZERO; } return 1; - case MANY: - return mUnion.table->EnumerateEntries(aEnumFunc, aUserArg); + case MANY: { + uint32_t n = mUnion.table->Count(); + for (auto iter = mUnion.table->Iter(); !iter.Done(); iter.Next()) { + auto entry = static_cast(iter.Get()); + if (aEnumFunc(entry, aUserArg) == OpRemove) { + iter.Remove(); + } + } + return n; + } default: NS_NOTREACHED("bogus state"); return 0; From 50600e08a248bdc8063a0b4cf1a7bac47fcf36ba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Jul 2015 02:36:13 -0700 Subject: [PATCH 31/90] Bug 1181443 (part 2) - Use nsTHashtable::Iterator in TestHashtables.cpp. r=froydnj. --HG-- extra : rebase_source : 8af9bef1f1f474555f09b41ec3d985add6d9d728 --- xpcom/tests/TestHashtables.cpp | 46 +++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/xpcom/tests/TestHashtables.cpp b/xpcom/tests/TestHashtables.cpp index ba9ab1e19dce..d6ada3f2a710 100644 --- a/xpcom/tests/TestHashtables.cpp +++ b/xpcom/tests/TestHashtables.cpp @@ -1,4 +1,5 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -82,20 +83,31 @@ public: const EntityNode* mNode; }; -PLDHashOperator -nsTEnumGo(EntityToUnicodeEntry* aEntry, void* userArg) { - printf(" enumerated \"%s\" = %u\n", - aEntry->mNode->mStr, aEntry->mNode->mUnicode); - - return PL_DHASH_NEXT; +static uint32_t +nsTIterPrint(nsTHashtable& hash) +{ + uint32_t n = 0; + for (auto iter = hash.Iter(); !iter.Done(); iter.Next()) { + EntityToUnicodeEntry* entry = iter.Get(); + printf(" enumerated \"%s\" = %u\n", + entry->mNode->mStr, entry->mNode->mUnicode); + n++; + } + return n; } -PLDHashOperator -nsTEnumStop(EntityToUnicodeEntry* aEntry, void* userArg) { - printf(" enumerated \"%s\" = %u\n", - aEntry->mNode->mStr, aEntry->mNode->mUnicode); - - return PL_DHASH_REMOVE; +static uint32_t +nsTIterPrintRemove(nsTHashtable& hash) +{ + uint32_t n = 0; + for (auto iter = hash.Iter(); !iter.Done(); iter.Next()) { + EntityToUnicodeEntry* entry = iter.Get(); + printf(" enumerated \"%s\" = %u\n", + entry->mNode->mStr, entry->mNode->mUnicode); + iter.Remove(); + n++; + } + return n; } void @@ -151,7 +163,7 @@ testTHashtable(nsTHashtable& hash, uint32_t numEntries) { printf("not found; good.\n"); printf("Enumerating:\n"); - uint32_t count = hash.EnumerateEntries(nsTEnumGo, nullptr); + uint32_t count = nsTIterPrint(hash); if (count != numEntries) { printf(" Bad count!\n"); exit (6); @@ -381,7 +393,7 @@ main(void) { testTHashtable(EntityToUnicode, 5); printf("Enumerate-removing...\n"); - uint32_t count = EntityToUnicode.EnumerateEntries(nsTEnumStop, nullptr); + uint32_t count = nsTIterPrintRemove(EntityToUnicode); if (count != 5) { printf("wrong count\n"); exit (7); @@ -389,7 +401,7 @@ main(void) { printf("OK\n"); printf("Check enumeration..."); - count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nullptr); + count = nsTIterPrint(EntityToUnicode); if (count) { printf("entries remain in table!\n"); exit (8); @@ -404,7 +416,7 @@ main(void) { printf("OK\n"); printf("Check enumeration..."); - count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nullptr); + count = nsTIterPrint(EntityToUnicode); if (count) { printf("entries remain in table!\n"); exit (9); From cec576a92289a293245fd6598ad1b313bf2477ca Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 24 Jul 2015 13:38:12 +1000 Subject: [PATCH 32/90] Bug 1187173 - Disable warning C4623 on security/certverifier. r=briansmith --HG-- extra : source : 9f3acfedff8cf4a26266bb578dc69727e799c0cf extra : amend_source : cb1d0a6e8c6d9199429159cb9a20484f5aa95b8d --- security/certverifier/moz.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/certverifier/moz.build b/security/certverifier/moz.build index a9d030c6f11a..3aaa39969bf8 100644 --- a/security/certverifier/moz.build +++ b/security/certverifier/moz.build @@ -45,6 +45,8 @@ if CONFIG['_MSC_VER']: '-wd4610', # struct 'symbol' can never be instantiated - user defined # constructor required '-wd4619', # pragma warning: there is no warning 'warning' + '-wd4623', # default constructor could not be generated because a base + # class default constructor is inaccessible or deleted '-wd4625', # copy constructor could not be generated because a base # class copy constructor is inaccessible or deleted '-wd4626', # assignment operator could not be generated because a base From 8942b13e62c48aea4afbaa6a7269bcc723d699d4 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 24 Jul 2015 14:07:39 +0900 Subject: [PATCH 33/90] Bug 1186014 Rename nsTextStore to mozilla::widget::TSFTextStore r=jimm+m_kato --HG-- rename : widget/windows/nsTextStore.cpp => widget/windows/TSFTextStore.cpp rename : widget/windows/nsTextStore.h => widget/windows/TSFTextStore.h --- .../{nsTextStore.cpp => TSFTextStore.cpp} | 1097 +++++++++-------- .../windows/{nsTextStore.h => TSFTextStore.h} | 95 +- widget/windows/WinIMEHandler.cpp | 72 +- widget/windows/WinUtils.cpp | 6 +- widget/windows/moz.build | 2 +- 5 files changed, 641 insertions(+), 631 deletions(-) rename widget/windows/{nsTextStore.cpp => TSFTextStore.cpp} (82%) rename widget/windows/{nsTextStore.h => TSFTextStore.h} (91%) diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/TSFTextStore.cpp similarity index 82% rename from widget/windows/nsTextStore.cpp rename to widget/windows/TSFTextStore.cpp index f93f4ef00580..f76f1fd262d7 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -19,10 +19,10 @@ #define INPUTSCOPE_INIT_GUID #define TEXTATTRS_INIT_GUID -#include "nsTextStore.h" +#include "TSFTextStore.h" -using namespace mozilla; -using namespace mozilla::widget; +namespace mozilla { +namespace widget { static const char* kPrefNameEnableTSF = "intl.tsf.enable"; static const char* kPrefNameForceEnableTSF = "intl.tsf.force_enable"; @@ -36,13 +36,13 @@ static const char* kPrefNameForceEnableTSF = "intl.tsf.force_enable"; * For logging error, use LogLevel::Error. * * When an instance method is called, start with following text: - * "TSF: 0x%p nsFoo::Bar(", the 0x%p should be the "this" of the nsFoo. + * "TSF: 0x%p TSFFoo::Bar(", the 0x%p should be the "this" of the nsFoo. * after that, start with: - * "TSF: 0x%p nsFoo::Bar(" + * "TSF: 0x%p TSFFoo::Bar(" * In an internal method, start with following text: - * "TSF: 0x%p nsFoo::Bar(" + * "TSF: 0x%p TSFFoo::Bar(" * When a static method is called, start with following text: - * "TSF: nsFoo::Bar(" + * "TSF: TSFFoo::Bar(" */ PRLogModuleInfo* sTextStoreLog = nullptr; @@ -453,7 +453,7 @@ GetTextRunTypeName(TsRunType aRunType) } static nsCString -GetColorName(const TF_DA_COLOR &aColor) +GetColorName(const TF_DA_COLOR& aColor) { switch (aColor.type) { case TF_CT_NONE: @@ -516,7 +516,7 @@ GetClauseAttrName(TF_DA_ATTR_INFO aAttr) } static nsCString -GetDisplayAttrStr(const TF_DISPLAYATTRIBUTE &aDispAttr) +GetDisplayAttrStr(const TF_DISPLAYATTRIBUTE& aDispAttr) { nsAutoCString str; str = "crText:{ "; @@ -731,10 +731,13 @@ public: return S_OK; } - STDMETHODIMP GetPhrase(BSTR **ppbstrPhrases, UINT *pcCount) { return E_NOTIMPL; } - STDMETHODIMP GetRegularExpression(BSTR *pbstrRegExp) { return E_NOTIMPL; } - STDMETHODIMP GetSRGS(BSTR *pbstrSRGS) { return E_NOTIMPL; } - STDMETHODIMP GetXML(BSTR *pbstrXML) { return E_NOTIMPL; } + STDMETHODIMP GetPhrase(BSTR **ppbstrPhrases, UINT* pcCount) + { + return E_NOTIMPL; + } + STDMETHODIMP GetRegularExpression(BSTR* pbstrRegExp) { return E_NOTIMPL; } + STDMETHODIMP GetSRGS(BSTR* pbstrSRGS) { return E_NOTIMPL; } + STDMETHODIMP GetXML(BSTR* pbstrXML) { return E_NOTIMPL; } private: nsTArray mInputScopes; @@ -957,7 +960,7 @@ TSFStaticSink::Destroy() hr = source->UnadviseSink(mIPProfileCookie); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::Shutdown() FAILED to uninstall " + ("TSF: 0x%p TSFTextStore::Shutdown() FAILED to uninstall " "ITfInputProcessorProfileActivationSink (0x%08X)", this, hr)); } @@ -1215,29 +1218,29 @@ TSFStaticSink::IsTIPCategoryKeyboard(REFCLSID aTextService, LANGID aLangID, } /******************************************************************/ -/* nsTextStore */ +/* TSFTextStore */ /******************************************************************/ -StaticRefPtr nsTextStore::sThreadMgr; -StaticRefPtr nsTextStore::sMessagePump; -StaticRefPtr nsTextStore::sKeystrokeMgr; -StaticRefPtr nsTextStore::sDisplayAttrMgr; -StaticRefPtr nsTextStore::sCategoryMgr; -StaticRefPtr nsTextStore::sDisabledDocumentMgr; -StaticRefPtr nsTextStore::sDisabledContext; -StaticRefPtr nsTextStore::sInputProcessorProfiles; -StaticRefPtr nsTextStore::sEnabledTextStore; -DWORD nsTextStore::sClientId = 0; +StaticRefPtr TSFTextStore::sThreadMgr; +StaticRefPtr TSFTextStore::sMessagePump; +StaticRefPtr TSFTextStore::sKeystrokeMgr; +StaticRefPtr TSFTextStore::sDisplayAttrMgr; +StaticRefPtr TSFTextStore::sCategoryMgr; +StaticRefPtr TSFTextStore::sDisabledDocumentMgr; +StaticRefPtr TSFTextStore::sDisabledContext; +StaticRefPtr TSFTextStore::sInputProcessorProfiles; +StaticRefPtr TSFTextStore::sEnabledTextStore; +DWORD TSFTextStore::sClientId = 0; -bool nsTextStore::sCreateNativeCaretForATOK = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToFreeChangJie = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar = false; -bool nsTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret = false; +bool TSFTextStore::sCreateNativeCaretForATOK = false; +bool TSFTextStore::sDoNotReturnNoLayoutErrorToFreeChangJie = false; +bool TSFTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false; +bool TSFTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar = false; +bool TSFTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret = false; #define TEXTSTORE_DEFAULT_VIEW (1) -nsTextStore::nsTextStore() +TSFTextStore::TSFTextStore() : mEditCookie(0) , mSinkMask(0) , mLock(0) @@ -1260,27 +1263,27 @@ nsTextStore::nsTextStore() mPendingActions.SetCapacity(5); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::nsTestStore() SUCCEEDED", this)); + ("TSF: 0x%p TSFTextStore::TSFTextStore() SUCCEEDED", this)); } -nsTextStore::~nsTextStore() +TSFTextStore::~TSFTextStore() { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore instance is destroyed", this)); + ("TSF: 0x%p TSFTextStore instance is destroyed", this)); } bool -nsTextStore::Init(nsWindowBase* aWidget) +TSFTextStore::Init(nsWindowBase* aWidget) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::Init(aWidget=0x%p)", + ("TSF: 0x%p TSFTextStore::Init(aWidget=0x%p)", this, aWidget)); TSFStaticSink::GetInstance()->EnsureInitActiveTIPKeyboard(); if (mDocumentMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::Init() FAILED due to already initialized", + ("TSF: 0x%p TSFTextStore::Init() FAILED due to already initialized", this)); return false; } @@ -1289,7 +1292,7 @@ nsTextStore::Init(nsWindowBase* aWidget) HRESULT hr = sThreadMgr->CreateDocumentMgr(getter_AddRefs(mDocumentMgr)); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::Init() FAILED to create DocumentMgr " + ("TSF: 0x%p TSFTextStore::Init() FAILED to create DocumentMgr " "(0x%08X)", this, hr)); return false; } @@ -1301,7 +1304,7 @@ nsTextStore::Init(nsWindowBase* aWidget) getter_AddRefs(mContext), &mEditCookie); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::Init() FAILED to create the context " + ("TSF: 0x%p TSFTextStore::Init() FAILED to create the context " "(0x%08X)", this, hr)); mDocumentMgr = nullptr; return false; @@ -1310,7 +1313,7 @@ nsTextStore::Init(nsWindowBase* aWidget) hr = mDocumentMgr->Push(mContext); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::Init() FAILED to push the context (0x%08X)", + ("TSF: 0x%p TSFTextStore::Init() FAILED to push the context (0x%08X)", this, hr)); // XXX Why don't we use NS_IF_RELEASE() here?? mContext = nullptr; @@ -1319,7 +1322,7 @@ nsTextStore::Init(nsWindowBase* aWidget) } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::Init() succeeded: " + ("TSF: 0x%p TSFTextStore::Init() succeeded: " "mDocumentMgr=0x%p, mContext=0x%p, mEditCookie=0x%08X", this, mDocumentMgr.get(), mContext.get(), mEditCookie)); @@ -1327,10 +1330,10 @@ nsTextStore::Init(nsWindowBase* aWidget) } bool -nsTextStore::Destroy() +TSFTextStore::Destroy() { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::Destroy(), mLock=%s, " + ("TSF: 0x%p TSFTextStore::Destroy(), mLock=%s, " "mComposition.IsComposing()=%s", this, GetLockFlagNameStr(mLock).get(), GetBoolName(mComposition.IsComposing()))); @@ -1349,7 +1352,7 @@ nsTextStore::Destroy() if (mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::Destroy(), calling " + ("TSF: 0x%p TSFTextStore::Destroy(), calling " "ITextStoreACPSink::OnLayoutChange(TS_LC_DESTROY)...", this)); mSink->OnLayoutChange(TS_LC_DESTROY, TEXTSTORE_DEFAULT_VIEW); @@ -1368,19 +1371,19 @@ nsTextStore::Destroy() if (!mMouseTrackers.IsEmpty()) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::Destroy(), removing a mouse tracker...", + ("TSF: 0x%p TSFTextStore::Destroy(), removing a mouse tracker...", this)); mMouseTrackers.Clear(); } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::Destroy() succeeded", this)); + ("TSF: 0x%p TSFTextStore::Destroy() succeeded", this)); return true; } STDMETHODIMP -nsTextStore::QueryInterface(REFIID riid, - void** ppv) +TSFTextStore::QueryInterface(REFIID riid, + void** ppv) { *ppv=nullptr; if ( (IID_IUnknown == riid) || (IID_ITextStoreACP == riid) ) { @@ -1396,32 +1399,32 @@ nsTextStore::QueryInterface(REFIID riid, } MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::QueryInterface() FAILED, riid=%s", + ("TSF: 0x%p TSFTextStore::QueryInterface() FAILED, riid=%s", this, GetRIIDNameStr(riid).get())); return E_NOINTERFACE; } STDMETHODIMP -nsTextStore::AdviseSink(REFIID riid, - IUnknown *punk, - DWORD dwMask) +TSFTextStore::AdviseSink(REFIID riid, + IUnknown* punk, + DWORD dwMask) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::AdviseSink(riid=%s, punk=0x%p, dwMask=%s), " + ("TSF: 0x%p TSFTextStore::AdviseSink(riid=%s, punk=0x%p, dwMask=%s), " "mSink=0x%p, mSinkMask=%s", this, GetRIIDNameStr(riid).get(), punk, GetSinkMaskNameStr(dwMask).get(), mSink.get(), GetSinkMaskNameStr(mSinkMask).get())); if (!punk) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to the null punk", + ("TSF: 0x%p TSFTextStore::AdviseSink() FAILED due to the null punk", this)); return E_UNEXPECTED; } if (IID_ITextStoreACPSink != riid) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::AdviseSink() FAILED due to " "unsupported interface", this)); return E_INVALIDARG; // means unsupported interface. } @@ -1431,7 +1434,7 @@ nsTextStore::AdviseSink(REFIID riid, punk->QueryInterface(IID_ITextStoreACPSink, getter_AddRefs(mSink)); if (!mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::AdviseSink() FAILED due to " "punk not having the interface", this)); return E_UNEXPECTED; } @@ -1443,7 +1446,7 @@ nsTextStore::AdviseSink(REFIID riid, mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2)); if (comparison1 != comparison2) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::AdviseSink() FAILED due to " "the sink being different from the stored sink", this)); return CONNECT_E_ADVISELIMIT; } @@ -1454,21 +1457,21 @@ nsTextStore::AdviseSink(REFIID riid, } STDMETHODIMP -nsTextStore::UnadviseSink(IUnknown *punk) +TSFTextStore::UnadviseSink(IUnknown* punk) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::UnadviseSink(punk=0x%p), mSink=0x%p", + ("TSF: 0x%p TSFTextStore::UnadviseSink(punk=0x%p), mSink=0x%p", this, punk, mSink.get())); if (!punk) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to the null punk", + ("TSF: 0x%p TSFTextStore::UnadviseSink() FAILED due to the null punk", this)); return E_INVALIDARG; } if (!mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::UnadviseSink() FAILED due to " "any sink not stored", this)); return CONNECT_E_NOCONNECTION; } @@ -1479,7 +1482,7 @@ nsTextStore::UnadviseSink(IUnknown *punk) // Unadvise only if sinks are the same if (comparison1 != comparison2) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::UnadviseSink() FAILED due to " "the sink being different from the stored sink", this)); return CONNECT_E_NOCONNECTION; } @@ -1489,23 +1492,23 @@ nsTextStore::UnadviseSink(IUnknown *punk) } STDMETHODIMP -nsTextStore::RequestLock(DWORD dwLockFlags, - HRESULT *phrSession) +TSFTextStore::RequestLock(DWORD dwLockFlags, + HRESULT* phrSession) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), " + ("TSF: 0x%p TSFTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), " "mLock=%s", this, GetLockFlagNameStr(dwLockFlags).get(), phrSession, GetLockFlagNameStr(mLock).get())); if (!mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " + ("TSF: 0x%p TSFTextStore::RequestLock() FAILED due to " "any sink not stored", this)); return E_FAIL; } if (!phrSession) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RequestLock() FAILED due to " + ("TSF: 0x%p TSFTextStore::RequestLock() FAILED due to " "null phrSession", this)); return E_INVALIDARG; } @@ -1519,7 +1522,7 @@ nsTextStore::RequestLock(DWORD dwLockFlags, this, GetLockFlagNameStr(mLock).get())); // Don't release this instance during this lock because this is called by // TSF but they don't grab us during this call. - nsRefPtr kungFuDeathGrip(this); + nsRefPtr kungFuDeathGrip(this); *phrSession = mSink->OnLockGranted(mLock); MOZ_LOG(sTextStoreLog, LogLevel::Info, ("TSF: 0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" @@ -1547,7 +1550,7 @@ nsTextStore::RequestLock(DWORD dwLockFlags, MaybeFlushPendingNotifications(); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestLock() succeeded: *phrSession=%s", + ("TSF: 0x%p TSFTextStore::RequestLock() succeeded: *phrSession=%s", this, GetTextStoreReturnValueName(*phrSession))); return S_OK; } @@ -1560,21 +1563,21 @@ nsTextStore::RequestLock(DWORD dwLockFlags, mLockQueued = dwLockFlags & (~TS_LF_SYNC); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestLock() stores the request in the " + ("TSF: 0x%p TSFTextStore::RequestLock() stores the request in the " "queue, *phrSession=TS_S_ASYNC", this)); return S_OK; } // no more locks allowed MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestLock() didn't allow to lock, " + ("TSF: 0x%p TSFTextStore::RequestLock() didn't allow to lock, " "*phrSession=TS_E_SYNCHRONOUS", this)); *phrSession = TS_E_SYNCHRONOUS; return E_FAIL; } void -nsTextStore::DidLockGranted() +TSFTextStore::DidLockGranted() { if (mNativeCaretIsCreated) { ::DestroyCaret(); @@ -1599,7 +1602,7 @@ nsTextStore::DidLockGranted() } void -nsTextStore::DispatchEvent(WidgetGUIEvent& aEvent) +TSFTextStore::DispatchEvent(WidgetGUIEvent& aEvent) { if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) { return; @@ -1613,7 +1616,7 @@ nsTextStore::DispatchEvent(WidgetGUIEvent& aEvent) } void -nsTextStore::FlushPendingActions() +TSFTextStore::FlushPendingActions() { if (!mWidget || mWidget->Destroyed()) { mPendingActions.Clear(); @@ -1634,7 +1637,7 @@ nsTextStore::FlushPendingActions() switch (action.mType) { case PendingAction::COMPOSITION_START: { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "flushing COMPOSITION_START={ mSelectionStart=%d, " "mSelectionLength=%d }", this, action.mSelectionStart, action.mSelectionLength)); @@ -1649,13 +1652,13 @@ nsTextStore::FlushPendingActions() DispatchEvent(selectionSet); if (!selectionSet.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "FAILED due to NS_SELECTION_SET failure", this)); break; } } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "dispatching compositionstart event...", this)); WidgetCompositionEvent compositionStart(true, NS_COMPOSITION_START, mWidget); @@ -1670,7 +1673,7 @@ nsTextStore::FlushPendingActions() } case PendingAction::COMPOSITION_UPDATE: { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "flushing COMPOSITION_UPDATE={ mData=\"%s\", " "mRanges=0x%p, mRanges->Length()=%d }", this, NS_ConvertUTF16toUTF8(action.mData).get(), action.mRanges.get(), @@ -1711,7 +1714,7 @@ nsTextStore::FlushPendingActions() NS_LITERAL_STRING("\n")); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions(), " + ("TSF: 0x%p TSFTextStore::FlushPendingActions(), " "dispatching compositionchange event...", this)); WidgetCompositionEvent compositionChange(true, NS_COMPOSITION_CHANGE, mWidget); @@ -1736,7 +1739,7 @@ nsTextStore::FlushPendingActions() } case PendingAction::COMPOSITION_END: { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "flushing COMPOSITION_END={ mData=\"%s\" }", this, NS_ConvertUTF16toUTF8(action.mData).get())); @@ -1744,7 +1747,7 @@ nsTextStore::FlushPendingActions() NS_LITERAL_STRING("\n")); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions(), " + ("TSF: 0x%p TSFTextStore::FlushPendingActions(), " "dispatching compositioncommit event...", this)); WidgetCompositionEvent compositionCommit(true, NS_COMPOSITION_COMMIT, mWidget); @@ -1763,7 +1766,7 @@ nsTextStore::FlushPendingActions() } case PendingAction::SELECTION_SET: { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::FlushPendingActions() " + ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "flushing SELECTION_SET={ mSelectionStart=%d, " "mSelectionLength=%d, mSelectionReversed=%s }", this, action.mSelectionStart, action.mSelectionLength, @@ -1786,7 +1789,7 @@ nsTextStore::FlushPendingActions() } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::FlushPendingActions(), " + ("TSF: 0x%p TSFTextStore::FlushPendingActions(), " "qutting since the mWidget has gone", this)); break; } @@ -1794,11 +1797,11 @@ nsTextStore::FlushPendingActions() } void -nsTextStore::MaybeFlushPendingNotifications() +TSFTextStore::MaybeFlushPendingNotifications() { if (mDeferNotifyingTSF) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MaybeFlushPendingNotifications(), " + ("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), " "putting off flushing pending notifications due to being " "dispatching events...", this)); return; @@ -1806,7 +1809,7 @@ nsTextStore::MaybeFlushPendingNotifications() if (IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MaybeFlushPendingNotifications(), " + ("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), " "putting off flushing pending notifications due to being the " "document locked...", this)); return; @@ -1824,28 +1827,28 @@ nsTextStore::MaybeFlushPendingNotifications() if (mPendingOnLayoutChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::MaybeFlushPendingNotifications(), " - "calling nsTextStore::NotifyTSFOfLayoutChange()...", this)); + ("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), " + "calling TSFTextStore::NotifyTSFOfLayoutChange()...", this)); NotifyTSFOfLayoutChange(true); } if (mPendingOnSelectionChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::MaybeFlushPendingNotifications(), " - "calling nsTextStore::NotifyTSFOfSelectionChange()...", this)); + ("TSF: 0x%p TSFTextStore::MaybeFlushPendingNotifications(), " + "calling TSFTextStore::NotifyTSFOfSelectionChange()...", this)); NotifyTSFOfSelectionChange(); } } STDMETHODIMP -nsTextStore::GetStatus(TS_STATUS *pdcs) +TSFTextStore::GetStatus(TS_STATUS* pdcs) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetStatus(pdcs=0x%p)", this, pdcs)); + ("TSF: 0x%p TSFTextStore::GetStatus(pdcs=0x%p)", this, pdcs)); if (!pdcs) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetStatus() FAILED due to null pdcs", this)); + ("TSF: 0x%p TSFTextStore::GetStatus() FAILED due to null pdcs", this)); return E_INVALIDARG; } pdcs->dwDynamicFlags = 0; @@ -1855,27 +1858,27 @@ nsTextStore::GetStatus(TS_STATUS *pdcs) } STDMETHODIMP -nsTextStore::QueryInsert(LONG acpTestStart, - LONG acpTestEnd, - ULONG cch, - LONG *pacpResultStart, - LONG *pacpResultEnd) +TSFTextStore::QueryInsert(LONG acpTestStart, + LONG acpTestEnd, + ULONG cch, + LONG* pacpResultStart, + LONG* pacpResultEnd) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::QueryInsert(acpTestStart=%ld, " + ("TSF: 0x%p TSFTextStore::QueryInsert(acpTestStart=%ld, " "acpTestEnd=%ld, cch=%lu, pacpResultStart=0x%p, pacpResultEnd=0x%p)", this, acpTestStart, acpTestEnd, cch, acpTestStart, acpTestEnd)); if (!pacpResultStart || !pacpResultEnd) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " + ("TSF: 0x%p TSFTextStore::QueryInsert() FAILED due to " "the null argument", this)); return E_INVALIDARG; } if (acpTestStart < 0 || acpTestStart > acpTestEnd) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::QueryInsert() FAILED due to " + ("TSF: 0x%p TSFTextStore::QueryInsert() FAILED due to " "wrong argument", this)); return E_INVALIDARG; } @@ -1886,32 +1889,32 @@ nsTextStore::QueryInsert(LONG acpTestStart, *pacpResultEnd = acpTestStart + cch; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::QueryInsert() succeeded: " + ("TSF: 0x%p TSFTextStore::QueryInsert() succeeded: " "*pacpResultStart=%ld, *pacpResultEnd=%ld)", this, *pacpResultStart, *pacpResultEnd)); return S_OK; } STDMETHODIMP -nsTextStore::GetSelection(ULONG ulIndex, - ULONG ulCount, - TS_SELECTION_ACP *pSelection, - ULONG *pcFetched) +TSFTextStore::GetSelection(ULONG ulIndex, + ULONG ulCount, + TS_SELECTION_ACP* pSelection, + ULONG* pcFetched) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetSelection(ulIndex=%lu, ulCount=%lu, " + ("TSF: 0x%p TSFTextStore::GetSelection(ulIndex=%lu, ulCount=%lu, " "pSelection=0x%p, pcFetched=0x%p)", this, ulIndex, ulCount, pSelection, pcFetched)); if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to not locked", + ("TSF: 0x%p TSFTextStore::GetSelection() FAILED due to not locked", this)); return TS_E_NOLOCK; } if (!ulCount || !pSelection || !pcFetched) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetSelection() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -1921,7 +1924,7 @@ nsTextStore::GetSelection(ULONG ulIndex, if (ulIndex != static_cast(TS_DEFAULT_SELECTION) && ulIndex != 0) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetSelection() FAILED due to " "unsupported selection", this)); return TS_E_NOSELECTION; } @@ -1929,19 +1932,19 @@ nsTextStore::GetSelection(ULONG ulIndex, Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetSelection() FAILED due to " "CurrentSelection() failure", this)); return E_FAIL; } *pSelection = currentSel.ACP(); *pcFetched = 1; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetSelection() succeeded", this)); + ("TSF: 0x%p TSFTextStore::GetSelection() succeeded", this)); return S_OK; } -nsTextStore::Content& -nsTextStore::LockedContent() +TSFTextStore::Content& +TSFTextStore::LockedContent() { // This should be called when the document is locked or the content hasn't // been abandoned yet. @@ -1967,7 +1970,7 @@ nsTextStore::LockedContent() } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::LockedContent(): " + ("TSF: 0x%p TSFTextStore::LockedContent(): " "mLockedContent={ mText.Length()=%d }", this, mLockedContent.Text().Length())); @@ -1975,7 +1978,7 @@ nsTextStore::LockedContent() } bool -nsTextStore::GetCurrentText(nsAString& aTextContent) +TSFTextStore::GetCurrentText(nsAString& aTextContent) { if (mLockedContent.IsInitialized()) { aTextContent = mLockedContent.Text(); @@ -1997,8 +2000,8 @@ nsTextStore::GetCurrentText(nsAString& aTextContent) return true; } -nsTextStore::Selection& -nsTextStore::CurrentSelection() +TSFTextStore::Selection& +TSFTextStore::CurrentSelection() { if (mSelection.IsDirty()) { // If the window has never been available, we should crash since working @@ -2020,7 +2023,7 @@ nsTextStore::CurrentSelection() } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::CurrentSelection(): " + ("TSF: 0x%p TSFTextStore::CurrentSelection(): " "acpStart=%d, acpEnd=%d (length=%d), reverted=%s", this, mSelection.StartOffset(), mSelection.EndOffset(), mSelection.Length(), @@ -2039,7 +2042,7 @@ GetRangeExtent(ITfRange* aRange, LONG* aStart, LONG* aLength) } static uint32_t -GetGeckoSelectionValue(TF_DISPLAYATTRIBUTE &aDisplayAttr) +GetGeckoSelectionValue(TF_DISPLAYATTRIBUTE& aDisplayAttr) { uint32_t result; switch (aDisplayAttr.bAttr) { @@ -2060,9 +2063,9 @@ GetGeckoSelectionValue(TF_DISPLAYATTRIBUTE &aDisplayAttr) } HRESULT -nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, - ITfRange* aRange, - TF_DISPLAYATTRIBUTE* aResult) +TSFTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, + ITfRange* aRange, + TF_DISPLAYATTRIBUTE* aResult) { NS_ENSURE_TRUE(aAttrProperty, E_FAIL); NS_ENSURE_TRUE(aRange, E_FAIL); @@ -2074,7 +2077,7 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, LONG start = 0, length = 0; hr = GetRangeExtent(aRange, &start, &length); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute(): " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute(): " "GetDisplayAttribute range=%ld-%ld (hr=%s)", this, start - mComposition.mStart, start - mComposition.mStart + length, @@ -2086,13 +2089,13 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, hr = aAttrProperty->GetValue(TfEditCookie(mEditCookie), aRange, &propValue); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() FAILED due to " "ITfProperty::GetValue() failed", this)); return hr; } if (VT_I4 != propValue.vt) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() FAILED due to " "ITfProperty::GetValue() returns non-VT_I4 value", this)); ::VariantClear(&propValue); return E_FAIL; @@ -2104,7 +2107,7 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, ::VariantClear(&propValue); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() FAILED due to " "ITfCategoryMgr::GetGUID() failed", this)); return hr; } @@ -2115,7 +2118,7 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, nullptr); if (FAILED(hr) || !info) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() FAILED due to " "ITfDisplayAttributeMgr::GetDisplayAttributeInfo() failed", this)); return hr; } @@ -2123,28 +2126,28 @@ nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty, hr = info->GetAttributeInfo(aResult); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() FAILED due to " "ITfDisplayAttributeInfo::GetAttributeInfo() failed", this)); return hr; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetDisplayAttribute() succeeded: " + ("TSF: 0x%p TSFTextStore::GetDisplayAttribute() succeeded: " "Result={ %s }", this, GetDisplayAttrStr(*aResult).get())); return S_OK; } HRESULT -nsTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) +TSFTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary(" + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary(" "aRangeNew=0x%p), mComposition.mView=0x%p", this, aRangeNew, mComposition.mView.get())); if (!mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary() FAILED " "due to no composition view", this)); return E_FAIL; } @@ -2156,8 +2159,8 @@ nsTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) hr = pComposition->GetRange(getter_AddRefs(composingRange)); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " - "due to pComposition->GetRange() failure", this)); + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary() " + "FAILED due to pComposition->GetRange() failure", this)); return hr; } } @@ -2167,13 +2170,13 @@ nsTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) hr = GetRangeExtent(composingRange, &compStart, &compLength); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary() FAILED " "due to GetRangeExtent() failure", this)); return hr; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary(), " + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary(), " "range=%ld-%ld, mComposition={ mStart=%ld, mString.Length()=%lu }", this, compStart, compStart + compLength, mComposition.mStart, mComposition.mString.Length())); @@ -2186,21 +2189,21 @@ nsTextStore::RestartCompositionIfNecessary(ITfRange* aRangeNew) hr = RestartComposition(pComposition, composingRange); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() FAILED " - "due to RestartComposition() failure", this)); + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary() " + "FAILED due to RestartComposition() failure", this)); return hr; } } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RestartCompositionIfNecessary() succeeded", + ("TSF: 0x%p TSFTextStore::RestartCompositionIfNecessary() succeeded", this)); return S_OK; } HRESULT -nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, - ITfRange* aNewRange) +TSFTextStore::RestartComposition(ITfCompositionView* aCompositionView, + ITfRange* aNewRange) { Selection& currentSelection = CurrentSelection(); @@ -2209,7 +2212,7 @@ nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, LONG newEnd = newStart + newLength; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RestartComposition(aCompositionView=0x%p, " + ("TSF: 0x%p TSFTextStore::RestartComposition(aCompositionView=0x%p, " "aNewRange=0x%p { newStart=%d, newLength=%d }), " "mComposition={ mStart=%d, mCompositionString.Length()=%d }, " "currentSelection={ IsDirty()=%s, StartOffset()=%d, Length()=%d }", @@ -2220,14 +2223,14 @@ nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, if (currentSelection.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartComposition() FAILED " + ("TSF: 0x%p TSFTextStore::RestartComposition() FAILED " "due to CurrentSelection() failure", this)); return E_FAIL; } if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartComposition() FAILED " + ("TSF: 0x%p TSFTextStore::RestartComposition() FAILED " "due to GetRangeExtent() failure", this)); return hr; } @@ -2264,7 +2267,7 @@ nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RestartComposition() FAILED " + ("TSF: 0x%p TSFTextStore::RestartComposition() FAILED " "due to LockedContent() failure", this)); return E_FAIL; } @@ -2297,7 +2300,7 @@ nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, currentSelection = oldSelection; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RestartComposition() succeeded, " + ("TSF: 0x%p TSFTextStore::RestartComposition() succeeded, " "mComposition={ mStart=%d, mCompositionString.Length()=%d }, " "currentSelection={ IsDirty()=%s, StartOffset()=%d, Length()=%d }", this, mComposition.mStart, mComposition.mString.Length(), @@ -2308,7 +2311,7 @@ nsTextStore::RestartComposition(ITfCompositionView* aCompositionView, } static bool -GetColor(const TF_DA_COLOR &aTSFColor, nscolor &aResult) +GetColor(const TF_DA_COLOR& aTSFColor, nscolor& aResult) { switch (aTSFColor.type) { case TF_CT_SYSCOLOR: { @@ -2328,7 +2331,7 @@ GetColor(const TF_DA_COLOR &aTSFColor, nscolor &aResult) } static bool -GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, uint8_t &aTextRangeLineStyle) +GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, uint8_t& aTextRangeLineStyle) { switch (aTSFLineStyle) { case TF_LS_NONE: @@ -2352,10 +2355,10 @@ GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, uint8_t &aTextRangeLineStyle) } HRESULT -nsTextStore::RecordCompositionUpdateAction() +TSFTextStore::RecordCompositionUpdateAction() { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction(), " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction(), " "mComposition={ mView=0x%p, mStart=%d, mString=\"%s\" " "(Length()=%d) }", this, mComposition.mView.get(), mComposition.mStart, @@ -2364,7 +2367,7 @@ nsTextStore::RecordCompositionUpdateAction() if (!mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() FAILED " "due to no composition view", this)); return E_FAIL; } @@ -2382,7 +2385,7 @@ nsTextStore::RecordCompositionUpdateAction() getter_AddRefs(attrPropetry)); if (FAILED(hr) || !attrPropetry) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() FAILED " "due to mContext->GetProperty() failure", this)); return FAILED(hr) ? hr : E_FAIL; } @@ -2391,7 +2394,7 @@ nsTextStore::RecordCompositionUpdateAction() hr = mComposition.mView->GetRange(getter_AddRefs(composingRange)); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() " "FAILED due to mComposition.mView->GetRange() failure", this)); return hr; } @@ -2401,7 +2404,7 @@ nsTextStore::RecordCompositionUpdateAction() getter_AddRefs(enumRanges), composingRange); if (FAILED(hr) || !enumRanges) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() FAILED " "due to attrPropetry->EnumRanges() failure", this)); return FAILED(hr) ? hr : E_FAIL; } @@ -2410,7 +2413,7 @@ nsTextStore::RecordCompositionUpdateAction() Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() FAILED " "due to CurrentSelection() failure", this)); return E_FAIL; } @@ -2447,7 +2450,7 @@ nsTextStore::RecordCompositionUpdateAction() LONG length = end - start; if (length < 0) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() " "ignores invalid range (%d-%d)", this, rangeStart - mComposition.mStart, rangeStart - mComposition.mStart + rangeLength)); @@ -2455,7 +2458,7 @@ nsTextStore::RecordCompositionUpdateAction() } if (!length) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() " "ignores a range due to outside of the composition or empty " "(%d-%d)", this, rangeStart - mComposition.mStart, @@ -2537,18 +2540,18 @@ nsTextStore::RecordCompositionUpdateAction() action->mIncomplete = false; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RecordCompositionUpdateAction() " + ("TSF: 0x%p TSFTextStore::RecordCompositionUpdateAction() " "succeeded", this)); return S_OK; } HRESULT -nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, - bool aDispatchCompositionChangeEvent) +TSFTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, + bool aDispatchCompositionChangeEvent) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::SetSelectionInternal(pSelection={ " + ("TSF: 0x%p TSFTextStore::SetSelectionInternal(pSelection={ " "acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s} }, " "aDispatchCompositionChangeEvent=%s), mComposition.IsComposing()=%s", this, pSelection->acpStart, pSelection->acpEnd, @@ -2562,7 +2565,7 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelectionInternal() FAILED due to " "CurrentSelection() failure", this)); return E_FAIL; } @@ -2572,7 +2575,7 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, HRESULT hr = RestartCompositionIfNecessary(); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelectionInternal() FAILED due to " "RestartCompositionIfNecessary() failure", this)); return hr; } @@ -2580,7 +2583,7 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, if (pSelection->acpStart < mComposition.mStart || pSelection->acpEnd > mComposition.EndOffset()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelectionInternal() FAILED due to " "the selection being out of the composition string", this)); return TS_E_INVALIDPOS; } @@ -2590,7 +2593,7 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, HRESULT hr = RecordCompositionUpdateAction(); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelectionInternal() FAILED due to " "RecordCompositionUpdateAction() failure", this)); return hr; } @@ -2611,11 +2614,11 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, } STDMETHODIMP -nsTextStore::SetSelection(ULONG ulCount, - const TS_SELECTION_ACP *pSelection) +TSFTextStore::SetSelection(ULONG ulCount, + const TS_SELECTION_ACP* pSelection) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu, pSelection=%p { " + ("TSF: 0x%p TSFTextStore::SetSelection(ulCount=%lu, pSelection=%p { " "acpStart=%ld, acpEnd=%ld, style={ ase=%s, fInterimChar=%s } }), " "mComposition.IsComposing()=%s", this, ulCount, pSelection, @@ -2627,19 +2630,19 @@ nsTextStore::SetSelection(ULONG ulCount, if (!IsReadWriteLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelection() FAILED due to " "not locked (read-write)", this)); return TS_E_NOLOCK; } if (ulCount != 1) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelection() FAILED due to " "trying setting multiple selection", this)); return E_INVALIDARG; } if (!pSelection) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelection() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -2647,28 +2650,28 @@ nsTextStore::SetSelection(ULONG ulCount, HRESULT hr = SetSelectionInternal(pSelection, true); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetSelection() FAILED due to " "SetSelectionInternal() failure", this)); } else { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::SetSelection() succeeded", this)); + ("TSF: 0x%p TSFTextStore::SetSelection() succeeded", this)); } return hr; } STDMETHODIMP -nsTextStore::GetText(LONG acpStart, - LONG acpEnd, - WCHAR *pchPlain, - ULONG cchPlainReq, - ULONG *pcchPlainOut, - TS_RUNINFO *prgRunInfo, - ULONG ulRunInfoReq, - ULONG *pulRunInfoOut, - LONG *pacpNext) +TSFTextStore::GetText(LONG acpStart, + LONG acpEnd, + WCHAR* pchPlain, + ULONG cchPlainReq, + ULONG* pcchPlainOut, + TS_RUNINFO* prgRunInfo, + ULONG ulRunInfoReq, + ULONG* pulRunInfoOut, + LONG* pacpNext) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, " + ("TSF: 0x%p TSFTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, " "cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, " "pulRunInfoOut=0x%p, pacpNext=0x%p), mComposition={ mStart=%ld, " "mString.Length()=%lu, IsComposing()=%s }", @@ -2679,7 +2682,7 @@ nsTextStore::GetText(LONG acpStart, if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } @@ -2687,14 +2690,14 @@ nsTextStore::GetText(LONG acpStart, if (!pcchPlainOut || (!pchPlain && !prgRunInfo) || !cchPlainReq != !pchPlain || !ulRunInfoReq != !prgRunInfo) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "invalid argument", this)); return E_INVALIDARG; } if (acpStart < 0 || acpEnd < -1 || (acpEnd != -1 && acpStart > acpEnd)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "invalid position", this)); return TS_E_INVALIDPOS; } @@ -2712,20 +2715,20 @@ nsTextStore::GetText(LONG acpStart, Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "LockedContent() failure", this)); return E_FAIL; } if (lockedContent.Text().Length() < static_cast(acpStart)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "acpStart is larger offset than the actual text length", this)); return TS_E_INVALIDPOS; } if (acpEnd != -1 && lockedContent.Text().Length() < static_cast(acpEnd)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetText() FAILED due to " "acpEnd is larger offset than the actual text length", this)); return TS_E_INVALIDPOS; } @@ -2752,7 +2755,7 @@ nsTextStore::GetText(LONG acpStart, } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetText() succeeded: pcchPlainOut=0x%p, " + ("TSF: 0x%p TSFTextStore::GetText() succeeded: pcchPlainOut=0x%p, " "*prgRunInfo={ uCount=%lu, type=%s }, *pulRunInfoOut=%lu, " "*pacpNext=%ld)", this, pcchPlainOut, prgRunInfo ? prgRunInfo->uCount : 0, @@ -2762,15 +2765,15 @@ nsTextStore::GetText(LONG acpStart, } STDMETHODIMP -nsTextStore::SetText(DWORD dwFlags, - LONG acpStart, - LONG acpEnd, - const WCHAR *pchText, - ULONG cch, - TS_TEXTCHANGE *pChange) +TSFTextStore::SetText(DWORD dwFlags, + LONG acpStart, + LONG acpEnd, + const WCHAR* pchText, + ULONG cch, + TS_TEXTCHANGE* pChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, " + ("TSF: 0x%p TSFTextStore::SetText(dwFlags=%s, acpStart=%ld, " "acpEnd=%ld, pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), " "mComposition.IsComposing()=%s", this, dwFlags == TS_ST_CORRECTION ? "TS_ST_CORRECTION" : @@ -2785,7 +2788,7 @@ nsTextStore::SetText(DWORD dwFlags, // call SetSelection followed by InsertTextAtSelection if (!IsReadWriteLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetText() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } @@ -2799,7 +2802,7 @@ nsTextStore::SetText(DWORD dwFlags, HRESULT hr = SetSelectionInternal(&selection); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetText() FAILED due to " "SetSelectionInternal() failure", this)); return hr; } @@ -2807,13 +2810,13 @@ nsTextStore::SetText(DWORD dwFlags, if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), pChange)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::SetText() FAILED due to " + ("TSF: 0x%p TSFTextStore::SetText() FAILED due to " "InsertTextAtSelectionInternal() failure", this)); return E_FAIL; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::SetText() succeeded: pChange={ " + ("TSF: 0x%p TSFTextStore::SetText() succeeded: pChange={ " "acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }", this, pChange ? pChange->acpStart : 0, pChange ? pChange->acpOldEnd : 0, pChange ? pChange->acpNewEnd : 0)); @@ -2821,12 +2824,12 @@ nsTextStore::SetText(DWORD dwFlags, } STDMETHODIMP -nsTextStore::GetFormattedText(LONG acpStart, - LONG acpEnd, - IDataObject **ppDataObject) +TSFTextStore::GetFormattedText(LONG acpStart, + LONG acpEnd, + IDataObject** ppDataObject) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetFormattedText() called " + ("TSF: 0x%p TSFTextStore::GetFormattedText() called " "but not supported (E_NOTIMPL)", this)); // no support for formatted text @@ -2834,13 +2837,13 @@ nsTextStore::GetFormattedText(LONG acpStart, } STDMETHODIMP -nsTextStore::GetEmbedded(LONG acpPos, - REFGUID rguidService, - REFIID riid, - IUnknown **ppunk) +TSFTextStore::GetEmbedded(LONG acpPos, + REFGUID rguidService, + REFIID riid, + IUnknown** ppunk) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetEmbedded() called " + ("TSF: 0x%p TSFTextStore::GetEmbedded() called " "but not supported (E_NOTIMPL)", this)); // embedded objects are not supported @@ -2848,12 +2851,12 @@ nsTextStore::GetEmbedded(LONG acpPos, } STDMETHODIMP -nsTextStore::QueryInsertEmbedded(const GUID *pguidService, - const FORMATETC *pFormatEtc, - BOOL *pfInsertable) +TSFTextStore::QueryInsertEmbedded(const GUID* pguidService, + const FORMATETC* pFormatEtc, + BOOL* pfInsertable) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::QueryInsertEmbedded() called " + ("TSF: 0x%p TSFTextStore::QueryInsertEmbedded() called " "but not supported, *pfInsertable=FALSE (S_OK)", this)); // embedded objects are not supported @@ -2862,14 +2865,14 @@ nsTextStore::QueryInsertEmbedded(const GUID *pguidService, } STDMETHODIMP -nsTextStore::InsertEmbedded(DWORD dwFlags, - LONG acpStart, - LONG acpEnd, - IDataObject *pDataObject, - TS_TEXTCHANGE *pChange) +TSFTextStore::InsertEmbedded(DWORD dwFlags, + LONG acpStart, + LONG acpEnd, + IDataObject* pDataObject, + TS_TEXTCHANGE* pChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::InsertEmbedded() called " + ("TSF: 0x%p TSFTextStore::InsertEmbedded() called " "but not supported (E_NOTIMPL)", this)); // embedded objects are not supported @@ -2877,7 +2880,7 @@ nsTextStore::InsertEmbedded(DWORD dwFlags, } void -nsTextStore::SetInputScope(const nsString& aHTMLInputType) +TSFTextStore::SetInputScope(const nsString& aHTMLInputType) { mInputScopes.Clear(); if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) { @@ -2912,7 +2915,7 @@ nsTextStore::SetInputScope(const nsString& aHTMLInputType) } int32_t -nsTextStore::GetRequestedAttrIndex(const TS_ATTRID& aAttrID) +TSFTextStore::GetRequestedAttrIndex(const TS_ATTRID& aAttrID) { if (IsEqualGUID(aAttrID, GUID_PROP_INPUTSCOPE)) { return eInputScope; @@ -2927,7 +2930,7 @@ nsTextStore::GetRequestedAttrIndex(const TS_ATTRID& aAttrID) } TS_ATTRID -nsTextStore::GetAttrID(int32_t aIndex) +TSFTextStore::GetAttrID(int32_t aIndex) { switch (aIndex) { case eInputScope: @@ -2943,12 +2946,12 @@ nsTextStore::GetAttrID(int32_t aIndex) } HRESULT -nsTextStore::HandleRequestAttrs(DWORD aFlags, - ULONG aFilterCount, - const TS_ATTRID* aFilterAttrs) +TSFTextStore::HandleRequestAttrs(DWORD aFlags, + ULONG aFilterCount, + const TS_ATTRID* aFilterAttrs) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::HandleRequestAttrs(aFlags=%s, " + ("TSF: 0x%p TSFTextStore::HandleRequestAttrs(aFlags=%s, " "aFilterCount=%u)", this, GetFindFlagName(aFlags).get(), aFilterCount)); @@ -2965,7 +2968,7 @@ nsTextStore::HandleRequestAttrs(DWORD aFlags, for (uint32_t i = 0; i < aFilterCount; i++) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::HandleRequestAttrs(), " + ("TSF: 0x%p TSFTextStore::HandleRequestAttrs(), " "requested attr=%s", this, GetGUIDNameStrWithTable(aFilterAttrs[i]).get())); int32_t index = GetRequestedAttrIndex(aFilterAttrs[i]); @@ -2977,12 +2980,12 @@ nsTextStore::HandleRequestAttrs(DWORD aFlags, } STDMETHODIMP -nsTextStore::RequestSupportedAttrs(DWORD dwFlags, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs) +TSFTextStore::RequestSupportedAttrs(DWORD dwFlags, + ULONG cFilterAttrs, + const TS_ATTRID* paFilterAttrs) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestSupportedAttrs(dwFlags=%s, " + ("TSF: 0x%p TSFTextStore::RequestSupportedAttrs(dwFlags=%s, " "cFilterAttrs=%lu)", this, GetFindFlagName(dwFlags).get(), cFilterAttrs)); @@ -2990,13 +2993,13 @@ nsTextStore::RequestSupportedAttrs(DWORD dwFlags, } STDMETHODIMP -nsTextStore::RequestAttrsAtPosition(LONG acpPos, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs, - DWORD dwFlags) +TSFTextStore::RequestAttrsAtPosition(LONG acpPos, + ULONG cFilterAttrs, + const TS_ATTRID* paFilterAttrs, + DWORD dwFlags) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestAttrsAtPosition(acpPos=%ld, " + ("TSF: 0x%p TSFTextStore::RequestAttrsAtPosition(acpPos=%ld, " "cFilterAttrs=%lu, dwFlags=%s)", this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get())); @@ -3005,13 +3008,13 @@ nsTextStore::RequestAttrsAtPosition(LONG acpPos, } STDMETHODIMP -nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttr, - DWORD dwFlags) +TSFTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, + ULONG cFilterAttrs, + const TS_ATTRID* paFilterAttr, + DWORD dwFlags) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition(" + ("TSF: 0x%p TSFTextStore::RequestAttrsTransitioningAtPosition(" "acpPos=%ld, cFilterAttrs=%lu, dwFlags=%s) called but not supported " "(S_OK)", this, acpPos, cFilterAttrs, GetFindFlagName(dwFlags).get())); @@ -3021,24 +3024,24 @@ nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos, } STDMETHODIMP -nsTextStore::FindNextAttrTransition(LONG acpStart, - LONG acpHalt, - ULONG cFilterAttrs, - const TS_ATTRID *paFilterAttrs, - DWORD dwFlags, - LONG *pacpNext, - BOOL *pfFound, - LONG *plFoundOffset) +TSFTextStore::FindNextAttrTransition(LONG acpStart, + LONG acpHalt, + ULONG cFilterAttrs, + const TS_ATTRID* paFilterAttrs, + DWORD dwFlags, + LONG* pacpNext, + BOOL* pfFound, + LONG* plFoundOffset) { if (!pacpNext || !pfFound || !plFoundOffset) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::FindNextAttrTransition() FAILED due to " + ("TSF: 0x%p TSFTextStore::FindNextAttrTransition() FAILED due to " "null argument", this)); return E_INVALIDARG; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::FindNextAttrTransition() called " + ("TSF: 0x%p TSFTextStore::FindNextAttrTransition() called " "but not supported (S_OK)", this)); // no per character attributes defined @@ -3048,13 +3051,13 @@ nsTextStore::FindNextAttrTransition(LONG acpStart, } STDMETHODIMP -nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, - TS_ATTRVAL *paAttrVals, - ULONG *pcFetched) +TSFTextStore::RetrieveRequestedAttrs(ULONG ulCount, + TS_ATTRVAL* paAttrVals, + ULONG* pcFetched) { if (!pcFetched || !paAttrVals) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() FAILED due to " + ("TSF: 0x%p TSFTextStore::RetrieveRequestedAttrs() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3067,14 +3070,14 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, } if (ulCount < expectedCount) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() FAILED due to " + ("TSF: 0x%p TSFTextStore::RetrieveRequestedAttrs() FAILED due to " "not enough count ulCount=%u, expectedCount=%u", this, ulCount, expectedCount)); return E_INVALIDARG; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called " + ("TSF: 0x%p TSFTextStore::RetrieveRequestedAttrs() called " "ulCount=%d, mRequestedAttrValues=%s", this, ulCount, GetBoolName(mRequestedAttrValues))); @@ -3088,7 +3091,7 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRID attrID = GetAttrID(i); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() for %s", + ("TSF: 0x%p TSFTextStore::RetrieveRequestedAttrs() for %s", this, GetGUIDNameStrWithTable(attrID).get())); paAttrVals[count].idAttr = attrID; @@ -3135,7 +3138,7 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called " + ("TSF: 0x%p TSFTextStore::RetrieveRequestedAttrs() called " "for unknown TS_ATTRVAL, *pcFetched=0 (S_OK)", this)); paAttrVals->dwOverlapId = 0; @@ -3145,21 +3148,21 @@ nsTextStore::RetrieveRequestedAttrs(ULONG ulCount, } STDMETHODIMP -nsTextStore::GetEndACP(LONG *pacp) +TSFTextStore::GetEndACP(LONG* pacp) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetEndACP(pacp=0x%p)", this, pacp)); + ("TSF: 0x%p TSFTextStore::GetEndACP(pacp=0x%p)", this, pacp)); if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetEndACP() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } if (!pacp) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetEndACP() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3167,7 +3170,7 @@ nsTextStore::GetEndACP(LONG *pacp) Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetEndACP() FAILED due to " "LockedContent() failure", this)); return E_FAIL; } @@ -3176,14 +3179,15 @@ nsTextStore::GetEndACP(LONG *pacp) } STDMETHODIMP -nsTextStore::GetActiveView(TsViewCookie *pvcView) +TSFTextStore::GetActiveView(TsViewCookie* pvcView) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetActiveView(pvcView=0x%p)", this, pvcView)); + ("TSF: 0x%p TSFTextStore::GetActiveView(pvcView=0x%p)", + this, pvcView)); if (!pvcView) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetActiveView() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetActiveView() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3191,19 +3195,19 @@ nsTextStore::GetActiveView(TsViewCookie *pvcView) *pvcView = TEXTSTORE_DEFAULT_VIEW; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetActiveView() succeeded: *pvcView=%ld", + ("TSF: 0x%p TSFTextStore::GetActiveView() succeeded: *pvcView=%ld", this, *pvcView)); return S_OK; } STDMETHODIMP -nsTextStore::GetACPFromPoint(TsViewCookie vcView, - const POINT *pt, - DWORD dwFlags, - LONG *pacp) +TSFTextStore::GetACPFromPoint(TsViewCookie vcView, + const POINT* pt, + DWORD dwFlags, + LONG* pacp) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetACPFromPoint(pvcView=%d, pt=%p (x=%d, " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint(pvcView=%d, pt=%p (x=%d, " "y=%d), dwFlags=%s, pacp=%p, mDeferNotifyingTSF=%s", this, vcView, pt, pt ? pt->x : 0, pt ? pt->y : 0, GetACPFromPointFlagName(dwFlags).get(), pacp, @@ -3211,35 +3215,35 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } if (vcView != TEXTSTORE_DEFAULT_VIEW) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "called with invalid view", this)); return E_INVALIDARG; } if (!pt) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "null pt", this)); return E_INVALIDARG; } if (!pacp) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "null pacp", this)); return E_INVALIDARG; } if (mLockedContent.IsLayoutChanged()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "layout not recomputed", this)); mPendingOnLayoutChange = true; return TS_E_NOLAYOUT; @@ -3257,24 +3261,24 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, // FYI: WidgetQueryContentEvent may cause flushing pending layout and it // may cause focus change or something. - nsRefPtr kungFuDeathGrip(this); + nsRefPtr kungFuDeathGrip(this); DispatchEvent(charAtPt); if (!mWidget || mWidget->Destroyed()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "mWidget was destroyed during NS_QUERY_CHARACTER_AT_POINT", this)); return E_FAIL; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetACPFromPoint(), charAtPt={ " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint(), charAtPt={ " "mSucceeded=%s, mReply={ mOffset=%u, mTentativeCaretOffset=%u }}", this, GetBoolName(charAtPt.mSucceeded), charAtPt.mReply.mOffset, charAtPt.mReply.mTentativeCaretOffset)); if (NS_WARN_IF(!charAtPt.mSucceeded)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "NS_QUERY_CHARACTER_AT_POINT failure", this)); return E_FAIL; } @@ -3284,7 +3288,7 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, if (!(dwFlags & GXFPF_NEAREST) && charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to the " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to the " "point contained by no bounding box", this)); return TS_E_INVALIDPOINT; } @@ -3322,7 +3326,7 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to " "LockedContent() failure", this)); return E_FAIL; } @@ -3335,27 +3339,27 @@ nsTextStore::GetACPFromPoint(TsViewCookie vcView, if (NS_WARN_IF(offset > LONG_MAX)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() FAILED due to out of " + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() FAILED due to out of " "range of the result", this)); return TS_E_INVALIDPOINT; } *pacp = static_cast(offset); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetACPFromPoint() succeeded: *pacp=%d", + ("TSF: 0x%p TSFTextStore::GetACPFromPoint() succeeded: *pacp=%d", this, *pacp)); return S_OK; } STDMETHODIMP -nsTextStore::GetTextExt(TsViewCookie vcView, - LONG acpStart, - LONG acpEnd, - RECT *prc, - BOOL *pfClipped) +TSFTextStore::GetTextExt(TsViewCookie vcView, + LONG acpStart, + LONG acpEnd, + RECT* prc, + BOOL* pfClipped) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetTextExt(vcView=%ld, " + ("TSF: 0x%p TSFTextStore::GetTextExt(vcView=%ld, " "acpStart=%ld, acpEnd=%ld, prc=0x%p, pfClipped=0x%p), " "mDeferNotifyingTSF=%s", this, vcView, acpStart, acpEnd, prc, pfClipped, @@ -3363,28 +3367,28 @@ nsTextStore::GetTextExt(TsViewCookie vcView, if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } if (vcView != TEXTSTORE_DEFAULT_VIEW) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "called with invalid view", this)); return E_INVALIDARG; } if (!prc || !pfClipped) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "null argument", this)); return E_INVALIDARG; } if (acpStart < 0 || acpEnd < acpStart) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "invalid position", this)); return TS_E_INVALIDPOS; } @@ -3411,7 +3415,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, kSink->IsGoogleJapaneseInputActive()) { acpEnd = acpStart; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetTextExt() hacked the offsets of " + ("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets of " "the first character of changing range of the composition " "string for TIP acpStart=%d, acpEnd=%d", this, acpStart, acpEnd)); @@ -3427,7 +3431,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, kSink->IsGoogleJapaneseInputActive()) { acpEnd = acpStart = mLockedContent.MinOffsetOfLayoutChanged(); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetTextExt() hacked the offsets of " + ("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets of " "the caret of the composition string for TIP acpStart=%d, " "acpEnd=%d", this, acpStart, acpEnd)); } @@ -3443,14 +3447,14 @@ nsTextStore::GetTextExt(TsViewCookie vcView, acpEnd = mComposition.mStart; acpStart = std::min(acpStart, acpEnd); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetTextExt() hacked the offsets for " + ("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets for " "TIP acpStart=%d, acpEnd=%d", this, acpStart, acpEnd)); } } if (mLockedContent.IsLayoutChangedAfter(acpEnd)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "layout not recomputed at %d", this, acpEnd)); mPendingOnLayoutChange = true; return TS_E_NOLAYOUT; @@ -3463,7 +3467,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, DispatchEvent(event); if (!event.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "NS_QUERY_TEXT_RECT failure", this)); return TS_E_INVALIDPOS; // but unexpected failure, maybe. } @@ -3480,7 +3484,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, refWindow = refWindow->GetTopLevelWindow(false); if (!refWindow) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "no top level window", this)); return E_FAIL; } @@ -3490,7 +3494,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, // get bounding screen rect to test for clipping if (!GetScreenExtInternal(*prc)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " "GetScreenExtInternal() failure", this)); return E_FAIL; } @@ -3521,7 +3525,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView, } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetTextExt() succeeded: " + ("TSF: 0x%p TSFTextStore::GetTextExt() succeeded: " "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }, *pfClipped=%s", this, prc->left, prc->top, prc->right, prc->bottom, GetBoolName(*pfClipped))); @@ -3530,46 +3534,46 @@ nsTextStore::GetTextExt(TsViewCookie vcView, } STDMETHODIMP -nsTextStore::GetScreenExt(TsViewCookie vcView, - RECT *prc) +TSFTextStore::GetScreenExt(TsViewCookie vcView, + RECT* prc) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetScreenExt(vcView=%ld, prc=0x%p)", + ("TSF: 0x%p TSFTextStore::GetScreenExt(vcView=%ld, prc=0x%p)", this, vcView, prc)); if (vcView != TEXTSTORE_DEFAULT_VIEW) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExt() FAILED due to " "called with invalid view", this)); return E_INVALIDARG; } if (!prc) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExt() FAILED due to " "null argument", this)); return E_INVALIDARG; } if (!GetScreenExtInternal(*prc)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExt() FAILED due to " "GetScreenExtInternal() failure", this)); return E_FAIL; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetScreenExt() succeeded: " + ("TSF: 0x%p TSFTextStore::GetScreenExt() succeeded: " "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }", this, prc->left, prc->top, prc->right, prc->bottom)); return S_OK; } bool -nsTextStore::GetScreenExtInternal(RECT &aScreenExt) +TSFTextStore::GetScreenExtInternal(RECT& aScreenExt) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal()", this)); + ("TSF: 0x%p TSFTextStore::GetScreenExtInternal()", this)); // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates WidgetQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWidget); @@ -3577,7 +3581,7 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) DispatchEvent(event); if (!event.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExtInternal() FAILED due to " "NS_QUERY_EDITOR_RECT failure", this)); return false; } @@ -3589,7 +3593,7 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) refWindow = refWindow->GetTopLevelWindow(false); if (!refWindow) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExtInternal() FAILED due to " "no top level window", this)); return false; } @@ -3597,7 +3601,7 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) nsIntRect boundRect; if (NS_FAILED(refWindow->GetClientBounds(boundRect))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExtInternal() FAILED due to " "failed to get the client bounds", this)); return false; } @@ -3615,7 +3619,7 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() succeeded: " + ("TSF: 0x%p TSFTextStore::GetScreenExtInternal() succeeded: " "aScreenExt={ left=%ld, top=%ld, right=%ld, bottom=%ld }", this, aScreenExt.left, aScreenExt.top, aScreenExt.right, aScreenExt.bottom)); @@ -3623,24 +3627,24 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) } STDMETHODIMP -nsTextStore::GetWnd(TsViewCookie vcView, - HWND *phwnd) +TSFTextStore::GetWnd(TsViewCookie vcView, + HWND* phwnd) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), " + ("TSF: 0x%p TSFTextStore::GetWnd(vcView=%ld, phwnd=0x%p), " "mWidget=0x%p", this, vcView, phwnd, mWidget.get())); if (vcView != TEXTSTORE_DEFAULT_VIEW) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetWnd() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetWnd() FAILED due to " "called with invalid view", this)); return E_INVALIDARG; } if (!phwnd) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::GetScreenExt() FAILED due to " + ("TSF: 0x%p TSFTextStore::GetScreenExt() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3648,21 +3652,21 @@ nsTextStore::GetWnd(TsViewCookie vcView, *phwnd = mWidget->GetWindowHandle(); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::GetWnd() succeeded: *phwnd=0x%p", + ("TSF: 0x%p TSFTextStore::GetWnd() succeeded: *phwnd=0x%p", this, static_cast(*phwnd))); return S_OK; } STDMETHODIMP -nsTextStore::InsertTextAtSelection(DWORD dwFlags, - const WCHAR *pchText, - ULONG cch, - LONG *pacpStart, - LONG *pacpEnd, - TS_TEXTCHANGE *pChange) +TSFTextStore::InsertTextAtSelection(DWORD dwFlags, + const WCHAR* pchText, + ULONG cch, + LONG* pacpStart, + LONG* pacpEnd, + TS_TEXTCHANGE* pChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection(dwFlags=%s, " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection(dwFlags=%s, " "pchText=0x%p \"%s\", cch=%lu, pacpStart=0x%p, pacpEnd=0x%p, " "pChange=0x%p), IsComposing()=%s", this, dwFlags == 0 ? "0" : @@ -3675,7 +3679,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, if (cch && !pchText) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "null pchText", this)); return E_INVALIDARG; } @@ -3683,14 +3687,14 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, if (TS_IAS_QUERYONLY == dwFlags) { if (!IsReadLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "not locked (read)", this)); return TS_E_NOLOCK; } if (!pacpStart || !pacpEnd) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3699,7 +3703,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "CurrentSelection() failure", this)); return E_FAIL; } @@ -3715,21 +3719,21 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, } else { if (!IsReadWriteLocked()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "not locked (read-write)", this)); return TS_E_NOLOCK; } if (!pChange) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "null pChange", this)); return E_INVALIDARG; } if (TS_IAS_NOQUERY != dwFlags && (!pacpStart || !pacpEnd)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "null argument", this)); return E_INVALIDARG; } @@ -3737,7 +3741,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), pChange)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() FAILED due to " "InsertTextAtSelectionInternal() failure", this)); return E_FAIL; } @@ -3748,7 +3752,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, } } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::InsertTextAtSelection() succeeded: " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelection() succeeded: " "*pacpStart=%ld, *pacpEnd=%ld, " "*pChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld })", this, pacpStart ? *pacpStart : 0, pacpEnd ? *pacpEnd : 0, @@ -3758,11 +3762,11 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, } bool -nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, - TS_TEXTCHANGE* aTextChange) +TSFTextStore::InsertTextAtSelectionInternal(const nsAString& aInsertStr, + TS_TEXTCHANGE* aTextChange) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal(" + ("TSF: 0x%p TSFTextStore::InsertTextAtSelectionInternal(" "aInsertStr=\"%s\", aTextChange=0x%p), IsComposing=%s", this, NS_ConvertUTF16toUTF8(aInsertStr).get(), aTextChange, GetBoolName(mComposition.IsComposing()))); @@ -3770,7 +3774,7 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() failed " + ("TSF: 0x%p TSFTextStore::InsertTextAtSelectionInternal() failed " "due to LockedContent() failure()", this)); return false; } @@ -3798,9 +3802,9 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: " - "mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ acpStart=%ld, " - "acpOldEnd=%ld, acpNewEnd=%ld }", + ("TSF: 0x%p TSFTextStore::InsertTextAtSelectionInternal() " + "succeeded: mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ " + "acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }", this, mWidget.get(), GetBoolName(mWidget ? mWidget->Destroyed() : true), aTextChange ? aTextChange->acpStart : 0, @@ -3810,14 +3814,14 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, } STDMETHODIMP -nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, - IDataObject *pDataObject, - LONG *pacpStart, - LONG *pacpEnd, - TS_TEXTCHANGE *pChange) +TSFTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, + IDataObject* pDataObject, + LONG* pacpStart, + LONG* pacpEnd, + TS_TEXTCHANGE* pChange) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::InsertEmbeddedAtSelection() called " + ("TSF: 0x%p TSFTextStore::InsertEmbeddedAtSelection() called " "but not supported (E_NOTIMPL)", this)); // embedded objects are not supported @@ -3825,12 +3829,12 @@ nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags, } HRESULT -nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, - ITfRange* aRange, - bool aPreserveSelection) +TSFTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, + ITfRange* aRange, + bool aPreserveSelection) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction(" + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction(" "aComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), " "mComposition.mView=0x%p", this, aComposition, aRange, GetBoolName(aPreserveSelection), @@ -3840,7 +3844,7 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, HRESULT hr = GetRangeExtent(aRange, &start, &length); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction() FAILED " "due to GetRangeExtent() failure", this)); return hr; } @@ -3850,13 +3854,13 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, } HRESULT -nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, - LONG aStart, - LONG aLength, - bool aPreserveSelection) +TSFTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, + LONG aStart, + LONG aLength, + bool aPreserveSelection) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction(" + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction(" "aComposition=0x%p, aStart=%d, aLength=%d, aPreserveSelection=%s), " "mComposition.mView=0x%p", this, aComposition, aStart, aLength, GetBoolName(aPreserveSelection), @@ -3865,7 +3869,7 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction() FAILED " "due to LockedContent() failure", this)); return E_FAIL; } @@ -3879,7 +3883,7 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() FAILED " + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction() FAILED " "due to CurrentSelection() failure", this)); action->mAdjustSelection = true; } else if (currentSel.MinOffset() != aStart || @@ -3898,7 +3902,7 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, lockedContent.StartComposition(aComposition, *action, aPreserveSelection); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RecordCompositionStartAction() succeeded: " + ("TSF: 0x%p TSFTextStore::RecordCompositionStartAction() succeeded: " "mComposition={ mStart=%ld, mString.Length()=%ld, " "mSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, " "style.fInterimChar=%s } }", @@ -3910,10 +3914,10 @@ nsTextStore::RecordCompositionStartAction(ITfCompositionView* aComposition, } HRESULT -nsTextStore::RecordCompositionEndAction() +TSFTextStore::RecordCompositionEndAction() { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::RecordCompositionEndAction(), " + ("TSF: 0x%p TSFTextStore::RecordCompositionEndAction(), " "mComposition={ mView=0x%p, mString=\"%s\" }", this, mComposition.mView.get(), NS_ConvertUTF16toUTF8(mComposition.mString).get())); @@ -3928,24 +3932,24 @@ nsTextStore::RecordCompositionEndAction() Content& lockedContent = LockedContent(); if (!lockedContent.IsInitialized()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::RecordCompositionEndAction() FAILED due " + ("TSF: 0x%p TSFTextStore::RecordCompositionEndAction() FAILED due " "to LockedContent() failure", this)); return E_FAIL; } lockedContent.EndComposition(*action); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::RecordCompositionEndAction(), succeeded", + ("TSF: 0x%p TSFTextStore::RecordCompositionEndAction(), succeeded", this)); return S_OK; } STDMETHODIMP -nsTextStore::OnStartComposition(ITfCompositionView* pComposition, - BOOL* pfOk) +TSFTextStore::OnStartComposition(ITfCompositionView* pComposition, + BOOL* pfOk) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, " + ("TSF: 0x%p TSFTextStore::OnStartComposition(pComposition=0x%p, " "pfOk=0x%p), mComposition.mView=0x%p", this, pComposition, pfOk, mComposition.mView.get())); @@ -3956,7 +3960,7 @@ nsTextStore::OnStartComposition(ITfCompositionView* pComposition, // Only one composition at a time if (mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnStartComposition() FAILED due to " "there is another composition already (but returns S_OK)", this)); return S_OK; } @@ -3965,30 +3969,30 @@ nsTextStore::OnStartComposition(ITfCompositionView* pComposition, HRESULT hr = pComposition->GetRange(getter_AddRefs(range)); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnStartComposition() FAILED due to " "pComposition->GetRange() failure", this)); return hr; } hr = RecordCompositionStartAction(pComposition, range, false); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnStartComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnStartComposition() FAILED due to " "RecordCompositionStartAction() failure", this)); return hr; } *pfOk = TRUE; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnStartComposition() succeeded", this)); + ("TSF: 0x%p TSFTextStore::OnStartComposition() succeeded", this)); return S_OK; } STDMETHODIMP -nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, - ITfRange* pRangeNew) +TSFTextStore::OnUpdateComposition(ITfCompositionView* pComposition, + ITfRange* pRangeNew) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition(pComposition=0x%p, " "pRangeNew=0x%p), mComposition.mView=0x%p", this, pComposition, pRangeNew, mComposition.mView.get())); @@ -3996,19 +4000,19 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, if (!mDocumentMgr || !mContext) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "not ready for the composition", this)); return E_UNEXPECTED; } if (!mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "no active composition", this)); return E_UNEXPECTED; } if (mComposition.mView != pComposition) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "different composition view specified", this)); return E_UNEXPECTED; } @@ -4018,7 +4022,7 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, PendingAction* action = LastOrNewPendingCompositionUpdate(); action->mIncomplete = true; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded but " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() succeeded but " "not complete", this)); return S_OK; } @@ -4026,7 +4030,7 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, HRESULT hr = RestartCompositionIfNecessary(pRangeNew); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "RestartCompositionIfNecessary() failure", this)); return hr; } @@ -4034,7 +4038,7 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, hr = RecordCompositionUpdateAction(); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "RecordCompositionUpdateAction() failure", this)); return hr; } @@ -4043,12 +4047,12 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() FAILED due to " "CurrentSelection() failure", this)); return E_FAIL; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnUpdateComposition() succeeded: " + ("TSF: 0x%p TSFTextStore::OnUpdateComposition() succeeded: " "mComposition={ mStart=%ld, mString=\"%s\" }, " "CurrentSelection()={ acpStart=%ld, acpEnd=%ld, style.ase=%s }", this, mComposition.mStart, @@ -4060,10 +4064,10 @@ nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition, } STDMETHODIMP -nsTextStore::OnEndComposition(ITfCompositionView* pComposition) +TSFTextStore::OnEndComposition(ITfCompositionView* pComposition) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), " + ("TSF: 0x%p TSFTextStore::OnEndComposition(pComposition=0x%p), " "mComposition={ mView=0x%p, mString=\"%s\" }", this, pComposition, mComposition.mView.get(), NS_ConvertUTF16toUTF8(mComposition.mString).get())); @@ -4072,14 +4076,14 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) if (!mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnEndComposition() FAILED due to " "no active composition", this)); return E_UNEXPECTED; } if (mComposition.mView != pComposition) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnEndComposition() FAILED due to " "different composition view specified", this)); return E_UNEXPECTED; } @@ -4087,28 +4091,28 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) HRESULT hr = RecordCompositionEndAction(); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::OnEndComposition() FAILED due to " + ("TSF: 0x%p TSFTextStore::OnEndComposition() FAILED due to " "RecordCompositionEndAction() failure", this)); return hr; } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnEndComposition(), succeeded", this)); + ("TSF: 0x%p TSFTextStore::OnEndComposition(), succeeded", this)); return S_OK; } STDMETHODIMP -nsTextStore::AdviseMouseSink(ITfRangeACP* range, - ITfMouseSink* pSink, - DWORD* pdwCookie) +TSFTextStore::AdviseMouseSink(ITfRangeACP* range, + ITfMouseSink* pSink, + DWORD* pdwCookie) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::AdviseMouseSink(range=0x%p, pSink=0x%p, " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink(range=0x%p, pSink=0x%p, " "pdwCookie=0x%p)", this, range, pSink, pdwCookie)); if (!pdwCookie) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseMouseSink() FAILED due to the " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink() FAILED due to the " "pdwCookie is null", this)); return E_INVALIDARG; } @@ -4117,13 +4121,13 @@ nsTextStore::AdviseMouseSink(ITfRangeACP* range, if (!range) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseMouseSink() FAILED due to the " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink() FAILED due to the " "range is null", this)); return E_INVALIDARG; } if (!pSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseMouseSink() FAILED due to the " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink() FAILED due to the " "pSink is null", this)); return E_INVALIDARG; } @@ -4143,7 +4147,7 @@ nsTextStore::AdviseMouseSink(ITfRangeACP* range, HRESULT hr = tracker->Init(this); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseMouseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink() FAILED due to " "failure of MouseTracker::Init()", this)); return hr; } @@ -4151,26 +4155,26 @@ nsTextStore::AdviseMouseSink(ITfRangeACP* range, HRESULT hr = tracker->AdviseSink(this, range, pSink); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::AdviseMouseSink() FAILED due to failure " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink() FAILED due to failure " "of MouseTracker::Init()", this)); return hr; } *pdwCookie = tracker->Cookie(); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::AdviseMouseSink(), succeeded, " + ("TSF: 0x%p TSFTextStore::AdviseMouseSink(), succeeded, " "*pdwCookie=%d", this, *pdwCookie)); return S_OK; } STDMETHODIMP -nsTextStore::UnadviseMouseSink(DWORD dwCookie) +TSFTextStore::UnadviseMouseSink(DWORD dwCookie) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::UnadviseMouseSink(dwCookie=%d)", + ("TSF: 0x%p TSFTextStore::UnadviseMouseSink(dwCookie=%d)", this, dwCookie)); if (dwCookie == MouseTracker::kInvalidCookie) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseMouseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::UnadviseMouseSink() FAILED due to " "the cookie is invalid value", this)); return E_INVALIDARG; } @@ -4178,31 +4182,31 @@ nsTextStore::UnadviseMouseSink(DWORD dwCookie) // We can use this shortcut for now. if (static_cast(dwCookie) >= mMouseTrackers.Length()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseMouseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::UnadviseMouseSink() FAILED due to " "the cookie is too large value", this)); return E_INVALIDARG; } MouseTracker& tracker = mMouseTrackers[dwCookie]; if (!tracker.IsUsing()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::UnadviseMouseSink() FAILED due to " + ("TSF: 0x%p TSFTextStore::UnadviseMouseSink() FAILED due to " "the found tracker uninstalled already", this)); return E_INVALIDARG; } tracker.UnadviseSink(); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::UnadviseMouseSink(), succeeded", this)); + ("TSF: 0x%p TSFTextStore::UnadviseMouseSink(), succeeded", this)); return S_OK; } // static nsresult -nsTextStore::OnFocusChange(bool aGotFocus, - nsWindowBase* aFocusedWidget, - const InputContext& aContext) +TSFTextStore::OnFocusChange(bool aGotFocus, + nsWindowBase* aFocusedWidget, + const InputContext& aContext) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, " + ("TSF: TSFTextStore::OnFocusChange(aGotFocus=%s, " "aFocusedWidget=0x%p, aContext={ mIMEState={ mEnabled=%s }, " "mHTMLInputType=\"%s\" }), " "sThreadMgr=0x%p, sEnabledTextStore=0x%p", @@ -4241,7 +4245,7 @@ nsTextStore::OnFocusChange(bool aGotFocus, HRESULT hr = sThreadMgr->SetFocus(sDisabledDocumentMgr); if (NS_WARN_IF(FAILED(hr))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::OnFocusChange() FAILED due to " + ("TSF: TSFTextStore::OnFocusChange() FAILED due to " "ITfThreadMgr::SetFocus() failure")); return NS_ERROR_FAILURE; } @@ -4251,7 +4255,7 @@ nsTextStore::OnFocusChange(bool aGotFocus, // If an editor is getting focus, create new TextStore and set focus. if (NS_WARN_IF(!CreateAndSetFocus(aFocusedWidget, aContext))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::OnFocusChange() FAILED due to " + ("TSF: TSFTextStore::OnFocusChange() FAILED due to " "ITfThreadMgr::CreateAndSetFocus() failure")); // If setting focus, we should destroy the TextStore completely because // it causes memory leak. @@ -4266,23 +4270,23 @@ nsTextStore::OnFocusChange(bool aGotFocus, // static bool -nsTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, - const InputContext& aContext) +TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, + const InputContext& aContext) { // TSF might do something which causes that we need to access static methods - // of nsTextStore. At that time, sEnabledTextStore may be necessary. + // of TSFTextStore. At that time, sEnabledTextStore may be necessary. // So, we should set sEnabledTextStore directly. - sEnabledTextStore = new nsTextStore(); + sEnabledTextStore = new TSFTextStore(); if (NS_WARN_IF(!sEnabledTextStore->Init(aFocusedWidget))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CreateAndSetFocus() FAILED due to " - "nsTextStore::Init() failure")); + ("TSF: TSFTextStore::CreateAndSetFocus() FAILED due to " + "TSFTextStore::Init() failure")); return false; } if (NS_WARN_IF(!sEnabledTextStore->mDocumentMgr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CreateAndSetFocus() FAILED due to " - "invalid nsTextStore::mDocumentMgr")); + ("TSF: TSFTextStore::CreateAndSetFocus() FAILED due to " + "invalid TSFTextStore::mDocumentMgr")); return false; } if (aContext.mIMEState.mEnabled == IMEState::PASSWORD) { @@ -4296,7 +4300,7 @@ nsTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, HRESULT hr = sThreadMgr->SetFocus(sEnabledTextStore->mDocumentMgr); if (NS_WARN_IF(FAILED(hr))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CreateAndSetFocus() FAILED due to " + ("TSF: TSFTextStore::CreateAndSetFocus() FAILED due to " "ITfTheadMgr::SetFocus() failure")); return false; } @@ -4308,7 +4312,7 @@ nsTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, getter_AddRefs(prevFocusedDocumentMgr)); if (NS_WARN_IF(FAILED(hr))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CreateAndSetFocus() FAILED due to " + ("TSF: TSFTextStore::CreateAndSetFocus() FAILED due to " "ITfTheadMgr::AssociateFocus() failure")); return false; } @@ -4316,7 +4320,7 @@ nsTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, if (sEnabledTextStore->mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: nsTextStore::CreateAndSetFocus(), calling " + ("TSF: TSFTextStore::CreateAndSetFocus(), calling " "ITextStoreACPSink::OnLayoutChange(TS_LC_CREATE) for 0x%p...", sEnabledTextStore.get())); sEnabledTextStore->mSink->OnLayoutChange(TS_LC_CREATE, @@ -4327,7 +4331,7 @@ nsTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget, // static nsIMEUpdatePreference -nsTextStore::GetIMEUpdatePreference() +TSFTextStore::GetIMEUpdatePreference() { if (sThreadMgr && sEnabledTextStore && sEnabledTextStore->mDocumentMgr) { nsRefPtr docMgr; @@ -4339,7 +4343,7 @@ nsTextStore::GetIMEUpdatePreference() nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE | nsIMEUpdatePreference::NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR | nsIMEUpdatePreference::NOTIFY_DURING_DEACTIVE); - // nsTextStore shouldn't notify TSF of selection change and text change + // TSFTextStore shouldn't notify TSF of selection change and text change // which are caused by composition. updatePreference.DontNotifyChangesCausedByComposition(); return updatePreference; @@ -4349,10 +4353,10 @@ nsTextStore::GetIMEUpdatePreference() } nsresult -nsTextStore::OnTextChangeInternal(const IMENotification& aIMENotification) +TSFTextStore::OnTextChangeInternal(const IMENotification& aIMENotification) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::OnTextChangeInternal(aIMENotification={ " + ("TSF: 0x%p TSFTextStore::OnTextChangeInternal(aIMENotification={ " "mMessage=0x%08X, mTextChangeData={ mStartOffset=%lu, " "mRemovedEndOffset=%lu, mAddedEndOffset=%lu}), mSink=0x%p, " "mSinkMask=%s, mComposition.IsComposing()=%s", @@ -4389,7 +4393,7 @@ nsTextStore::OnTextChangeInternal(const IMENotification& aIMENotification) NotifyTSFOfTextChange(textChange); } else { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::NotifyTSFOfTextChange() FAILED due to " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfTextChange() FAILED due to " "offset is too big for calling " "ITextStoreACPSink::OnTextChange()...", this)); @@ -4401,7 +4405,7 @@ nsTextStore::OnTextChangeInternal(const IMENotification& aIMENotification) } void -nsTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) +TSFTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) { // XXX We need to cache the text change ranges and notify TSF of that // the document is unlocked. @@ -4414,7 +4418,7 @@ nsTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) // For preventing it, let's commit the composition. if (mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfTextChange(), " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfTextChange(), " "committing the composition for avoiding making TIP confused...", this)); CommitCompositionInternal(false); @@ -4422,7 +4426,7 @@ nsTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfTextChange(), calling " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfTextChange(), calling " "ITextStoreACPSink::OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " "acpNewEnd=%ld })...", this, aTextChange.acpStart, aTextChange.acpOldEnd, aTextChange.acpNewEnd)); @@ -4430,12 +4434,12 @@ nsTextStore::NotifyTSFOfTextChange(const TS_TEXTCHANGE& aTextChange) } nsresult -nsTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification) +TSFTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification) { const IMENotification::SelectionChangeData& selectionChangeData = aIMENotification.mSelectionChangeData; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(" + ("TSF: 0x%p TSFTextStore::OnSelectionChangeInternal(" "aIMENotification={ mSelectionChangeData={ mOffset=%lu, " "Length()=%lu, mReversed=%s, mWritingMode=%s, " "mCausedByComposition=%s, mCausedBySelectionEvent=%s } }), " @@ -4469,7 +4473,7 @@ nsTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification) mPendingOnSelectionChange = true; if (mIsRecordingActionsWithoutLock) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), putting " + ("TSF: 0x%p TSFTextStore::OnSelectionChangeInternal(), putting " "off notifying TSF of selection change...", this)); return NS_OK; } @@ -4488,7 +4492,7 @@ nsTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification) } void -nsTextStore::NotifyTSFOfSelectionChange() +TSFTextStore::NotifyTSFOfSelectionChange() { if (NS_WARN_IF(IsReadLocked())) { return; @@ -4505,7 +4509,7 @@ nsTextStore::NotifyTSFOfSelectionChange() // For preventing it, let's commit the composition. if (mComposition.IsComposing()) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfSelectionChange(), " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfSelectionChange(), " "committing the composition for avoiding making TIP confused...", this)); CommitCompositionInternal(false); @@ -4513,13 +4517,13 @@ nsTextStore::NotifyTSFOfSelectionChange() } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfSelectionChange(), calling " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfSelectionChange(), calling " "ITextStoreACPSink::OnSelectionChange()...", this)); mSink->OnSelectionChange(); } nsresult -nsTextStore::OnLayoutChangeInternal() +TSFTextStore::OnLayoutChangeInternal() { NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE); @@ -4532,14 +4536,14 @@ nsTextStore::OnLayoutChangeInternal() // So, don't use MaybeFlushPendingNotifications() for flushing pending // layout change. MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::OnLayoutChangeInternal(), calling " + ("TSF: 0x%p TSFTextStore::OnLayoutChangeInternal(), calling " "NotifyTSFOfLayoutChange()...", this)); if (NS_WARN_IF(!NotifyTSFOfLayoutChange(mPendingOnLayoutChange))) { rv = NS_ERROR_FAILURE; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::OnLayoutChangeInternal(), calling " + ("TSF: 0x%p TSFTextStore::OnLayoutChangeInternal(), calling " "MaybeFlushPendingNotifications()...", this)); MaybeFlushPendingNotifications(); @@ -4547,7 +4551,7 @@ nsTextStore::OnLayoutChangeInternal() } bool -nsTextStore::NotifyTSFOfLayoutChange(bool aFlush) +TSFTextStore::NotifyTSFOfLayoutChange(bool aFlush) { mPendingOnLayoutChange = false; @@ -4556,7 +4560,7 @@ nsTextStore::NotifyTSFOfLayoutChange(bool aFlush) if (mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfLayoutChange(), " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), " "calling ITextStoreACPSink::OnLayoutChange()...", this)); HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW); @@ -4571,7 +4575,7 @@ nsTextStore::NotifyTSFOfLayoutChange(bool aFlush) getter_AddRefs(service)); if (service) { MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::NotifyTSFOfLayoutChange(), " + ("TSF: 0x%p TSFTextStore::NotifyTSFOfLayoutChange(), " "calling ITfContextOwnerServices::OnLayoutChange()...", this)); HRESULT hr = service->OnLayoutChange(); @@ -4583,10 +4587,10 @@ nsTextStore::NotifyTSFOfLayoutChange(bool aFlush) } nsresult -nsTextStore::OnUpdateCompositionInternal() +TSFTextStore::OnUpdateCompositionInternal() { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::OnUpdateCompositionInternal(), " + ("TSF: 0x%p TSFTextStore::OnUpdateCompositionInternal(), " "mDeferNotifyingTSF=%s", this, GetBoolName(mDeferNotifyingTSF))); @@ -4597,14 +4601,15 @@ nsTextStore::OnUpdateCompositionInternal() } nsresult -nsTextStore::OnMouseButtonEventInternal(const IMENotification& aIMENotification) +TSFTextStore::OnMouseButtonEventInternal( + const IMENotification& aIMENotification) { if (mMouseTrackers.IsEmpty()) { return NS_OK; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::OnMouseButtonEventInternal(" + ("TSF: 0x%p TSFTextStore::OnMouseButtonEventInternal(" "aIMENotification={ mEventMessage=%s, mOffset=%u, mCursorPos={ " "mX=%d, mY=%d }, mCharRect={ mX=%d, mY=%d, mWidth=%d, mHeight=%d }, " "mButton=%s, mButtons=%s, mModifiers=%s })", @@ -4671,17 +4676,17 @@ nsTextStore::OnMouseButtonEventInternal(const IMENotification& aIMENotification) } void -nsTextStore::CreateNativeCaret() +TSFTextStore::CreateNativeCaret() { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::CreateNativeCaret(), " + ("TSF: 0x%p TSFTextStore::CreateNativeCaret(), " "mComposition.IsComposing()=%s", this, GetBoolName(mComposition.IsComposing()))); Selection& currentSel = CurrentSelection(); if (currentSel.IsDirty()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " + ("TSF: 0x%p TSFTextStore::CreateNativeCaret() FAILED due to " "CurrentSelection() failure", this)); return; } @@ -4696,7 +4701,7 @@ nsTextStore::CreateNativeCaret() DispatchEvent(queryCaretRect); if (!queryCaretRect.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " + ("TSF: 0x%p TSFTextStore::CreateNativeCaret() FAILED due to " "NS_QUERY_CARET_RECT failure (offset=%d)", this, caretOffset)); return; } @@ -4706,7 +4711,7 @@ nsTextStore::CreateNativeCaret() caretRect.width, caretRect.height); if (!mNativeCaretIsCreated) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " + ("TSF: 0x%p TSFTextStore::CreateNativeCaret() FAILED due to " "CreateCaret() failure", this)); return; } @@ -4715,7 +4720,7 @@ nsTextStore::CreateNativeCaret() nsWindow* toplevelWindow = window->GetTopLevelWindow(false); if (!toplevelWindow) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::CreateNativeCaret() FAILED due to " + ("TSF: 0x%p TSFTextStore::CreateNativeCaret() FAILED due to " "no top level window", this)); return; } @@ -4729,10 +4734,10 @@ nsTextStore::CreateNativeCaret() } void -nsTextStore::CommitCompositionInternal(bool aDiscard) +TSFTextStore::CommitCompositionInternal(bool aDiscard) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), " + ("TSF: 0x%p TSFTextStore::CommitCompositionInternal(aDiscard=%s), " "mSink=0x%p, mContext=0x%p, mComposition.mView=0x%p, " "mComposition.mString=\"%s\"", this, GetBoolName(aDiscard), mSink.get(), mContext.get(), @@ -4748,7 +4753,7 @@ nsTextStore::CommitCompositionInternal(bool aDiscard) textChange.acpOldEnd = endOffset; textChange.acpNewEnd = mComposition.mStart; MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), calling" + ("TSF: 0x%p TSFTextStore::CommitCompositionInternal(), calling" "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, " "acpNewEnd=%ld })...", this, textChange.acpStart, textChange.acpOldEnd, textChange.acpNewEnd)); @@ -4765,7 +4770,7 @@ nsTextStore::CommitCompositionInternal(bool aDiscard) getter_AddRefs(services)); if (services) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::CommitCompositionInternal(), " + ("TSF: 0x%p TSFTextStore::CommitCompositionInternal(), " "requesting TerminateComposition() for the context 0x%p...", this, context.get())); services->TerminateComposition(nullptr); @@ -4796,17 +4801,18 @@ GetCompartment(IUnknown* pUnk, // static void -nsTextStore::SetIMEOpenState(bool aState) +TSFTextStore::SetIMEOpenState(bool aState) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::SetIMEOpenState(aState=%s)", GetBoolName(aState))); + ("TSF: TSFTextStore::SetIMEOpenState(aState=%s)", + GetBoolName(aState))); nsRefPtr comp; if (!GetCompartment(sThreadMgr, GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, getter_AddRefs(comp))) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::SetIMEOpenState() FAILED due to" + ("TSF: TSFTextStore::SetIMEOpenState() FAILED due to" "no compartment available")); return; } @@ -4815,7 +4821,7 @@ nsTextStore::SetIMEOpenState(bool aState) variant.vt = VT_I4; variant.lVal = aState; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::SetIMEOpenState(), setting " + ("TSF: TSFTextStore::SetIMEOpenState(), setting " "0x%04X to GUID_COMPARTMENT_KEYBOARD_OPENCLOSE...", variant.lVal)); comp->SetValue(sClientId, &variant); @@ -4823,7 +4829,7 @@ nsTextStore::SetIMEOpenState(bool aState) // static bool -nsTextStore::GetIMEOpenState(void) +TSFTextStore::GetIMEOpenState() { nsRefPtr comp; if (!GetCompartment(sThreadMgr, @@ -4842,12 +4848,12 @@ nsTextStore::GetIMEOpenState(void) // static void -nsTextStore::SetInputContext(nsWindowBase* aWidget, +TSFTextStore::SetInputContext(nsWindowBase* aWidget, const InputContext& aContext, const InputContextAction& aAction) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::SetInputContext(aWidget=%p, " + ("TSF: TSFTextStore::SetInputContext(aWidget=%p, " "aContext.mIMEState.mEnabled=%s, aAction.mFocusChange=%s), " "sEnabledTextStore=0x%p, ThinksHavingFocus()=%s", aWidget, GetIMEEnabledName(aContext.mIMEState.mEnabled), @@ -4874,7 +4880,7 @@ nsTextStore::SetInputContext(nsWindowBase* aWidget, // static void -nsTextStore::MarkContextAsKeyboardDisabled(ITfContext* aContext) +TSFTextStore::MarkContextAsKeyboardDisabled(ITfContext* aContext) { VARIANT variant_int4_value1; variant_int4_value1.vt = VT_I4; @@ -4885,13 +4891,13 @@ nsTextStore::MarkContextAsKeyboardDisabled(ITfContext* aContext) GUID_COMPARTMENT_KEYBOARD_DISABLED, getter_AddRefs(comp))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::MarkContextAsKeyboardDisabled() failed" + ("TSF: TSFTextStore::MarkContextAsKeyboardDisabled() failed" "aContext=0x%p...", aContext)); return; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::MarkContextAsKeyboardDisabled(), setting " + ("TSF: TSFTextStore::MarkContextAsKeyboardDisabled(), setting " "to disable context 0x%p...", aContext)); comp->SetValue(sClientId, &variant_int4_value1); @@ -4899,7 +4905,7 @@ nsTextStore::MarkContextAsKeyboardDisabled(ITfContext* aContext) // static void -nsTextStore::MarkContextAsEmpty(ITfContext* aContext) +TSFTextStore::MarkContextAsEmpty(ITfContext* aContext) { VARIANT variant_int4_value1; variant_int4_value1.vt = VT_I4; @@ -4910,31 +4916,31 @@ nsTextStore::MarkContextAsEmpty(ITfContext* aContext) GUID_COMPARTMENT_EMPTYCONTEXT, getter_AddRefs(comp))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::MarkContextAsEmpty() failed" + ("TSF: TSFTextStore::MarkContextAsEmpty() failed" "aContext=0x%p...", aContext)); return; } MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: nsTextStore::MarkContextAsEmpty(), setting " + ("TSF: TSFTextStore::MarkContextAsEmpty(), setting " "to mark empty context 0x%p...", aContext)); comp->SetValue(sClientId, &variant_int4_value1); } // static void -nsTextStore::Initialize() +TSFTextStore::Initialize() { if (!sTextStoreLog) { sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets"); } MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: nsTextStore::Initialize() is called...")); + ("TSF: TSFTextStore::Initialize() is called...")); if (sThreadMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED due to already initialized")); + ("TSF: TSFTextStore::Initialize() FAILED due to already initialized")); return; } @@ -4943,7 +4949,7 @@ nsTextStore::Initialize() (IsVistaOrLater() && Preferences::GetBool(kPrefNameEnableTSF, false) && !BrowserTabsRemoteAutostart()); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: nsTextStore::Initialize(), TSF is %s", + ("TSF: TSFTextStore::Initialize(), TSF is %s", enableTsf ? "enabled" : "disabled")); if (!enableTsf) { return; @@ -4961,7 +4967,7 @@ nsTextStore::Initialize() getter_AddRefs(inputProcessorProfiles)); if (FAILED(hr) || !inputProcessorProfiles) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to create input processor " + ("TSF: TSFTextStore::Initialize() FAILED to create input processor " "profiles, hr=0x%08X", hr)); return; } @@ -4972,7 +4978,7 @@ nsTextStore::Initialize() getter_AddRefs(threadMgr)); if (FAILED(hr) || !threadMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to " + ("TSF: TSFTextStore::Initialize() FAILED to " "create the thread manager, hr=0x%08X", hr)); return; } @@ -4982,7 +4988,7 @@ nsTextStore::Initialize() getter_AddRefs(messagePump)); if (FAILED(hr) || !messagePump) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to " + ("TSF: TSFTextStore::Initialize() FAILED to " "QI message pump from the thread manager, hr=0x%08X", hr)); return; } @@ -4992,7 +4998,7 @@ nsTextStore::Initialize() getter_AddRefs(keystrokeMgr)); if (FAILED(hr) || !keystrokeMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to " + ("TSF: TSFTextStore::Initialize() FAILED to " "QI keystroke manager from the thread manager, hr=0x%08X", hr)); return; } @@ -5000,7 +5006,7 @@ nsTextStore::Initialize() hr = threadMgr->Activate(&sClientId); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to activate, hr=0x%08X", hr)); + ("TSF: TSFTextStore::Initialize() FAILED to activate, hr=0x%08X", hr)); return; } @@ -5010,7 +5016,7 @@ nsTextStore::Initialize() getter_AddRefs(displayAttributeMgr)); if (FAILED(hr) || !displayAttributeMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to create " + ("TSF: TSFTextStore::Initialize() FAILED to create " "a display attribute manager instance, hr=0x%08X", hr)); return; } @@ -5021,7 +5027,7 @@ nsTextStore::Initialize() getter_AddRefs(categoryMgr)); if (FAILED(hr) || !categoryMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to create " + ("TSF: TSFTextStore::Initialize() FAILED to create " "a category manager instance, hr=0x%08X", hr)); return; } @@ -5030,7 +5036,7 @@ nsTextStore::Initialize() hr = threadMgr->CreateDocumentMgr(getter_AddRefs(disabledDocumentMgr)); if (FAILED(hr) || !disabledDocumentMgr) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to create " + ("TSF: TSFTextStore::Initialize() FAILED to create " "a document manager for disabled mode, hr=0x%08X", hr)); return; } @@ -5042,7 +5048,7 @@ nsTextStore::Initialize() &editCookie); if (FAILED(hr) || !disabledContext) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to create " + ("TSF: TSFTextStore::Initialize() FAILED to create " "a context for disabled mode, hr=0x%08X", hr)); return; } @@ -5051,13 +5057,13 @@ nsTextStore::Initialize() MarkContextAsEmpty(disabledContext); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: nsTextStore::Initialize() is creating " + ("TSF: TSFTextStore::Initialize() is creating " "a TSFStaticSink instance...")); TSFStaticSink* staticSink = TSFStaticSink::GetInstance(); if (!staticSink->Init(threadMgr, inputProcessorProfiles)) { TSFStaticSink::Shutdown(); MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::Initialize() FAILED to initialize TSFStaticSink " + ("TSF: TSFTextStore::Initialize() FAILED to initialize TSFStaticSink " "instance")); return; } @@ -5089,7 +5095,7 @@ nsTextStore::Initialize() true); MOZ_LOG(sTextStoreLog, LogLevel::Info, - ("TSF: nsTextStore::Initialize(), sThreadMgr=0x%p, " + ("TSF: TSFTextStore::Initialize(), sThreadMgr=0x%p, " "sClientId=0x%08X, sDisplayAttrMgr=0x%p, " "sCategoryMgr=0x%p, sDisabledDocumentMgr=0x%p, sDisabledContext=%p, " "sCreateNativeCaretForATOK=%s, " @@ -5108,9 +5114,9 @@ nsTextStore::Initialize() // static void -nsTextStore::Terminate(void) +TSFTextStore::Terminate() { - MOZ_LOG(sTextStoreLog, LogLevel::Info, ("TSF: nsTextStore::Terminate()")); + MOZ_LOG(sTextStoreLog, LogLevel::Info, ("TSF: TSFTextStore::Terminate()")); TSFStaticSink::Shutdown(); @@ -5131,7 +5137,7 @@ nsTextStore::Terminate(void) // static bool -nsTextStore::ProcessRawKeyMessage(const MSG& aMsg) +TSFTextStore::ProcessRawKeyMessage(const MSG& aMsg) { if (!sKeystrokeMgr) { return false; // not in TSF mode @@ -5160,9 +5166,11 @@ nsTextStore::ProcessRawKeyMessage(const MSG& aMsg) // static void -nsTextStore::ProcessMessage(nsWindowBase* aWindow, UINT aMessage, - WPARAM& aWParam, LPARAM& aLParam, - MSGResult& aResult) +TSFTextStore::ProcessMessage(nsWindowBase* aWindow, + UINT aMessage, + WPARAM& aWParam, + LPARAM& aLParam, + MSGResult& aResult) { switch (aMessage) { case WM_IME_SETCONTEXT: @@ -5188,19 +5196,19 @@ nsTextStore::ProcessMessage(nsWindowBase* aWindow, UINT aMessage, // static bool -nsTextStore::IsIMM_IME() +TSFTextStore::IsIMM_IME() { return TSFStaticSink::IsIMM_IME(); } /******************************************************************/ -/* nsTextStore::Composition */ +/* TSFTextStore::Composition */ /******************************************************************/ void -nsTextStore::Composition::Start(ITfCompositionView* aCompositionView, - LONG aCompositionStartOffset, - const nsAString& aCompositionString) +TSFTextStore::Composition::Start(ITfCompositionView* aCompositionView, + LONG aCompositionStartOffset, + const nsAString& aCompositionString) { mView = aCompositionView; mString = aCompositionString; @@ -5208,18 +5216,18 @@ nsTextStore::Composition::Start(ITfCompositionView* aCompositionView, } void -nsTextStore::Composition::End() +TSFTextStore::Composition::End() { mView = nullptr; mString.Truncate(); } /****************************************************************************** - * nsTextStore::Content + * TSFTextStore::Content *****************************************************************************/ const nsDependentSubstring -nsTextStore::Content::GetSelectedText() const +TSFTextStore::Content::GetSelectedText() const { MOZ_ASSERT(mInitialized); return GetSubstring(static_cast(mSelection.StartOffset()), @@ -5227,14 +5235,14 @@ nsTextStore::Content::GetSelectedText() const } const nsDependentSubstring -nsTextStore::Content::GetSubstring(uint32_t aStart, uint32_t aLength) const +TSFTextStore::Content::GetSubstring(uint32_t aStart, uint32_t aLength) const { MOZ_ASSERT(mInitialized); return nsDependentSubstring(mText, aStart, aLength); } void -nsTextStore::Content::ReplaceSelectedTextWith(const nsAString& aString) +TSFTextStore::Content::ReplaceSelectedTextWith(const nsAString& aString) { MOZ_ASSERT(mInitialized); ReplaceTextWith(mSelection.StartOffset(), mSelection.Length(), aString); @@ -5253,8 +5261,9 @@ FirstDifferentCharOffset(const nsAString& aStr1, const nsAString& aStr2) } void -nsTextStore::Content::ReplaceTextWith(LONG aStart, LONG aLength, - const nsAString& aReplaceString) +TSFTextStore::Content::ReplaceTextWith(LONG aStart, + LONG aLength, + const nsAString& aReplaceString) { MOZ_ASSERT(mInitialized); const nsDependentSubstring replacedString = @@ -5298,9 +5307,9 @@ nsTextStore::Content::ReplaceTextWith(LONG aStart, LONG aLength, } void -nsTextStore::Content::StartComposition(ITfCompositionView* aCompositionView, - const PendingAction& aCompStart, - bool aPreserveSelection) +TSFTextStore::Content::StartComposition(ITfCompositionView* aCompositionView, + const PendingAction& aCompStart, + bool aPreserveSelection) { MOZ_ASSERT(mInitialized); MOZ_ASSERT(aCompositionView); @@ -5319,7 +5328,7 @@ nsTextStore::Content::StartComposition(ITfCompositionView* aCompositionView, } void -nsTextStore::Content::EndComposition(const PendingAction& aCompEnd) +TSFTextStore::Content::EndComposition(const PendingAction& aCompEnd) { MOZ_ASSERT(mInitialized); MOZ_ASSERT(mComposition.mView); @@ -5330,10 +5339,10 @@ nsTextStore::Content::EndComposition(const PendingAction& aCompEnd) } /****************************************************************************** - * nsTextStore::MouseTracker + * TSFTextStore::MouseTracker *****************************************************************************/ -nsTextStore::MouseTracker::MouseTracker() +TSFTextStore::MouseTracker::MouseTracker() : mStart(-1) , mLength(-1) , mCookie(kInvalidCookie) @@ -5341,45 +5350,45 @@ nsTextStore::MouseTracker::MouseTracker() } HRESULT -nsTextStore::MouseTracker::Init(nsTextStore* aTextStore) +TSFTextStore::MouseTracker::Init(TSFTextStore* aTextStore) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MouseTracker::Init(aTextStore=0x%p), " + ("TSF: 0x%p TSFTextStore::MouseTracker::Init(aTextStore=0x%p), " "aTextStore->mMouseTrackers.Length()=%d", this, aTextStore->mMouseTrackers.Length())); if (&aTextStore->mMouseTrackers.LastElement() != this) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::Init() FAILED due to " + ("TSF: 0x%p TSFTextStore::MouseTracker::Init() FAILED due to " "this is not the last element of mMouseTrackers", this)); return E_FAIL; } if (aTextStore->mMouseTrackers.Length() > kInvalidCookie) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::Init() FAILED due to " + ("TSF: 0x%p TSFTextStore::MouseTracker::Init() FAILED due to " "no new cookie available", this)); return E_FAIL; } MOZ_ASSERT(!aTextStore->mMouseTrackers.IsEmpty(), - "This instance must be in nsTextStore::mMouseTrackers"); + "This instance must be in TSFTextStore::mMouseTrackers"); mCookie = static_cast(aTextStore->mMouseTrackers.Length() - 1); return S_OK; } HRESULT -nsTextStore::MouseTracker::AdviseSink(nsTextStore* aTextStore, - ITfRangeACP* aTextRange, - ITfMouseSink* aMouseSink) +TSFTextStore::MouseTracker::AdviseSink(TSFTextStore* aTextStore, + ITfRangeACP* aTextRange, + ITfMouseSink* aMouseSink) { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseSink(aTextStore=0x%p, " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseSink(aTextStore=0x%p, " "aTextRange=0x%p, aMouseSink=0x%p), mCookie=%d, mSink=0x%p", this, aTextStore, aTextRange, aMouseSink, mCookie, mSink.get())); MOZ_ASSERT(mCookie != kInvalidCookie, "This hasn't been initalized?"); if (mSink) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink() FAILED " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink() FAILED " "due to already being used", this)); return E_FAIL; } @@ -5387,14 +5396,14 @@ nsTextStore::MouseTracker::AdviseSink(nsTextStore* aTextStore, HRESULT hr = aTextRange->GetExtent(&mStart, &mLength); if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink() FAILED " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink() FAILED " "due to failure of ITfRangeACP::GetExtent()", this)); return hr; } if (mStart < 0 || mLength <= 0) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink() FAILED " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink() FAILED " "due to odd result of ITfRangeACP::GetExtent(), " "mStart=%d, mLength=%d", this, mStart, mLength)); return E_INVALIDARG; @@ -5403,15 +5412,15 @@ nsTextStore::MouseTracker::AdviseSink(nsTextStore* aTextStore, nsAutoString textContent; if (NS_WARN_IF(!aTextStore->GetCurrentText(textContent))) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink() FAILED " - "due to failure of nsTextStore::GetCurrentText()", this)); + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink() FAILED " + "due to failure of TSFTextStore::GetCurrentText()", this)); return E_FAIL; } if (textContent.Length() <= static_cast(mStart) || textContent.Length() < static_cast(mStart + mLength)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink() FAILED " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink() FAILED " "due to out of range, mStart=%d, mLength=%d, " "textContent.Length()=%d", this, mStart, mLength, textContent.Length())); @@ -5421,17 +5430,17 @@ nsTextStore::MouseTracker::AdviseSink(nsTextStore* aTextStore, mSink = aMouseSink; MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MouseTracker::AdviseMouseSink(), " + ("TSF: 0x%p TSFTextStore::MouseTracker::AdviseMouseSink(), " "succeeded, mStart=%d, mLength=%d, textContent.Length()=%d", this, mStart, mLength, textContent.Length())); return S_OK; } void -nsTextStore::MouseTracker::UnadviseSink() +TSFTextStore::MouseTracker::UnadviseSink() { MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MouseTracker::UnadviseSink(), " + ("TSF: 0x%p TSFTextStore::MouseTracker::UnadviseSink(), " "mCookie=%d, mSink=0x%p, mStart=%d, mLength=%d", this, mCookie, mSink.get(), mStart, mLength)); mSink = nullptr; @@ -5439,9 +5448,9 @@ nsTextStore::MouseTracker::UnadviseSink() } bool -nsTextStore::MouseTracker::OnMouseButtonEvent(ULONG aEdge, - ULONG aQuadrant, - DWORD aButtonStatus) +TSFTextStore::MouseTracker::OnMouseButtonEvent(ULONG aEdge, + ULONG aQuadrant, + DWORD aButtonStatus) { MOZ_ASSERT(IsUsing(), "The caller must check before calling OnMouseEvent()"); @@ -5449,7 +5458,7 @@ nsTextStore::MouseTracker::OnMouseButtonEvent(ULONG aEdge, HRESULT hr = mSink->OnMouseEvent(aEdge, aQuadrant, aButtonStatus, &eaten); MOZ_LOG(sTextStoreLog, LogLevel::Debug, - ("TSF: 0x%p nsTextStore::MouseTracker::OnMouseEvent(aEdge=%d, " + ("TSF: 0x%p TSFTextStore::MouseTracker::OnMouseEvent(aEdge=%d, " "aQuadrant=%d, aButtonStatus=0x%08X), hr=0x%08X, eaten=%s", this, aEdge, aQuadrant, aButtonStatus, hr, GetBoolName(!!eaten))); @@ -5459,12 +5468,12 @@ nsTextStore::MouseTracker::OnMouseButtonEvent(ULONG aEdge, #ifdef DEBUG // static bool -nsTextStore::CurrentKeyboardLayoutHasIME() +TSFTextStore::CurrentKeyboardLayoutHasIME() { if (!sInputProcessorProfiles) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED due to there is " - "no input processor profiles instance")); + ("TSF: TSFTextStore::CurrentKeyboardLayoutHasIME() FAILED due to " + "there is no input processor profiles instance")); return false; } nsRefPtr profileMgr; @@ -5477,7 +5486,7 @@ nsTextStore::CurrentKeyboardLayoutHasIME() // keyboard layout has IME. if (IsVistaOrLater()) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to query " + ("TSF: TSFTextStore::CurrentKeyboardLayoutHasIME() FAILED to query " "ITfInputProcessorProfileMgr")); return false; } @@ -5494,10 +5503,14 @@ nsTextStore::CurrentKeyboardLayoutHasIME() } if (FAILED(hr)) { MOZ_LOG(sTextStoreLog, LogLevel::Error, - ("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive " + ("TSF: TSFTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive " "active profile")); return false; } return (profile.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR); } #endif // #ifdef DEBUG + +} // name widget +} // name mozilla + diff --git a/widget/windows/nsTextStore.h b/widget/windows/TSFTextStore.h similarity index 91% rename from widget/windows/nsTextStore.h rename to widget/windows/TSFTextStore.h index 600635343001..38b316ab1305 100644 --- a/widget/windows/nsTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -3,8 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef NSTEXTSTORE_H_ -#define NSTEXTSTORE_H_ +#ifndef TSFTextStore_h_ +#define TSFTextStore_h_ #include "nsAutoPtr.h" #include "nsString.h" @@ -41,22 +41,21 @@ class nsWindow; namespace mozilla { namespace widget { + struct MSGResult; -} // namespace widget -} // namespace mozilla /* * Text Services Framework text store */ -class nsTextStore final : public ITextStoreACP - , public ITfContextOwnerCompositionSink - , public ITfMouseTrackerACP +class TSFTextStore final : public ITextStoreACP + , public ITfContextOwnerCompositionSink + , public ITfMouseTrackerACP { public: /*IUnknown*/ STDMETHODIMP QueryInterface(REFIID, void**); - NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(nsTextStore) + NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFTextStore) public: /*ITextStoreACP*/ STDMETHODIMP AdviseSink(REFIID, IUnknown*, DWORD); @@ -100,12 +99,6 @@ public: /*ITfMouseTrackerACP*/ STDMETHODIMP AdviseMouseSink(ITfRangeACP*, ITfMouseSink*, DWORD*); STDMETHODIMP UnadviseMouseSink(DWORD); -protected: - typedef mozilla::widget::IMENotification IMENotification; - typedef mozilla::widget::IMEState IMEState; - typedef mozilla::widget::InputContext InputContext; - typedef mozilla::widget::InputContextAction InputContextAction; - public: static void Initialize(void); static void Terminate(void); @@ -113,7 +106,7 @@ public: static bool ProcessRawKeyMessage(const MSG& aMsg); static void ProcessMessage(nsWindowBase* aWindow, UINT aMessage, WPARAM& aWParam, LPARAM& aLParam, - mozilla::widget::MSGResult& aResult); + MSGResult& aResult); static void SetIMEOpenState(bool); @@ -227,8 +220,8 @@ public: #endif // #ifdef DEBUG protected: - nsTextStore(); - ~nsTextStore(); + TSFTextStore(); + ~TSFTextStore(); static bool CreateAndSetFocus(nsWindowBase* aFocusedWidget, const InputContext& aContext); @@ -253,7 +246,7 @@ protected: // Note that mLock isn't cleared yet when this is called. void DidLockGranted(); - bool GetScreenExtInternal(RECT &aScreenExt); + bool GetScreenExtInternal(RECT& aScreenExt); // If aDispatchCompositionChangeEvent is true, this method will dispatch // compositionchange event if this is called during IME composing. // aDispatchCompositionChangeEvent should be true only when this is called @@ -261,7 +254,7 @@ protected: // not be sent from here. HRESULT SetSelectionInternal(const TS_SELECTION_ACP*, bool aDispatchCompositionChangeEvent = false); - bool InsertTextAtSelectionInternal(const nsAString &aInsertStr, + bool InsertTextAtSelectionInternal(const nsAString& aInsertStr, TS_TEXTCHANGE* aTextChange); void CommitCompositionInternal(bool); nsresult OnTextChangeInternal(const IMENotification& aIMENotification); @@ -289,7 +282,7 @@ protected: // DispatchEvent() dispatches the event and if it may not be handled // synchronously, this makes the instance not notify TSF of pending // notifications until next notification from content. - void DispatchEvent(mozilla::WidgetGUIEvent& aEvent); + void DispatchEvent(WidgetGUIEvent& aEvent); void OnLayoutInformationAvaliable(); // FlushPendingActions() performs pending actions recorded in mPendingActions @@ -369,7 +362,7 @@ protected: // While the document is locked, we cannot dispatch any events which cause // DOM events since the DOM events' handlers may modify the locked document. // However, even while the document is locked, TSF may queries us. - // For that, nsTextStore modifies mComposition even while the document is + // For that, TSFTextStore modifies mComposition even while the document is // locked. With mComposition, query methods can returns the text content // information. Composition mComposition; @@ -401,8 +394,10 @@ protected: mACP.style.fInterimChar = FALSE; } - void SetSelection(uint32_t aStart, uint32_t aLength, bool aReversed, - mozilla::WritingMode aWritingMode) + void SetSelection(uint32_t aStart, + uint32_t aLength, + bool aReversed, + WritingMode aWritingMode) { mDirty = false; mACP.acpStart = static_cast(aStart); @@ -484,7 +479,7 @@ protected: return (mACP.style.fInterimChar != FALSE); } - mozilla::WritingMode GetWritingMode() const + WritingMode GetWritingMode() const { MOZ_ASSERT(!mDirty); return mWritingMode; @@ -492,7 +487,7 @@ protected: private: TS_SELECTION_ACP mACP; - mozilla::WritingMode mWritingMode; + WritingMode mWritingMode; bool mDirty; }; // Don't access mSelection directly except at calling MarkDirty(). @@ -523,7 +518,7 @@ protected: // For compositionupdate and compositionend nsString mData; // For compositionupdate - nsRefPtr mRanges; + nsRefPtr mRanges; // For selectionset bool mSelectionReversed; // For compositionupdate @@ -547,7 +542,7 @@ protected: } PendingAction* newAction = mPendingActions.AppendElement(); newAction->mType = PendingAction::COMPOSITION_UPDATE; - newAction->mRanges = new mozilla::TextRangeArray(); + newAction->mRanges = new TextRangeArray(); newAction->mIncomplete = true; return newAction; } @@ -576,7 +571,7 @@ protected: class MOZ_STACK_CLASS AutoPendingActionAndContentFlusher final { public: - AutoPendingActionAndContentFlusher(nsTextStore* aTextStore) + AutoPendingActionAndContentFlusher(TSFTextStore* aTextStore) : mTextStore(aTextStore) { MOZ_ASSERT(!mTextStore->mIsRecordingActionsWithoutLock); @@ -597,14 +592,14 @@ protected: private: AutoPendingActionAndContentFlusher() {} - nsRefPtr mTextStore; + nsRefPtr mTextStore; }; class Content final { public: - Content(nsTextStore::Composition& aComposition, - nsTextStore::Selection& aSelection) : + Content(TSFTextStore::Composition& aComposition, + TSFTextStore::Selection& aSelection) : mComposition(aComposition), mSelection(aSelection) { Clear(); @@ -664,16 +659,16 @@ protected: return mInitialized ? mMinTextModifiedOffset : NOT_MODIFIED; } - nsTextStore::Composition& Composition() { return mComposition; } - nsTextStore::Selection& Selection() { return mSelection; } + TSFTextStore::Composition& Composition() { return mComposition; } + TSFTextStore::Selection& Selection() { return mSelection; } private: nsString mText; // mLastCompositionString stores the composition string when the document // is locked. This is necessary to compute mMinTextModifiedOffset. nsString mLastCompositionString; - nsTextStore::Composition& mComposition; - nsTextStore::Selection& mSelection; + TSFTextStore::Composition& mComposition; + TSFTextStore::Selection& mSelection; // The minimum offset of modified part of the text. enum : uint32_t @@ -705,8 +700,8 @@ protected: MouseTracker(); - HRESULT Init(nsTextStore* aTextStore); - HRESULT AdviseSink(nsTextStore* aTextStore, + HRESULT Init(TSFTextStore* aTextStore); + HRESULT AdviseSink(TSFTextStore* aTextStore, ITfRangeACP* aTextRange, ITfMouseSink* aMouseSink); void UnadviseSink(); @@ -794,28 +789,27 @@ protected: // TSF thread manager object for the current application - static mozilla::StaticRefPtr sThreadMgr; + static StaticRefPtr sThreadMgr; // sMessagePump is QI'ed from sThreadMgr - static mozilla::StaticRefPtr sMessagePump; + static StaticRefPtr sMessagePump; // sKeystrokeMgr is QI'ed from sThreadMgr - static mozilla::StaticRefPtr sKeystrokeMgr; + static StaticRefPtr sKeystrokeMgr; // TSF display attribute manager - static mozilla::StaticRefPtr sDisplayAttrMgr; + static StaticRefPtr sDisplayAttrMgr; // TSF category manager - static mozilla::StaticRefPtr sCategoryMgr; + static StaticRefPtr sCategoryMgr; // Current text store which is managing a keyboard enabled editor (i.e., - // editable editor). Currently only ONE nsTextStore instance is ever used, + // editable editor). Currently only ONE TSFTextStore instance is ever used, // although Create is called when an editor is focused and Destroy called // when the focused editor is blurred. - static mozilla::StaticRefPtr sEnabledTextStore; + static StaticRefPtr sEnabledTextStore; // For IME (keyboard) disabled state: - static mozilla::StaticRefPtr sDisabledDocumentMgr; - static mozilla::StaticRefPtr sDisabledContext; + static StaticRefPtr sDisabledDocumentMgr; + static StaticRefPtr sDisabledContext; - static mozilla::StaticRefPtr - sInputProcessorProfiles; + static StaticRefPtr sInputProcessorProfiles; // TSF client ID for the current application static DWORD sClientId; @@ -828,4 +822,7 @@ protected: static bool sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret; }; -#endif /*NSTEXTSTORE_H_*/ +} // namespace widget +} // namespace mozilla + +#endif // #ifndef TSFTextStore_h_ diff --git a/widget/windows/WinIMEHandler.cpp b/widget/windows/WinIMEHandler.cpp index e1a6f2b508c9..695c9d6c54ed 100644 --- a/widget/windows/WinIMEHandler.cpp +++ b/widget/windows/WinIMEHandler.cpp @@ -10,7 +10,7 @@ #include "nsWindowDefs.h" #ifdef NS_ENABLE_TSF -#include "nsTextStore.h" +#include "TSFTextStore.h" #endif // #ifdef NS_ENABLE_TSF #include "nsWindow.h" @@ -35,12 +35,12 @@ void IMEHandler::Initialize() { #ifdef NS_ENABLE_TSF - nsTextStore::Initialize(); - sIsInTSFMode = nsTextStore::IsInTSFMode(); + TSFTextStore::Initialize(); + sIsInTSFMode = TSFTextStore::IsInTSFMode(); sIsIMMEnabled = !sIsInTSFMode || Preferences::GetBool("intl.tsf.support_imm", true); if (!sIsInTSFMode) { - // When full nsTextStore is not available, try to use SetInputScopes API + // When full TSFTextStore is not available, try to use SetInputScopes API // to enable at least InputScope. Use GET_MODULE_HANDLE_EX_FLAG_PIN to // ensure that msctf.dll will not be unloaded. HMODULE module = nullptr; @@ -61,7 +61,7 @@ IMEHandler::Terminate() { #ifdef NS_ENABLE_TSF if (sIsInTSFMode) { - nsTextStore::Terminate(); + TSFTextStore::Terminate(); sIsInTSFMode = false; } #endif // #ifdef NS_ENABLE_TSF @@ -74,7 +74,7 @@ void* IMEHandler::GetNativeData(uint32_t aDataType) { #ifdef NS_ENABLE_TSF - void* result = nsTextStore::GetNativeData(aDataType); + void* result = TSFTextStore::GetNativeData(aDataType); if (!result || !(*(static_cast(result)))) { return nullptr; } @@ -95,7 +95,7 @@ IMEHandler::ProcessRawKeyMessage(const MSG& aMsg) { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::ProcessRawKeyMessage(aMsg); + return TSFTextStore::ProcessRawKeyMessage(aMsg); } #endif // #ifdef NS_ENABLE_TSF return false; // noting to do in IMM mode. @@ -109,7 +109,7 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage, { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - nsTextStore::ProcessMessage(aWindow, aMessage, aWParam, aLParam, aResult); + TSFTextStore::ProcessMessage(aWindow, aMessage, aWParam, aLParam, aResult); if (aResult.mConsumed) { return true; } @@ -119,7 +119,7 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage, } // IME isn't implemented with IMM, IMMHandler shouldn't handle any // messages. - if (!nsTextStore::IsIMM_IME()) { + if (!TSFTextStore::IsIMM_IME()) { return false; } } @@ -134,7 +134,7 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage, bool IMEHandler::IsIMMActive() { - return nsTextStore::IsIMM_IME(); + return TSFTextStore::IsIMM_IME(); } #endif // #ifdef NS_ENABLE_TSF @@ -144,7 +144,7 @@ IMEHandler::IsComposing() { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::IsComposing() || IMMHandler::IsComposing(); + return TSFTextStore::IsComposing() || IMMHandler::IsComposing(); } #endif // #ifdef NS_ENABLE_TSF @@ -157,7 +157,7 @@ IMEHandler::IsComposingOn(nsWindow* aWindow) { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::IsComposingOn(aWindow) || + return TSFTextStore::IsComposingOn(aWindow) || IMMHandler::IsComposingOn(aWindow); } #endif // #ifdef NS_ENABLE_TSF @@ -174,7 +174,7 @@ IMEHandler::NotifyIME(nsWindow* aWindow, if (IsTSFAvailable()) { switch (aIMENotification.mMessage) { case NOTIFY_IME_OF_SELECTION_CHANGE: { - nsresult rv = nsTextStore::OnSelectionChange(aIMENotification); + nsresult rv = TSFTextStore::OnSelectionChange(aIMENotification); // If IMM IME is active, we need to notify IMMHandler of updating // composition change. It will adjust candidate window position or // composition window position. @@ -192,41 +192,41 @@ IMEHandler::NotifyIME(nsWindow* aWindow, if (IsIMMActive()) { IMMHandler::OnUpdateComposition(aWindow); } else { - nsTextStore::OnUpdateComposition(); + TSFTextStore::OnUpdateComposition(); } return NS_OK; case NOTIFY_IME_OF_TEXT_CHANGE: - return nsTextStore::OnTextChange(aIMENotification); + return TSFTextStore::OnTextChange(aIMENotification); case NOTIFY_IME_OF_FOCUS: IMMHandler::OnFocusChange(true, aWindow); - return nsTextStore::OnFocusChange(true, aWindow, - aWindow->GetInputContext()); + return TSFTextStore::OnFocusChange(true, aWindow, + aWindow->GetInputContext()); case NOTIFY_IME_OF_BLUR: IMMHandler::OnFocusChange(false, aWindow); - return nsTextStore::OnFocusChange(false, aWindow, - aWindow->GetInputContext()); + return TSFTextStore::OnFocusChange(false, aWindow, + aWindow->GetInputContext()); case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: // If IMM IME is active, we should send a mouse button event via IMM. if (IsIMMActive()) { return IMMHandler::OnMouseButtonEvent(aWindow, aIMENotification); } - return nsTextStore::OnMouseButtonEvent(aIMENotification); + return TSFTextStore::OnMouseButtonEvent(aIMENotification); case REQUEST_TO_COMMIT_COMPOSITION: - if (nsTextStore::IsComposingOn(aWindow)) { - nsTextStore::CommitComposition(false); + if (TSFTextStore::IsComposingOn(aWindow)) { + TSFTextStore::CommitComposition(false); } else if (IsIMMActive()) { IMMHandler::CommitComposition(aWindow); } return NS_OK; case REQUEST_TO_CANCEL_COMPOSITION: - if (nsTextStore::IsComposingOn(aWindow)) { - nsTextStore::CommitComposition(true); + if (TSFTextStore::IsComposingOn(aWindow)) { + TSFTextStore::CommitComposition(true); } else if (IsIMMActive()) { IMMHandler::CancelComposition(aWindow); } return NS_OK; case NOTIFY_IME_OF_POSITION_CHANGE: - return nsTextStore::OnLayoutChange(); + return TSFTextStore::OnLayoutChange(); default: return NS_ERROR_NOT_IMPLEMENTED; } @@ -257,9 +257,9 @@ IMEHandler::NotifyIME(nsWindow* aWindow, #ifdef NS_ENABLE_TSF // If a plugin gets focus while TSF has focus, we need to notify TSF of // the blur. - if (nsTextStore::ThinksHavingFocus()) { - return nsTextStore::OnFocusChange(false, aWindow, - aWindow->GetInputContext()); + if (TSFTextStore::ThinksHavingFocus()) { + return TSFTextStore::OnFocusChange(false, aWindow, + aWindow->GetInputContext()); } #endif //NS_ENABLE_TSF return NS_OK; @@ -274,7 +274,7 @@ IMEHandler::GetUpdatePreference() { #ifdef NS_ENABLE_TSF if (IsTSFAvailable()) { - return nsTextStore::GetIMEUpdatePreference(); + return TSFTextStore::GetIMEUpdatePreference(); } #endif //NS_ENABLE_TSF @@ -287,7 +287,7 @@ IMEHandler::GetOpenState(nsWindow* aWindow) { #ifdef NS_ENABLE_TSF if (IsTSFAvailable() && !IsIMMActive()) { - return nsTextStore::GetIMEOpenState(); + return TSFTextStore::GetIMEOpenState(); } #endif //NS_ENABLE_TSF @@ -336,9 +336,9 @@ IMEHandler::SetInputContext(nsWindow* aWindow, #ifdef NS_ENABLE_TSF // Note that even while a plugin has focus, we need to notify TSF of that. if (sIsInTSFMode) { - nsTextStore::SetInputContext(aWindow, aInputContext, aAction); + TSFTextStore::SetInputContext(aWindow, aInputContext, aAction); if (IsTSFAvailable()) { - aInputContext.mNativeIMEContext = nsTextStore::GetThreadManager(); + aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager(); if (sIsIMMEnabled) { // Associate IME context for IMM-IMEs. AssociateIMEContext(aWindow, enable); @@ -348,7 +348,7 @@ IMEHandler::SetInputContext(nsWindow* aWindow, AssociateIMEContext(aWindow, false); } if (adjustOpenState) { - nsTextStore::SetIMEOpenState(open); + TSFTextStore::SetIMEOpenState(open); } return; } @@ -400,10 +400,10 @@ IMEHandler::InitInputContext(nsWindow* aWindow, InputContext& aInputContext) #ifdef NS_ENABLE_TSF if (sIsInTSFMode) { - nsTextStore::SetInputContext(aWindow, aInputContext, + TSFTextStore::SetInputContext(aWindow, aInputContext, InputContextAction(InputContextAction::CAUSE_UNKNOWN, InputContextAction::GOT_FOCUS)); - aInputContext.mNativeIMEContext = nsTextStore::GetThreadManager(); + aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager(); MOZ_ASSERT(aInputContext.mNativeIMEContext); // IME context isn't necessary in pure TSF mode. if (!sIsIMMEnabled) { @@ -431,7 +431,7 @@ IMEHandler::CurrentKeyboardLayoutHasIME() { #ifdef NS_ENABLE_TSF if (sIsInTSFMode) { - return nsTextStore::CurrentKeyboardLayoutHasIME(); + return TSFTextStore::CurrentKeyboardLayoutHasIME(); } #endif // #ifdef NS_ENABLE_TSF diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index 2360a43679ae..7d70f7431721 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -47,7 +47,7 @@ #ifdef NS_ENABLE_TSF #include -#include "nsTextStore.h" +#include "TSFTextStore.h" #endif // #ifdef NS_ENABLE_TSF PRLogModuleInfo* gWindowsLog = nullptr; @@ -572,7 +572,7 @@ WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, UINT aLastMessage, UINT aOption) { #ifdef NS_ENABLE_TSF - ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); + ITfMessagePump* msgPump = TSFTextStore::GetMessagePump(); if (msgPump) { BOOL ret = FALSE; HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, @@ -590,7 +590,7 @@ WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, UINT aLastMessage) { #ifdef NS_ENABLE_TSF - ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); + ITfMessagePump* msgPump = TSFTextStore::GetMessagePump(); if (msgPump) { BOOL ret = FALSE; HRESULT hr = msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, diff --git a/widget/windows/moz.build b/widget/windows/moz.build index 40c0660122b0..755e763553c1 100644 --- a/widget/windows/moz.build +++ b/widget/windows/moz.build @@ -81,7 +81,7 @@ if CONFIG['NS_PRINTING']: if CONFIG['NS_ENABLE_TSF']: SOURCES += [ - 'nsTextStore.cpp', + 'TSFTextStore.cpp', ] FAIL_ON_WARNINGS = True From 6417ed4d21596121f3b58f3a49bdeba08b139baf Mon Sep 17 00:00:00 2001 From: JW Wang Date: Fri, 24 Jul 2015 14:24:42 +0800 Subject: [PATCH 34/90] Bug 1186801 - Remove decoder monitor from AudioSink. r=kinetik. --- dom/media/AudioSink.cpp | 25 ++++++++++++++++--------- dom/media/AudioSink.h | 16 +++++++++------- dom/media/MediaDecoderStateMachine.cpp | 14 ++++++++------ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/dom/media/AudioSink.cpp b/dom/media/AudioSink.cpp index dceef6e2ee9f..1b761b8c1fcb 100644 --- a/dom/media/AudioSink.cpp +++ b/dom/media/AudioSink.cpp @@ -23,12 +23,11 @@ extern PRLogModuleInfo* gMediaDecoderLog; static const int64_t AUDIO_FUZZ_FRAMES = 1; AudioSink::AudioSink(MediaQueue& aAudioQueue, - ReentrantMonitor& aMonitor, int64_t aStartTime, const AudioInfo& aInfo, dom::AudioChannel aChannel) : mAudioQueue(aAudioQueue) - , mDecoderMonitor(aMonitor) + , mMonitor("AudioSink::mMonitor") , mStartTime(aStartTime) , mWritten(0) , mLastGoodPosition(0) @@ -71,7 +70,7 @@ AudioSink::Init() int64_t AudioSink::GetPosition() { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); int64_t pos; if (mAudioStream && @@ -86,7 +85,7 @@ AudioSink::GetPosition() bool AudioSink::HasUnplayedFrames() { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); // Experimentation suggests that GetPositionInFrames() is zero-indexed, // so we need to add 1 here before comparing it to mWritten. return mAudioStream && mAudioStream->GetPositionInFrames() + 1 < mWritten; @@ -95,13 +94,14 @@ AudioSink::HasUnplayedFrames() void AudioSink::Shutdown() { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mStopAudioThread = true; if (mAudioStream) { mAudioStream->Cancel(); } GetReentrantMonitor().NotifyAll(); + // Exit the monitor so audio loop can enter the monitor and finish its job. ReentrantMonitorAutoExit exit(GetReentrantMonitor()); mThread->Shutdown(); mThread = nullptr; @@ -114,7 +114,7 @@ AudioSink::Shutdown() void AudioSink::SetVolume(double aVolume) { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mVolume = aVolume; mSetVolume = true; } @@ -122,7 +122,7 @@ AudioSink::SetVolume(double aVolume) void AudioSink::SetPlaybackRate(double aPlaybackRate) { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); NS_ASSERTION(mPlaybackRate != 0, "Don't set the playbackRate to 0 on AudioStream"); mPlaybackRate = aPlaybackRate; mSetPlaybackRate = true; @@ -131,7 +131,7 @@ AudioSink::SetPlaybackRate(double aPlaybackRate) void AudioSink::SetPreservesPitch(bool aPreservesPitch) { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mPreservesPitch = aPreservesPitch; mSetPreservesPitch = true; } @@ -139,11 +139,18 @@ AudioSink::SetPreservesPitch(bool aPreservesPitch) void AudioSink::SetPlaying(bool aPlaying) { - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mPlaying = aPlaying; GetReentrantMonitor().NotifyAll(); } +void +AudioSink::NotifyData() +{ + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + GetReentrantMonitor().NotifyAll(); +} + void AudioSink::AudioLoop() { diff --git a/dom/media/AudioSink.h b/dom/media/AudioSink.h index 2b36e7083d99..e14f09399112 100644 --- a/dom/media/AudioSink.h +++ b/dom/media/AudioSink.h @@ -26,7 +26,6 @@ public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioSink) AudioSink(MediaQueue& aAudioQueue, - ReentrantMonitor& aMonitor, int64_t aStartTime, const AudioInfo& aInfo, dom::AudioChannel aChannel); @@ -35,9 +34,10 @@ public: // or rejected if any error. nsRefPtr Init(); + /* + * All public functions below are thread-safe. + */ int64_t GetPosition(); - - // Thread-safe. Can be called on any thread. int64_t GetEndTime() const; // Check whether we've pushed more frames to the audio hardware than it has @@ -45,15 +45,17 @@ public: bool HasUnplayedFrames(); // Shut down the AudioSink's resources. - // Must be called with the decoder monitor held. void Shutdown(); void SetVolume(double aVolume); void SetPlaybackRate(double aPlaybackRate); void SetPreservesPitch(bool aPreservesPitch); - void SetPlaying(bool aPlaying); + // Wake up the audio loop if it is waiting for data to play or the audio + // queue is finished. + void NotifyData(); + private: ~AudioSink() {} @@ -104,7 +106,7 @@ private: } ReentrantMonitor& GetReentrantMonitor() const { - return mDecoderMonitor; + return mMonitor; } void AssertCurrentThreadInMonitor() const { @@ -114,7 +116,7 @@ private: void AssertOnAudioThread(); MediaQueue& mAudioQueue; - ReentrantMonitor& mDecoderMonitor; + mutable ReentrantMonitor mMonitor; // Thread for pushing audio onto the audio hardware. // The "audio push thread". diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 960fd6850e66..2ca215ca06f9 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -642,8 +642,9 @@ MediaDecoderStateMachine::Push(AudioData* aSample) UpdateNextFrameStatus(); DispatchDecodeTasksIfNeeded(); - // XXXbholley - Still necessary? - mDecoder->GetReentrantMonitor().NotifyAll(); + if (mAudioSink) { + mAudioSink->NotifyData(); + } } void @@ -789,6 +790,10 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, case DECODER_STATE_DECODING: { CheckIfDecodeComplete(); mDecoder->GetReentrantMonitor().NotifyAll(); + // Tell AudioSink to wake up for audio queue is finished. + if (mAudioSink) { + mAudioSink->NotifyData(); + } // Schedule the state machine to notify track ended as soon as possible. if (mAudioCaptured) { ScheduleStateMachine(); @@ -1053,9 +1058,6 @@ void MediaDecoderStateMachine::StopPlayback() mPlayDuration = GetClock(); SetPlayStartTime(TimeStamp()); } - // Notify the audio sink, so that it notices that we've stopped playing, - // so it can pause audio playback. - mDecoder->GetReentrantMonitor().NotifyAll(); NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()"); DispatchDecodeTasksIfNeeded(); @@ -1794,7 +1796,7 @@ MediaDecoderStateMachine::StartAudioThread() if (HasAudio() && !mAudioSink) { mAudioCompleted = false; - mAudioSink = new AudioSink(mAudioQueue, mDecoder->GetReentrantMonitor(), + mAudioSink = new AudioSink(mAudioQueue, GetMediaTime(), mInfo.mAudio, mDecoder->GetAudioChannel()); From 94f8966c4bf5e21fbb8bfa202620e1fc2fd28747 Mon Sep 17 00:00:00 2001 From: Nate Hughes Date: Fri, 17 Jul 2015 14:38:10 -0700 Subject: [PATCH 35/90] Bug 986302 - Add memory reporting for HPACK tables r=hurley r=njn --- netwerk/protocol/http/Http2Compression.cpp | 89 ++++++++++++++++++++++ netwerk/protocol/http/Http2Compression.h | 11 ++- xpcom/base/nsIMemoryReporter.idl | 3 + xpcom/base/nsMemoryReporterManager.cpp | 11 +++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 9bc69abd611e..c0552cfd7744 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -16,6 +16,7 @@ #include "Http2Compression.h" #include "Http2HuffmanIncoming.h" #include "Http2HuffmanOutgoing.h" +#include "mozilla/StaticPtr.h" extern PRThread *gSocketThread; @@ -24,12 +25,70 @@ namespace net { static nsDeque *gStaticHeaders = nullptr; +class HpackStaticTableReporter final : public nsIMemoryReporter +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + HpackStaticTableReporter() {} + + NS_IMETHODIMP + CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, + bool aAnonymize) override + { + return MOZ_COLLECT_REPORT( + "explicit/network/hpack/static-table", KIND_HEAP, UNITS_BYTES, + gStaticHeaders->SizeOfIncludingThis(MallocSizeOf), + "Memory usage of HPACK static table."); + } + +private: + MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) + + ~HpackStaticTableReporter() {} +}; + +NS_IMPL_ISUPPORTS(HpackStaticTableReporter, nsIMemoryReporter) + +class HpackDynamicTableReporter final : public nsIMemoryReporter +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + explicit HpackDynamicTableReporter(Http2BaseCompressor* aCompressor) + : mCompressor(aCompressor) + {} + + NS_IMETHODIMP + CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, + bool aAnonymize) override + { + return MOZ_COLLECT_REPORT( + "explicit/network/hpack/dynamic-tables", KIND_HEAP, UNITS_BYTES, + mCompressor->SizeOfExcludingThis(MallocSizeOf), + "Aggregate memory usage of HPACK dynamic tables."); + } + +private: + MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) + + ~HpackDynamicTableReporter() {} + + Http2BaseCompressor* mCompressor; +}; + +NS_IMPL_ISUPPORTS(HpackDynamicTableReporter, nsIMemoryReporter) + +StaticRefPtr gStaticReporter; + void Http2CompressionCleanup() { // this happens after the socket thread has been destroyed delete gStaticHeaders; gStaticHeaders = nullptr; + UnregisterStrongMemoryReporter(gStaticReporter); + gStaticReporter = nullptr; } static void @@ -51,6 +110,8 @@ InitializeStaticHeaders() MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); if (!gStaticHeaders) { gStaticHeaders = new nsDeque(); + gStaticReporter = new HpackStaticTableReporter(); + RegisterStrongMemoryReporter(gStaticReporter); AddStaticElement(NS_LITERAL_CSTRING(":authority")); AddStaticElement(NS_LITERAL_CSTRING(":method"), NS_LITERAL_CSTRING("GET")); AddStaticElement(NS_LITERAL_CSTRING(":method"), NS_LITERAL_CSTRING("POST")); @@ -115,6 +176,17 @@ InitializeStaticHeaders() } } +size_t nvPair::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + return mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf) + + mValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf); +} + +size_t nvPair::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const +{ + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); +} + nvFIFO::nvFIFO() : mByteCount(0) , mTable() @@ -203,6 +275,13 @@ Http2BaseCompressor::Http2BaseCompressor() : mOutput(nullptr) , mMaxBuffer(kDefaultMaxBuffer) { + mDynamicReporter = new HpackDynamicTableReporter(this); + RegisterStrongMemoryReporter(mDynamicReporter); +} + +Http2BaseCompressor::~Http2BaseCompressor() +{ + UnregisterStrongMemoryReporter(mDynamicReporter); } void @@ -211,6 +290,16 @@ Http2BaseCompressor::ClearHeaderTable() mHeaderTable.Clear(); } +size_t +Http2BaseCompressor::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +{ + size_t size = 0; + for (uint32_t i = mHeaderTable.StaticLength(); i < mHeaderTable.Length(); ++i) { + size += mHeaderTable[i]->SizeOfIncludingThis(aMallocSizeOf); + } + return size; +} + void Http2BaseCompressor::MakeRoom(uint32_t amount, const char *direction) { diff --git a/netwerk/protocol/http/Http2Compression.h b/netwerk/protocol/http/Http2Compression.h index 60f0923040be..c78175d02f10 100644 --- a/netwerk/protocol/http/Http2Compression.h +++ b/netwerk/protocol/http/Http2Compression.h @@ -12,6 +12,7 @@ #include "mozilla/Attributes.h" #include "nsDeque.h" #include "nsString.h" +#include "nsIMemoryReporter.h" namespace mozilla { namespace net { @@ -29,6 +30,8 @@ nvPair(const nsACString &name, const nsACString &value) { } uint32_t Size() const { return mName.Length() + mValue.Length() + 32; } + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; nsCString mName; nsCString mValue; @@ -54,11 +57,14 @@ private: nsDeque mTable; }; +class HpackDynamicTableReporter; + class Http2BaseCompressor { public: Http2BaseCompressor(); - virtual ~Http2BaseCompressor() { }; + virtual ~Http2BaseCompressor(); + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; protected: const static uint32_t kDefaultMaxBuffer = 4096; @@ -71,6 +77,9 @@ protected: nvFIFO mHeaderTable; uint32_t mMaxBuffer; + +private: + nsRefPtr mDynamicReporter; }; class Http2Compressor; diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 14c31c24c0f4..39e3be823b18 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -464,6 +464,9 @@ XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); // to this reporter. XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); +// Unregister a strong memory reporter. +XPCOM_API(nsresult) UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter); + // Unregister a weak memory reporter. XPCOM_API(nsresult) UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter); diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 0d63557103fa..00491749d959 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -2293,6 +2293,17 @@ RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) return mgr->RegisterWeakReporter(aReporter); } +nsresult +UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } + return mgr->UnregisterStrongReporter(aReporter); +} + nsresult UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { From 82dbe1a9193f2e5c0aa8f3aa176cf43480448c91 Mon Sep 17 00:00:00 2001 From: Spenser Andrew Bauman Date: Wed, 22 Jul 2015 18:12:00 +0200 Subject: [PATCH 36/90] Bug 1030095 - IonMonkey: When deciding to inline don't check for a common inlining path on the first builder. r=h4writer --- js/src/jit/IonBuilder.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 3a21d3fab319..9d5dcfdbb11d 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -406,12 +406,9 @@ IonBuilder::DontInline(JSScript* targetScript, const char* reason) bool IonBuilder::hasCommonInliningPath(const JSScript* scriptToInline) { - if (this->script() == scriptToInline) - return true; - // Find all previous inlinings of the |scriptToInline| and check for common // inlining paths with the top of the inlining stack. - for (IonBuilder* it = this; it; it = it->callerBuilder_) { + for (IonBuilder* it = this->callerBuilder_; it; it = it->callerBuilder_) { if (it->script() != scriptToInline) continue; From 176076ffd372831de98c6ebd8db0fdb099818460 Mon Sep 17 00:00:00 2001 From: Benjamin Chen Date: Wed, 22 Jul 2015 18:51:47 +0800 Subject: [PATCH 37/90] Bug 1064535 - fix testcase: 1. Relax the number of ondataavailble checking. 2. Don't check the mimetype of empty blob. r=jwwang --- .../test/test_mediarecorder_record_startstopstart.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dom/media/test/test_mediarecorder_record_startstopstart.html b/dom/media/test/test_mediarecorder_record_startstopstart.html index 67d484de57c7..1d90a782b34b 100644 --- a/dom/media/test/test_mediarecorder_record_startstopstart.html +++ b/dom/media/test/test_mediarecorder_record_startstopstart.html @@ -26,8 +26,11 @@ function startTest() { 'Media recorder stream = element stream post recording'); stopCount++; if (stopCount == 2) { - is(2, dataavailable, 'Should has two dataavailable event'); - SimpleTest.finish(); + if (dataavailable >= 2) { + SimpleTest.finish(); + } else { + ok(false, 'Should have at least two dataavailable events'); + } } } recorder.ondataavailable = function (evt) { @@ -41,9 +44,6 @@ function startTest() { info('blob size = ' + evt.data.size); is(evt.data.type, expectedMimeType, 'Blob data received should have type = ' + expectedMimeType); - } else { - is(evt.data.type, '', - 'Blob data received should have empty type'); } dataavailable++; } From 6555587480c67a1808145d56af6aed27197b9be8 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 21 Jul 2015 17:15:00 +0200 Subject: [PATCH 38/90] Bug 1144631 - Make FTP with auth prompts work in e10s. r=billm/dragana --- netwerk/ipc/NeckoParent.cpp | 2 +- netwerk/protocol/ftp/FTPChannelParent.cpp | 32 ++++++++++++++++++++--- netwerk/protocol/ftp/FTPChannelParent.h | 11 +++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 4966109e208c..c34c6fa1300c 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -271,7 +271,7 @@ NeckoParent::AllocPFTPChannelParent(const PBrowserOrId& aBrowser, return nullptr; } PBOverrideStatus overrideStatus = PBOverrideStatusFromLoadContext(aSerialized); - FTPChannelParent *p = new FTPChannelParent(loadContext, overrideStatus); + FTPChannelParent *p = new FTPChannelParent(aBrowser, loadContext, overrideStatus); p->AddRef(); return p; } diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index aaa131365233..45422dfce417 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -6,10 +6,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/net/FTPChannelParent.h" +#include "mozilla/dom/TabParent.h" #include "nsFTPChannel.h" #include "nsNetCID.h" #include "nsNetUtil.h" +#include "nsQueryObject.h" #include "nsFtpProtocolHandler.h" +#include "nsIAuthPrompt.h" +#include "nsIAuthPromptProvider.h" #include "nsIEncodedChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIForcePendingChannel.h" @@ -22,6 +26,7 @@ #include "nsIOService.h" #include "mozilla/LoadInfo.h" +using namespace mozilla::dom; using namespace mozilla::ipc; #undef LOG @@ -30,7 +35,9 @@ using namespace mozilla::ipc; namespace mozilla { namespace net { -FTPChannelParent::FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus) +FTPChannelParent::FTPChannelParent(const PBrowserOrId& aIframeEmbedding, + nsILoadContext* aLoadContext, + PBOverrideStatus aOverrideStatus) : mIPCClosed(false) , mLoadContext(aLoadContext) , mPBOverride(aOverrideStatus) @@ -41,8 +48,12 @@ FTPChannelParent::FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatu { nsIProtocolHandler* handler; CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler); - NS_ASSERTION(handler, "no ftp handler"); - + MOZ_ASSERT(handler, "no ftp handler"); + + if (aIframeEmbedding.type() == PBrowserOrId::TPBrowserParent) { + mTabParent = static_cast(aIframeEmbedding.get_PBrowserParent()); + } + mObserver = new OfflineObserver(this); } @@ -450,6 +461,21 @@ FTPChannelParent::Delete() NS_IMETHODIMP FTPChannelParent::GetInterface(const nsIID& uuid, void** result) { + if (uuid.Equals(NS_GET_IID(nsIAuthPromptProvider)) || + uuid.Equals(NS_GET_IID(nsISecureBrowserUI))) { + if (mTabParent) { + return mTabParent->QueryInterface(uuid, result); + } + } else if (uuid.Equals(NS_GET_IID(nsIAuthPrompt)) || + uuid.Equals(NS_GET_IID(nsIAuthPrompt2))) { + nsCOMPtr provider(do_QueryObject(mTabParent)); + if (provider) { + return provider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL, + uuid, + result); + } + } + // Only support nsILoadContext if child channel's callbacks did too if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { nsCOMPtr copy = mLoadContext; diff --git a/netwerk/protocol/ftp/FTPChannelParent.h b/netwerk/protocol/ftp/FTPChannelParent.h index db5be931e1d4..fcb2511acfb4 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.h +++ b/netwerk/protocol/ftp/FTPChannelParent.h @@ -19,6 +19,12 @@ class nsILoadContext; namespace mozilla { + +namespace dom { +class TabParent; +class PBrowserOrId; +} // namespace dom + namespace net { class FTPChannelParent final : public PFTPChannelParent @@ -36,7 +42,9 @@ public: NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK - FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus); + FTPChannelParent(const dom::PBrowserOrId& aIframeEmbedding, + nsILoadContext* aLoadContext, + PBOverrideStatus aOverrideStatus); bool Init(const FTPChannelCreationArgs& aOpenArgs); @@ -110,6 +118,7 @@ protected: // when we call ResumeForDiversion. bool mSuspendedForDiversion; nsRefPtr mObserver; + nsRefPtr mTabParent; }; } // namespace net From a4496fe0e35b40f542d0a025ac2d39866c18e5be Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Wed, 22 Jul 2015 10:07:00 -0700 Subject: [PATCH 39/90] Bug 1184781 - additional referrer tests - redirect. r=christophkerschbaumer --- dom/base/test/mochitest.ini | 1 + dom/base/test/referrer_testserver.sjs | 200 +++++++++++++++------- dom/base/test/test_referrer_redirect.html | 72 ++++++++ 3 files changed, 214 insertions(+), 59 deletions(-) create mode 100644 dom/base/test/test_referrer_redirect.html diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 20b74f82349c..e7862fb30332 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -802,5 +802,6 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' [test_file_negative_date.html] [test_nonascii_blob_url.html] [test_window_element_enumeration.html] +[test_referrer_redirect.html] [test_cloning_fileList.html] support-files = script_cloning_fileList.js iframe_cloning_fileList.html diff --git a/dom/base/test/referrer_testserver.sjs b/dom/base/test/referrer_testserver.sjs index 4e47174d1774..0299baaa1649 100644 --- a/dom/base/test/referrer_testserver.sjs +++ b/dom/base/test/referrer_testserver.sjs @@ -1,33 +1,51 @@ /* * Test server for iframe, anchor, and area referrer attributes. * https://bugzilla.mozilla.org/show_bug.cgi?id=1175736 +* Also server for further referrer tests such as redirecting tests +* bug 1174913, bug 1175736, bug 1184781 */ Components.utils.importGlobalProperties(["URLSearchParams"]); -const BASE_URL = 'example.com/tests/dom/base/test/referrer_testserver.sjs'; -const SHARED_KEY = 'referrer_testserver.sjs'; +const SJS = "referrer_testserver.sjs?"; +const BASE_URL = "example.com/tests/dom/base/test/" + SJS; +const SHARED_KEY = SJS; +const SAME_ORIGIN = "mochi.test:8888/tests/dom/base/test/" + SJS; +const CROSS_ORIGIN = "test1.example.com/tests/dom/base/test/" + SJS; + +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="); function createTestUrl(aPolicy, aAction, aName, aType) { - return 'http://' + BASE_URL + '?' + - 'ACTION=' + aAction + '&' + - 'policy=' + aPolicy + '&' + - 'name=' + aName + '&' + - 'type=' + aType; + return "http://" + BASE_URL + + "ACTION=" + aAction + "&" + + "policy=" + aPolicy + "&" + + "NAME=" + aName + "&" + + "type=" + aType; } // test page using iframe referrer attribute -function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod) { +// if aParams are set this creates a test where the iframe url is a redirect +function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aParams, aChangingMethod) { var metaString = ""; if (aMetaPolicy) { - metaString = ''; + metaString = ``; } - var changeString = ''; - if (aChangingMethod === 'setAttribute') { + var changeString = ""; + if (aChangingMethod === "setAttribute") { changeString = `document.getElementById("myframe").setAttribute("referrer", "${aNewAttributePolicy}")`; - } else if (aChangingMethod === 'property') { + } else if (aChangingMethod === "property") { changeString = `document.getElementById("myframe").referrer = "${aNewAttributePolicy}"`; } - var iFrameString = ``; + var iFrameString = ``; + var iframeUrl = ""; + if (aParams) { + aParams.delete("ACTION"); + aParams.append("ACTION", "redirectIframe"); + iframeUrl = "http://" + CROSS_ORIGIN + aParams.toString(); + } else { + iframeUrl = createTestUrl(aAttributePolicy, "test", aName, "iframe"); + } return ` @@ -42,7 +60,7 @@ function createIframeTestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAt document.getElementById("myframe").onload = function(){ parent.postMessage("childLoadComplete", "http://mochi.test:8888"); }; - document.getElementById("myframe").src = "${createTestUrl(aAttributePolicy, 'test', aName, 'iframe')}"; + document.getElementById("myframe").src = "${iframeUrl}"; }.bind(window), false); @@ -71,17 +89,17 @@ function buildAreaString(aMetaPolicy, aReferrerPolicy, aName, aRelString){ // test page using anchor or area referrer attribute function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aRel, aStringBuilder, aChangingMethod) { - var metaString = ''; + var metaString = ""; if (aMetaPolicy) { - metaString = ''; + metaString = ``; } - var changeString = ''; - if (aChangingMethod === 'setAttribute') { + var changeString = ""; + if (aChangingMethod === "setAttribute") { changeString = `document.getElementById("link").setAttribute("referrer", "${aNewAttributePolicy}")`; - } else if (aChangingMethod === 'property') { + } else if (aChangingMethod === "property") { changeString = `document.getElementById("link").referrer = "${aNewAttributePolicy}"`; } - var relString = ''; + var relString = ""; if (aRel) { relString = `rel="noreferrer"`; } @@ -102,41 +120,84 @@ function createAETestPageUsingRefferer(aMetaPolicy, aAttributePolicy, aNewAttrib `; } +// creates test page with img that is a redirect +function createRedirectImgTestCase(aParams, aAttributePolicy) { + var metaString = ""; + if (aParams.has("META_POLICY")) { + metaString = ``; + } + aParams.delete("ACTION"); + aParams.append("ACTION", "redirectImg"); + var imgUrl = "http://" + CROSS_ORIGIN + aParams.toString(); + + return ` + + + + ${metaString} + Test referrer policies on redirect (img) + + + + + + `; +} + function handleRequest(request, response) { var params = new URLSearchParams(request.queryString); - var action = params.get('ACTION'); + var action = params.get("ACTION"); - response.setHeader('Cache-Control', 'no-cache', false); - response.setHeader('Content-Type', 'text/html; charset=utf-8', false); - - if (action === 'resetState') { + if (action === "resetState") { setSharedState(SHARED_KEY, "{}"); response.write(""); return; } - if (action === 'get-test-results') { + if (action === "get-test-results") { // ?action=get-result - response.setHeader('Cache-Control', 'no-cache', false); - response.setHeader('Content-Type', 'text/plain', false); + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/plain", false); response.write(getSharedState(SHARED_KEY)); return; } - if (action === 'redirect') { + if (action === "redirect") { response.write(''); return; } - if (action === 'test') { + if (action === "redirectImg"){ + params.delete("ACTION"); + params.append("ACTION", "test"); + params.append("type", "img"); + // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect + response.setStatusLine("1.1", 302, "found"); + response.setHeader("Location", "http://" + CROSS_ORIGIN + params.toString(), false); + return; + } + if (action === "redirectIframe"){ + params.delete("ACTION"); + params.append("ACTION", "test"); + params.append("type", "iframe"); + // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect + response.setStatusLine("1.1", 302, "found"); + response.setHeader("Location", "http://" + CROSS_ORIGIN + params.toString(), false); + return; + } + if (action === "test") { // ?action=test&policy=origin&name=name - var policy = params.get('policy'); - var name = params.get('name'); - var type = params.get('type'); + var policy = params.get("policy"); + var name = params.get("NAME"); + var type = params.get("type"); var result = getSharedState(SHARED_KEY); result = result ? JSON.parse(result) : {}; var referrerLevel = "none"; var test = {} - if (request.hasHeader('Referer')) { + if (request.hasHeader("Referer")) { var referrer = request.getHeader("Referer"); if (referrer.indexOf("referrer_testserver") > 0) { referrerLevel = "full"; @@ -148,7 +209,7 @@ function handleRequest(request, response) { } test.referrer = referrer; } else { - test.referrer = ''; + test.referrer = ""; } test.policy = referrerLevel; test.expected = policy; @@ -157,23 +218,34 @@ function handleRequest(request, response) { setSharedState(SHARED_KEY, JSON.stringify(result)); + if (type === "img") { + // return image + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } if (type === "iframe") { // return iframe page response.write("I am the iframe"); - } else if (type === "link") { + return; + } + if (type === "link") { // forward link click to redirect URL to finish test - var loc = "http://" + BASE_URL + "?ACTION=redirect"; - response.setStatusLine('1.1', 302, 'Found'); - response.setHeader('Location', loc, false); + var loc = "http://" + BASE_URL + "ACTION=redirect"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", loc, false); } return; } + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html; charset=utf-8", false); + // parse test arguments and start test - var attributePolicy = params.get("ATTRIBUTE_POLICY") || ''; - var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || ''; - var metaPolicy = params.get("META_POLICY") || ''; - var rel = params.get("REL") || ''; + var attributePolicy = params.get("ATTRIBUTE_POLICY") || ""; + var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || ""; + var metaPolicy = params.get("META_POLICY") || ""; + var rel = params.get("REL") || ""; var name = params.get("NAME"); // anchor & area @@ -182,45 +254,55 @@ function handleRequest(request, response) { var _getAreaPage = _getPage.bind(null, buildAreaString); // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder - if (action === 'generate-anchor-policy-test') { + if (action === "generate-anchor-policy-test") { response.write(_getAnchorPage()); return; } - if (action === 'generate-anchor-changing-policy-test-set-attribute') { - response.write(_getAnchorPage('setAttribute')); + if (action === "generate-anchor-changing-policy-test-set-attribute") { + response.write(_getAnchorPage("setAttribute")); return; } - if (action === 'generate-anchor-changing-policy-test-property') { - response.write(_getAnchorPage('property')); + if (action === "generate-anchor-changing-policy-test-property") { + response.write(_getAnchorPage("property")); return; } - if (action === 'generate-area-policy-test') { + if (action === "generate-area-policy-test") { response.write(_getAreaPage()); return; } - if (action === 'generate-area-changing-policy-test-set-attribute') { - response.write(_getAreaPage('setAttribute')); + if (action === "generate-area-changing-policy-test-set-attribute") { + response.write(_getAreaPage("setAttribute")); return; } - if (action === 'generate-area-changing-policy-test-property') { - response.write(_getAreaPage('property')); + if (action === "generate-area-changing-policy-test-property") { + response.write(_getAreaPage("property")); return; } // iframe - _getPage = createIframeTestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name); + _getPage = createIframeTestPageUsingRefferer.bind(null, metaPolicy, attributePolicy, newAttributePolicy, name, ""); // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod - if (action === 'generate-iframe-policy-test') { + if (action === "generate-iframe-policy-test") { response.write(_getPage()); return; } - if (action === 'generate-iframe-changing-policy-test-set-attribute') { - response.write(_getPage('setAttribute')); + if (action === "generate-iframe-changing-policy-test-set-attribute") { + response.write(_getPage("setAttribute")); return; } - if (action === 'generate-iframe-changing-policy-test-property') { - response.write(_getPage('property')); + if (action === "generate-iframe-changing-policy-test-property") { + response.write(_getPage("property")); + return; + } + + // redirect tests with img and iframe + if (action === "generate-img-redirect-policy-test") { + response.write(createRedirectImgTestCase(params, attributePolicy)); + return; + } + if (action === "generate-iframe-redirect-policy-test") { + response.write(createIframeTestPageUsingRefferer(metaPolicy, attributePolicy, newAttributePolicy, name, params)); return; } diff --git a/dom/base/test/test_referrer_redirect.html b/dom/base/test/test_referrer_redirect.html new file mode 100644 index 000000000000..a00def9c7bf8 --- /dev/null +++ b/dom/base/test/test_referrer_redirect.html @@ -0,0 +1,72 @@ + + + + + Test anchor and area policy attribute for Bug 1184781 + + + + + + + + + + + + + From 08faa7ea9fe06e999eb3139126ce0d563ff41a6f Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 23 Jul 2015 13:11:04 -0400 Subject: [PATCH 40/90] Bug 1167651 - Made EGL initialize its ANGLE display using WARP if the system is blacklisted from using HW acceleration for WebGL ANGLE or if WebGL WARP is forced through a pref. ClientCanvasLayer is changed so that it will use shared surfaces only if the compositing device and the WebGL device are both WARP or both not WARP. Added a mIsWARP field to GLLibraryEGL so that this condition can be checked. r=jgilbert --- gfx/angle/src/libEGL/libEGL.cpp | 2 +- gfx/gl/GLContext.h | 8 +++ gfx/gl/GLContextEGL.h | 4 ++ gfx/gl/GLDefs.h | 5 ++ gfx/gl/GLLibraryEGL.cpp | 70 +++++++++++++++++++++---- gfx/gl/GLLibraryEGL.h | 8 ++- gfx/layers/client/ClientCanvasLayer.cpp | 3 ++ gfx/thebes/gfxPrefs.h | 1 + modules/libpref/init/all.js | 1 + 9 files changed, 90 insertions(+), 12 deletions(-) diff --git a/gfx/angle/src/libEGL/libEGL.cpp b/gfx/angle/src/libEGL/libEGL.cpp index 234b398f4c78..701ec2591774 100644 --- a/gfx/angle/src/libEGL/libEGL.cpp +++ b/gfx/angle/src/libEGL/libEGL.cpp @@ -122,7 +122,7 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis #if !defined(ANGLE_ENABLE_WINDOWS_STORE) // Validate the display device context - if (WindowFromDC(displayId) == NULL) + if (displayId != EGL_DEFAULT_DISPLAY && WindowFromDC(displayId) == NULL) { return egl::success(EGL_NO_DISPLAY); } diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index d48a0305cd7d..84a2a04f7f1a 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -196,6 +196,14 @@ public: return false; } + /** + * Returns true if the context is using WARP. This should only be overridden + * for an ANGLE implementation. + */ + virtual bool IsWARP() const { + return false; + } + /** * Return true if we are running on a OpenGL core profile context */ diff --git a/gfx/gl/GLContextEGL.h b/gfx/gl/GLContextEGL.h index 6574a300fcda..5a4d3b7222d6 100644 --- a/gfx/gl/GLContextEGL.h +++ b/gfx/gl/GLContextEGL.h @@ -66,6 +66,10 @@ public: return sEGLLibrary.IsANGLE(); } + virtual bool IsWARP() const override { + return sEGLLibrary.IsWARP(); + } + virtual bool BindTexImage() override; virtual bool ReleaseTexImage() override; diff --git a/gfx/gl/GLDefs.h b/gfx/gl/GLDefs.h index f0fe552f6e99..18faa79416bd 100644 --- a/gfx/gl/GLDefs.h +++ b/gfx/gl/GLDefs.h @@ -54,6 +54,11 @@ #define LOCAL_EGL_PRESERVED_RESOURCES 0x3030 #define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +// ANGLE_platform_angle_d3d +#define LOCAL_EGL_PLATFORM_ANGLE_ANGLE 0x3201 +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 +#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206 + #define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define LOCAL_GL_CONTEXT_LOST 0x9242 #define LOCAL_GL_CONTEXT_FLAGS_ARB 0x2094 diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 761c698650ce..a2024cd2225f 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -9,6 +9,7 @@ #include "mozilla/Assertions.h" #include "nsDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" +#include "nsIGfxInfo.h" #include "nsPrintfCString.h" #ifdef XP_WIN #include "nsWindowsHelpers.h" @@ -101,8 +102,36 @@ LoadLibraryForEGLOnWindows(const nsAString& filename) } return lib; } + #endif // XP_WIN +static EGLDisplay +GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType) +{ + EGLint attrib_list[] = { LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE, + LOCAL_EGL_NONE }; + EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_ANGLE_ANGLE, + displayType, + attrib_list); + + if (display == EGL_NO_DISPLAY) + return EGL_NO_DISPLAY; + + if (!egl.fInitialize(display, nullptr, nullptr)) + return EGL_NO_DISPLAY; + + return display; +} + +static bool +IsAccelAngleSupported(const nsCOMPtr& gfxInfo) +{ + int32_t angleSupport; + gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &angleSupport); + return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK); +} + static EGLDisplay GetAndInitDisplay(GLLibraryEGL& egl, void* displayType) { @@ -277,17 +306,41 @@ GLLibraryEGL::EnsureInitialized() } } #endif + mEGLDisplay = EGL_NO_DISPLAY; + // Check the ANGLE support the system has + nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); + mIsANGLE = IsExtensionSupported(ANGLE_platform_angle_d3d); - mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY); + //WARP ANGLE fallback path + if (mIsANGLE) { + bool accelAngleSupport = IsAccelAngleSupported(gfxInfo); + bool warpAngleSupport = gfxPlatform::CanUseDirect3D11ANGLE(); - const char* vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR); - if (vendor && (strstr(vendor, "TransGaming") != 0 || - strstr(vendor, "Google Inc.") != 0)) - { - mIsANGLE = true; + // Fallback to a WARP display if non-WARP is blacklisted, + // or if WARP is forced + bool shouldTryWARP = warpAngleSupport && !accelAngleSupport; + if (gfxPrefs::WebGLANGLEForceWARP()) { + shouldTryWARP = true; + } + + if (shouldTryWARP) { + mEGLDisplay = GetAndInitWARPDisplay(*this, + EGL_DEFAULT_DISPLAY); + if (mEGLDisplay != EGL_NO_DISPLAY) { + mIsWARP = true; + } + } + + // If falling back to WARP did not work, then fail + if (mEGLDisplay == EGL_NO_DISPLAY && !accelAngleSupport) { + NS_ERROR("Fallback WARP ANGLE context failed to initialize."); + return false; + } } - if (mIsANGLE) { + if (mEGLDisplay == EGL_NO_DISPLAY) { + mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY); + EGLDisplay newDisplay = EGL_NO_DISPLAY; // D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer @@ -308,10 +361,7 @@ GLLibraryEGL::EnsureInitialized() if (newDisplay != EGL_NO_DISPLAY) { DebugOnly success = fTerminate(mEGLDisplay); MOZ_ASSERT(success == LOCAL_EGL_TRUE); - mEGLDisplay = newDisplay; - - vendor = (char*)fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR); } } diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 58459f07df03..4de482e3e981 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -108,7 +108,8 @@ public: GLLibraryEGL() : mInitialized(false), mEGLLibrary(nullptr), - mIsANGLE(false) + mIsANGLE(false), + mIsWARP(false) { } @@ -469,6 +470,10 @@ public: return mIsANGLE; } + bool IsWARP() const { + return mIsWARP; + } + bool HasKHRImageBase() { return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base); } @@ -619,6 +624,7 @@ private: EGLDisplay mEGLDisplay; bool mIsANGLE; + bool mIsWARP; }; extern GLLibraryEGL sEGLLibrary; diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index c6e04bcf3164..585a606ac27c 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -98,7 +98,10 @@ ClientCanvasLayer::Initialize(const Data& aData) } case mozilla::layers::LayersBackend::LAYERS_D3D11: { #ifdef XP_WIN + // Enable surface sharing only if ANGLE and compositing devices + // are both WARP or both not WARP if (mGLContext->IsANGLE() && + (mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) && gfxWindowsPlatform::GetPlatform()->DoesD3D11TextureSharingWork()) { factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder, diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index e8dae5c8bd80..844c4eab38ba 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -381,6 +381,7 @@ private: DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500); DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false); DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false); + DECL_GFX_PREF(Once, "webgl.angle.force-warp", WebGLANGLEForceWARP, bool, false); DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat", WebGLDisableFailIfMajorPerformanceCaveat, bool, false); DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index b7ee3feb7879..20bd13480cfe 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4140,6 +4140,7 @@ pref("webgl.vendor-string-override", ""); #ifdef XP_WIN pref("webgl.angle.try-d3d11", true); pref("webgl.angle.force-d3d11", false); +pref("webgl.angle.force-warp", false); #endif #ifdef MOZ_WIDGET_GONK From 5c7d22e2ef5551c3b9e1812a49ea73d8fbc28edf Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 13 Jul 2015 15:23:26 -0400 Subject: [PATCH 41/90] Bug 1167651 - Added an initialization to mDoesD3D11TextureSharingWork for Windows 8 and later. r=bas --- gfx/thebes/gfxWindowsPlatform.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index c921384455f3..8126f677911a 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -2122,6 +2122,12 @@ gfxWindowsPlatform::InitD3D11Devices() mD3D11Status = FeatureStatus::Failed; } + // Only test for texture sharing on Windows 8 since it puts the device into + // an unusable state if used on Windows 7 + if (mD3D11Device && IsWin8OrLater()) { + mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device); + } + if (!mD3D11Device) { // We could not get a D3D11 compositor, and there's nothing more we can try. return; From 06c3dd12468f3d11c3ee9c686e08bfa40c63de14 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 23 Jul 2015 13:12:59 -0400 Subject: [PATCH 42/90] Bug 1167651 - Passed the forceEnabled pref from function to function down to GLLibraryEGL::EnsureInitialized. r=jgilbert --- dom/canvas/WebGLContext.cpp | 11 ++----- gfx/gl/GLContextProviderCGL.mm | 2 +- gfx/gl/GLContextProviderEGL.cpp | 4 +-- gfx/gl/GLContextProviderGLX.cpp | 2 +- gfx/gl/GLContextProviderImpl.h | 2 +- gfx/gl/GLContextProviderWGL.cpp | 2 +- gfx/gl/GLLibraryEGL.cpp | 57 ++++++++++++++++----------------- gfx/gl/GLLibraryEGL.h | 2 +- 8 files changed, 36 insertions(+), 46 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index ed3b3d8b0334..2db6fb4a13df 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -570,15 +570,8 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr& gfxInfo, nsRefPtr gl; #ifdef XP_WIN - if (!forceEnabled && - IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_ANGLE)) - { - webgl->GenerateWarning("Refused to create ANGLE OpenGL context" - " because of blacklisting."); - return nullptr; - } - - gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile); + gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile, + forceEnabled); if (!gl) { webgl->GenerateWarning("Error during ANGLE OpenGL init."); return nullptr; diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index 7727484b9b8c..490d534d01b5 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -287,7 +287,7 @@ CreateOffscreenFBOContext(bool requireCompatProfile) } already_AddRefed -GLContextProviderCGL::CreateHeadless(bool requireCompatProfile) +GLContextProviderCGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled) { nsRefPtr gl; gl = CreateOffscreenFBOContext(requireCompatProfile); diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 5c513806e76a..89c4fe9830fb 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -933,9 +933,9 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size) } already_AddRefed -GLContextProviderEGL::CreateHeadless(bool) +GLContextProviderEGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled) { - if (!sEGLLibrary.EnsureInitialized()) { + if (!sEGLLibrary.EnsureInitialized(forceEnabled)) { return nullptr; } diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index d1750da33a85..d2fdf6dbbcca 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -1215,7 +1215,7 @@ DONE_CREATING_PIXMAP: } already_AddRefed -GLContextProviderGLX::CreateHeadless(bool) +GLContextProviderGLX::CreateHeadless(bool requireCompatProfile, bool forceEnabled) { IntSize dummySize = IntSize(16, 16); nsRefPtr glContext = CreateOffscreenPixmapContext(dummySize); diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h index 48251f638743..7cadd0042839 100644 --- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -66,7 +66,7 @@ public: // Just create a context. We'll add offscreen stuff ourselves. static already_AddRefed - CreateHeadless(bool requireCompatProfile); + CreateHeadless(bool requireCompatProfile, bool forceEnabled = false); /** * Create wrapping Gecko GLContext for external gl context. diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index 8aeaf8c04fa6..2510adfc0621 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -607,7 +607,7 @@ CreateWindowOffscreenContext() } already_AddRefed -GLContextProviderWGL::CreateHeadless(bool) +GLContextProviderWGL::CreateHeadless(bool requireCompatProfile, bool forceEnabled) { if (!sWGLLib.EnsureInitialized()) { return nullptr; diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index a2024cd2225f..cd808254ca16 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -146,7 +146,7 @@ GetAndInitDisplay(GLLibraryEGL& egl, void* displayType) } bool -GLLibraryEGL::EnsureInitialized() +GLLibraryEGL::EnsureInitialized(bool forceAccel) { if (mInitialized) { return true; @@ -311,18 +311,19 @@ GLLibraryEGL::EnsureInitialized() nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); mIsANGLE = IsExtensionSupported(ANGLE_platform_angle_d3d); - //WARP ANGLE fallback path if (mIsANGLE) { bool accelAngleSupport = IsAccelAngleSupported(gfxInfo); bool warpAngleSupport = gfxPlatform::CanUseDirect3D11ANGLE(); - // Fallback to a WARP display if non-WARP is blacklisted, - // or if WARP is forced - bool shouldTryWARP = warpAngleSupport && !accelAngleSupport; + bool shouldTryAccel = forceAccel || accelAngleSupport; + bool shouldTryWARP = !shouldTryAccel && warpAngleSupport; if (gfxPrefs::WebGLANGLEForceWARP()) { shouldTryWARP = true; + shouldTryAccel = false; } + // Fallback to a WARP display if non-WARP is blacklisted, + // or if WARP is forced if (shouldTryWARP) { mEGLDisplay = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY); @@ -331,38 +332,34 @@ GLLibraryEGL::EnsureInitialized() } } - // If falling back to WARP did not work, then fail - if (mEGLDisplay == EGL_NO_DISPLAY && !accelAngleSupport) { + // If falling back to WARP did not work and we don't want to try + // using HW accelerated ANGLE, then fail + if (mEGLDisplay == EGL_NO_DISPLAY && !shouldTryAccel) { NS_ERROR("Fallback WARP ANGLE context failed to initialize."); return false; } + + // Hardware accelerated ANGLE path + if (mEGLDisplay == EGL_NO_DISPLAY && shouldTryAccel) { + // D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer + // manager, and it's pointless to try to fix it. We also don't try + // D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?) + if (gfxPrefs::LayersOffMainThreadCompositionEnabled() && + !gfxPrefs::LayersPreferD3D9()) + { + if (gfxPrefs::WebGLANGLEForceD3D11()) { + mEGLDisplay = GetAndInitDisplay(*this, + LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE); + } else if (gfxPrefs::WebGLANGLETryD3D11() && gfxPlatform::CanUseDirect3D11ANGLE()) { + mEGLDisplay = GetAndInitDisplay(*this, + LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE); + } + } + } } if (mEGLDisplay == EGL_NO_DISPLAY) { mEGLDisplay = GetAndInitDisplay(*this, EGL_DEFAULT_DISPLAY); - - EGLDisplay newDisplay = EGL_NO_DISPLAY; - - // D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer - // manager, and it's pointless to try to fix it. We also don't try - // D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?) - if (gfxPrefs::LayersOffMainThreadCompositionEnabled() && - !gfxPrefs::LayersPreferD3D9()) - { - if (gfxPrefs::WebGLANGLEForceD3D11()) { - newDisplay = GetAndInitDisplay(*this, - LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE); - } else if (gfxPrefs::WebGLANGLETryD3D11() && gfxPlatform::CanUseDirect3D11ANGLE()) { - newDisplay = GetAndInitDisplay(*this, - LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE); - } - } - - if (newDisplay != EGL_NO_DISPLAY) { - DebugOnly success = fTerminate(mEGLDisplay); - MOZ_ASSERT(success == LOCAL_EGL_TRUE); - mEGLDisplay = newDisplay; - } } InitExtensionsFromDisplay(mEGLDisplay); diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 4de482e3e981..225dc8fd1029 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -494,7 +494,7 @@ public: return IsExtensionSupported(EXT_create_context_robustness); } - bool EnsureInitialized(); + bool EnsureInitialized(bool forceAccel = false); void DumpEGLConfig(EGLConfig cfg); void DumpEGLConfigs(); From 4dac3678568f748b7301365e9e1676db7f1d2e7c Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 21 Jul 2015 14:57:00 +0200 Subject: [PATCH 43/90] Bug 1186213 - Add an API to deep-freeze the result of Cu.cloneInto. r=gkrizsanits --- js/xpconnect/src/ExportHelpers.cpp | 12 ++++++- js/xpconnect/src/xpcprivate.h | 7 +++- .../tests/unit/test_deepFreezeClone.js | 33 +++++++++++++++++++ js/xpconnect/tests/unit/xpcshell.ini | 1 + 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 js/xpconnect/tests/unit/test_deepFreezeClone.js diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 4dede255a1da..1f1b75f1905f 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -271,7 +271,17 @@ StackScopedClone(JSContext* cx, StackScopedCloneOptions& options, } // Now recreate the clones in the target compartment. - return buffer.read(cx, val, &gStackScopedCloneCallbacks, &data); + if (!buffer.read(cx, val, &gStackScopedCloneCallbacks, &data)) + return false; + + // Deep-freeze if requested. + if (options.deepFreeze && val.isObject()) { + RootedObject obj(cx, &val.toObject()); + if (!JS_DeepFreezeObject(cx, obj)) + return false; + } + + return true; } // Note - This function mirrors the logic of CheckPassToChrome in diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 70205ee0dead..fbad24cec8c6 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3567,11 +3567,13 @@ public: : OptionsBase(cx, options) , wrapReflectors(false) , cloneFunctions(false) + , deepFreeze(false) { } virtual bool Parse() { return ParseBoolean("wrapReflectors", &wrapReflectors) && - ParseBoolean("cloneFunctions", &cloneFunctions); + ParseBoolean("cloneFunctions", &cloneFunctions) && + ParseBoolean("deepFreeze", &deepFreeze); } // When a reflector is encountered, wrap it rather than aborting the clone. @@ -3580,6 +3582,9 @@ public: // When a function is encountered, clone it (exportFunction-style) rather than // aborting the clone. bool cloneFunctions; + + // If true, the resulting object is deep-frozen after being cloned. + bool deepFreeze; }; JSObject* diff --git a/js/xpconnect/tests/unit/test_deepFreezeClone.js b/js/xpconnect/tests/unit/test_deepFreezeClone.js new file mode 100644 index 000000000000..67ea4e66df64 --- /dev/null +++ b/js/xpconnect/tests/unit/test_deepFreezeClone.js @@ -0,0 +1,33 @@ +const Cu = Components.utils; + +function checkThrows(f, rgxp) { try { f(); do_check_false(); } catch (e) { do_check_true(rgxp.test(e)); } } + +var o = { foo: 42, bar : { tick: 'tock' } }; +function checkClone(clone, frozen) { + var waived = Cu.waiveXrays(clone); + function touchFoo() { "use strict"; waived.foo = 12; do_check_eq(waived.foo, 12); } + function touchBar() { "use strict"; waived.bar.tick = 'tack'; do_check_eq(waived.bar.tick, 'tack'); } + function addProp() { "use strict"; waived.newProp = 100; do_check_eq(waived.newProp, 100); } + if (!frozen) { + touchFoo(); + touchBar(); + addProp(); + } else { + checkThrows(touchFoo, /read-only/); + checkThrows(touchBar, /read-only/); + checkThrows(addProp, /extensible/); + } + + var desc = Object.getOwnPropertyDescriptor(waived, 'foo'); + do_check_eq(desc.writable, !frozen); + do_check_eq(desc.configurable, !frozen); + desc = Object.getOwnPropertyDescriptor(waived.bar, 'tick'); + do_check_eq(desc.writable, !frozen); + do_check_eq(desc.configurable, !frozen); +} + +function run_test() { + var sb = new Cu.Sandbox(null); + checkClone(Cu.waiveXrays(Cu.cloneInto(o, sb)), false); + checkClone(Cu.cloneInto(o, sb, { deepFreeze: true }), true); +} diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index fa6bb7c96f03..cbe82fdf9fa7 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -62,6 +62,7 @@ support-files = [test_bug1170311.js] [test_bug_442086.js] [test_callFunctionWithAsyncStack.js] +[test_deepFreezeClone.js] [test_file.js] [test_blob.js] [test_blob2.js] From bf15291935be1bd2e7af0c9b49f9219f1331a7c5 Mon Sep 17 00:00:00 2001 From: Kilik Kuo Date: Wed, 22 Jul 2015 19:07:14 +0800 Subject: [PATCH 44/90] Bug 1186375 - Add GMP EME render flags and APIs for query. r=cpearce --- dom/media/eme/CDMCaps.cpp | 12 ++++++++++++ dom/media/eme/CDMCaps.h | 3 +++ dom/media/gmp/gmp-api/gmp-decryption.h | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/dom/media/eme/CDMCaps.cpp b/dom/media/eme/CDMCaps.cpp index b5c677385dd8..c8042375f7bf 100644 --- a/dom/media/eme/CDMCaps.cpp +++ b/dom/media/eme/CDMCaps.cpp @@ -184,6 +184,18 @@ CDMCaps::AutoLock::AreCapsKnown() return mData.mCaps != 0; } +bool +CDMCaps::AutoLock::CanRenderAudio() +{ + return mData.HasCap(GMP_EME_CAP_RENDER_AUDIO); +} + +bool +CDMCaps::AutoLock::CanRenderVideo() +{ + return mData.HasCap(GMP_EME_CAP_RENDER_VIDEO); +} + bool CDMCaps::AutoLock::CanDecryptAndDecodeAudio() { diff --git a/dom/media/eme/CDMCaps.h b/dom/media/eme/CDMCaps.h index ad9ad16331c3..7c9682706c3c 100644 --- a/dom/media/eme/CDMCaps.h +++ b/dom/media/eme/CDMCaps.h @@ -75,6 +75,9 @@ public: // GMP_EME_CAP_* flags from gmp-decryption.h. void SetCaps(uint64_t aCaps); + bool CanRenderAudio(); + bool CanRenderVideo(); + bool CanDecryptAndDecodeAudio(); bool CanDecryptAndDecodeVideo(); diff --git a/dom/media/gmp/gmp-api/gmp-decryption.h b/dom/media/gmp/gmp-api/gmp-decryption.h index 0db631457e61..9956ba8e25dc 100644 --- a/dom/media/gmp/gmp-api/gmp-decryption.h +++ b/dom/media/gmp/gmp-api/gmp-decryption.h @@ -125,6 +125,10 @@ typedef int64_t GMPTimestamp; #define GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO (uint64_t(1) << 2) #define GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO (uint64_t(1) << 3) +// Capability; CDM can decrypt and then decode and render encrypted buffers +#define GMP_EME_CAP_RENDER_AUDIO (uint64_t(1) << 4) +#define GMP_EME_CAP_RENDER_VIDEO (uint64_t(1) << 5) + // Callbacks to be called from the CDM. Threadsafe. class GMPDecryptorCallback { public: From cc94d65dda79eb27ccf51b7120b4c791f5eb4f3e Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 23 Jul 2015 17:34:21 +0900 Subject: [PATCH 45/90] Bug 1177951 - Use tooltool on b2g desktop and mulet taskcluster builds. r=wcosta,r=garndt --- .../scripts/builder/install-packages.sh | 27 +++++-------------- testing/taskcluster/tasks/build.yml | 2 ++ .../tasks/builds/b2g_desktop_base.yml | 3 +-- .../taskcluster/tasks/builds/mulet_linux.yml | 1 + 4 files changed, 10 insertions(+), 23 deletions(-) diff --git a/testing/taskcluster/scripts/builder/install-packages.sh b/testing/taskcluster/scripts/builder/install-packages.sh index 2a290ea1c578..710881eb3c06 100755 --- a/testing/taskcluster/scripts/builder/install-packages.sh +++ b/testing/taskcluster/scripts/builder/install-packages.sh @@ -2,26 +2,11 @@ gecko_dir=$1 test -d $gecko_dir +test -n "$TOOLTOOL_CACHE" +test -n "$TOOLTOOL_MANIFEST" +test -n "$TOOLTOOL_REPO" +test -n "$TOOLTOOL_REV" -if [ ! -d "$gecko_dir/gcc" ]; then - cd $gecko_dir - curl https://s3-us-west-2.amazonaws.com/test-caching/packages/gcc.tar.xz | tar Jx - cd - -fi +tc-vcs checkout $gecko_dir/tooltool $TOOLTOOL_REPO $TOOLTOOL_REPO $TOOLTOOL_REV -if [ ! -d "$gecko_dir/sccache" ]; then - cd $gecko_dir - curl https://s3-us-west-2.amazonaws.com/test-caching/packages/sccache.tar.bz2 | tar jx - cd - -fi - -# Remove cached moztt directory if it exists when a user supplied a git url/revision -if [ ! -z $MOZTT_GIT_URL ] || [ ! -z $MOZTT_REVISION ]; then - echo "Removing cached moztt package" - rm -rf moztt -fi - -moztt_url=${MOZTT_GIT_URL:=https://github.com/mozilla-b2g/moztt} -moztt_revision=${MOZTT_REVISION:=master} - -tc-vcs checkout $gecko_dir/moztt $moztt_url $moztt_url $moztt_revision +(cd $gecko_dir; python $gecko_dir/tooltool/tooltool.py --url https://api.pub.build.mozilla.org/tooltool/ --overwrite -m $gecko_dir/$TOOLTOOL_MANIFEST fetch -c $TOOLTOOL_CACHE) diff --git a/testing/taskcluster/tasks/build.yml b/testing/taskcluster/tasks/build.yml index 02c2245227b4..79a9764249d9 100644 --- a/testing/taskcluster/tasks/build.yml +++ b/testing/taskcluster/tasks/build.yml @@ -55,6 +55,8 @@ task: MOZHARNESS_REPOSITORY: '{{mozharness_repository}}' MOZHARNESS_REV: '{{mozharness_rev}}' MOZHARNESS_REF: '{{mozharness_ref}}' + TOOLTOOL_REPO: 'https://github.com/mozilla/build-tooltool' + TOOLTOOL_REV: 'master' extra: index: diff --git a/testing/taskcluster/tasks/builds/b2g_desktop_base.yml b/testing/taskcluster/tasks/builds/b2g_desktop_base.yml index b86b35f428fa..2651e141c340 100644 --- a/testing/taskcluster/tasks/builds/b2g_desktop_base.yml +++ b/testing/taskcluster/tasks/builds/b2g_desktop_base.yml @@ -9,8 +9,7 @@ task: payload: env: MOZCONFIG: 'b2g/config/mozconfigs/linux64_gecko/nightly' - MOZTT_GIT_URL: '{{moztt_git_url}}' - MOZTT_REVISION: '{{moztt_revision}}' + TOOLTOOL_MANIFEST: 'b2g/config/tooltool-manifests/linux64/releng.manifest' command: - /bin/bash diff --git a/testing/taskcluster/tasks/builds/mulet_linux.yml b/testing/taskcluster/tasks/builds/mulet_linux.yml index 158b718fcf6a..572c47051dcd 100644 --- a/testing/taskcluster/tasks/builds/mulet_linux.yml +++ b/testing/taskcluster/tasks/builds/mulet_linux.yml @@ -29,6 +29,7 @@ task: env: MOZCONFIG: 'b2g/dev/config/mozconfigs/linux64/mulet' + TOOLTOOL_MANIFEST: 'b2g/dev/config/tooltool-manifests/linux64/releng.manifest' maxRunTime: 3600 From 05aa617f653b58ce2507e3681451e9e8d7c6884b Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Wed, 22 Jul 2015 16:51:38 -0700 Subject: [PATCH 46/90] Bug 1185198 - use port 9 for TCP active candidates. r=bwc --HG-- extra : transplant_source : %A1E%BEA%E6%60%E6%BE%12%CD%E6%04%F0%0C%DF%FB/%D2%28%80 --- media/mtransport/test/ice_unittest.cpp | 19 ++++++++++++++++--- .../third_party/nICEr/src/ice/ice_candidate.c | 3 +++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/media/mtransport/test/ice_unittest.cpp b/media/mtransport/test/ice_unittest.cpp index 47211229a170..44de49c01b8f 100644 --- a/media/mtransport/test/ice_unittest.cpp +++ b/media/mtransport/test/ice_unittest.cpp @@ -65,9 +65,9 @@ static unsigned int kDefaultTimeout = 7000; //TODO(nils@mozilla.com): This should get replaced with some non-external //solution like discussed in bug 860775. -const std::string kDefaultStunServerAddress((char *)"52.11.16.249"); +const std::string kDefaultStunServerAddress((char *)"52.27.56.60"); const std::string kDefaultStunServerHostname( - (char *)"global.stun.twilio.com"); + (char *)"global.stun.twillio.com"); const std::string kBogusStunServerHostname( (char *)"stun-server-nonexistent.invalid"); const uint16_t kDefaultStunServerPort=3478; @@ -1672,7 +1672,8 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) { peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort); peer_->SetDNSResolver(); Gather(); - // TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094 + ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "typ srflx raddr")); } TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddressTcp) { @@ -1685,6 +1686,11 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddressTcp) { kNrIceTransportTcp); peer_->SetDNSResolver(); Gather(); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype passive")); + ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype passive", " 9 ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype so")); + ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype so", " 9 ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype active", " 9 ")); } TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) { @@ -1696,6 +1702,8 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) { peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort); peer_->SetDNSResolver(); Gather(); + ASSERT_TRUE(StreamHasMatchingCandidate(0, " UDP ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "typ srflx raddr")); } TEST_F(IceGatherTest, TestGatherDNSStunServerHostnameTcp) { @@ -1704,6 +1712,11 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerHostnameTcp) { kNrIceTransportTcp); peer_->SetDNSResolver(); Gather(); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype passive")); + ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype passive", " 9 ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype so")); + ASSERT_FALSE(StreamHasMatchingCandidate(0, "tcptype so", " 9 ")); + ASSERT_TRUE(StreamHasMatchingCandidate(0, "tcptype active", " 9 ")); } TEST_F(IceGatherTest, TestGatherDNSStunServerHostnameBothUdpTcp) { diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c index 7d76b02a0246..4f69a27d9e02 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c +++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c @@ -929,6 +929,9 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma ABORT(r); if(r=nr_transport_addr_get_port(&cand->addr,&port)) ABORT(r); + /* https://tools.ietf.org/html/rfc6544#section-4.5 */ + if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type==TCP_TYPE_ACTIVE) + port=9; snprintf(attr,maxlen,"candidate:%s %d %s %u %s %d typ %s", cand->foundation, cand->component_id, cand->addr.protocol==IPPROTO_UDP?"UDP":"TCP",cand->priority, addr, port, nr_ctype_name(cand->type)); From 3544a8c61389bb159da92d985411f4592d4eb036 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 21 Jul 2015 16:36:10 -0400 Subject: [PATCH 47/90] Bug 1186142 - Make selector arg optional on PeerConnection.getStats(). r=bz --HG-- extra : transplant_source : %D9Y%3EecN%F2AJ%01%0A%D6%188.p%11%9C%29%C9 --- dom/media/tests/mochitest/templates.js | 12 ++++++------ dom/webidl/RTCPeerConnection.webidl | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/media/tests/mochitest/templates.js b/dom/media/tests/mochitest/templates.js index 303e36f12c9a..445750ce8f53 100644 --- a/dom/media/tests/mochitest/templates.js +++ b/dom/media/tests/mochitest/templates.js @@ -455,31 +455,31 @@ var commandsPeerConnectionOfferAnswer = [ }, function PC_LOCAL_CHECK_STATS(test) { - return test.pcLocal.getStats(null).then(stats => { + return test.pcLocal.getStats().then(stats => { test.pcLocal.checkStats(stats, test.steeplechase); }); }, function PC_REMOTE_CHECK_STATS(test) { - test.pcRemote.getStats(null).then(stats => { + test.pcRemote.getStats().then(stats => { test.pcRemote.checkStats(stats, test.steeplechase); }); }, function PC_LOCAL_CHECK_ICE_CONNECTION_TYPE(test) { - test.pcLocal.getStats(null).then(stats => { + test.pcLocal.getStats().then(stats => { test.pcLocal.checkStatsIceConnectionType(stats); }); }, function PC_REMOTE_CHECK_ICE_CONNECTION_TYPE(test) { - test.pcRemote.getStats(null).then(stats => { + test.pcRemote.getStats().then(stats => { test.pcRemote.checkStatsIceConnectionType(stats); }); }, function PC_LOCAL_CHECK_ICE_CONNECTIONS(test) { - test.pcLocal.getStats(null).then(stats => { + test.pcLocal.getStats().then(stats => { test.pcLocal.checkStatsIceConnections(stats, test._offer_constraints, test._offer_options, @@ -488,7 +488,7 @@ var commandsPeerConnectionOfferAnswer = [ }, function PC_REMOTE_CHECK_ICE_CONNECTIONS(test) { - test.pcRemote.getStats(null).then(stats => { + test.pcRemote.getStats().then(stats => { test.pcRemote.checkStatsIceConnections(stats, test._offer_constraints, test._offer_options, diff --git a/dom/webidl/RTCPeerConnection.webidl b/dom/webidl/RTCPeerConnection.webidl index 195c71bdc587..6004f01d494c 100644 --- a/dom/webidl/RTCPeerConnection.webidl +++ b/dom/webidl/RTCPeerConnection.webidl @@ -144,7 +144,7 @@ interface mozRTCPeerConnection : EventTarget { attribute EventHandler onremovestream; attribute EventHandler oniceconnectionstatechange; - Promise getStats (MediaStreamTrack? selector); + Promise getStats (optional MediaStreamTrack? selector); // Data channel. RTCDataChannel createDataChannel (DOMString label, From 0012786ede541afd4afd6b2d0816b10b50b0cdf9 Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Wed, 22 Jul 2015 10:54:11 -0700 Subject: [PATCH 48/90] Bug 1186339 - skip STUN/TURN servers with non-matching IP versions for TCP sockets. r=bwc --HG-- extra : transplant_source : %3E%0E8%D9%D8%A4%03J%E42%AE%0C%3D%C0o%84%D7%40dl --- .../mtransport/third_party/nICEr/src/ice/ice_candidate.c | 2 +- .../third_party/nICEr/src/net/nr_socket_multi_tcp.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c index 4f69a27d9e02..381414bd9db8 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c +++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c @@ -555,7 +555,7 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) { if(cand->base.ip_version != cand->stun_server->u.addr.ip_version) { - r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%d) than STUN/TURN server (%d).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version); + r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%u) than STUN/TURN server (%u).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version); ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */ } diff --git a/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c b/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c index 3eb3d74b0c69..b0300de51173 100644 --- a/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c +++ b/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c @@ -170,8 +170,15 @@ static int nr_socket_multi_tcp_create_stun_server_socket( nr_tcp_socket_ctx *tcp_socket_ctx=0; nr_socket * nrsock; - if (stun_server->transport!=IPPROTO_TCP) + if (stun_server->transport!=IPPROTO_TCP) { + r_log(LOG_ICE,LOG_INFO,"%s:%d function %s skipping UDP STUN server(addr:%s)",__FILE__,__LINE__,__FUNCTION__,stun_server->u.addr.as_string); ABORT(R_BAD_ARGS); + } + + if (stun_server->u.addr.ip_version!=addr->ip_version) { + r_log(LOG_ICE,LOG_INFO,"%s:%d function %s skipping STUN with different IP version (%u) than local socket (%u),",__FILE__,__LINE__,__FUNCTION__,stun_server->u.addr.ip_version,addr->ip_version); + ABORT(R_BAD_ARGS); + } if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory,addr, &nrsock))) ABORT(r); From 41efe494ad3d6d348f69ee1a51e4921fc32355fb Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 24 Jul 2015 11:45:50 +0200 Subject: [PATCH 49/90] Bug 1183093 - Uninitialised value use in Probe::Trigger. r=dteller. --- xpcom/build/perfprobe.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xpcom/build/perfprobe.cpp b/xpcom/build/perfprobe.cpp index 4cb3ddc52422..c1713c50ec21 100644 --- a/xpcom/build/perfprobe.cpp +++ b/xpcom/build/perfprobe.cpp @@ -118,10 +118,12 @@ ProbeManager::~ProbeManager() ProbeManager::ProbeManager(const nsCID& aApplicationUID, const nsACString& aApplicationName) - : mApplicationUID(aApplicationUID) + : mIsActive(false) + , mApplicationUID(aApplicationUID) , mApplicationName(aApplicationName) , mSessionHandle(0) , mRegistrationHandle(0) + , mInitialized(false) { #if defined(MOZ_LOGGING) char cidStr[NSID_LENGTH]; From 3c61547e30e3ac90abb99100f626b0b8e7f3f676 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Thu, 23 Jul 2015 19:23:49 +0300 Subject: [PATCH 50/90] Bug 1180382, update display port after, not before Gecko has scrolled the page to the #hashtag, r=kats --- mobile/android/chrome/content/browser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 9f8cdf87b6ce..234d05aedb35 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -4683,7 +4683,9 @@ Tab.prototype = { this.contentDocumentIsDisplayed = false; this.hasTouchListener = false; } else { - this.sendViewportUpdate(); + setTimeout(function() { + this.sendViewportUpdate(); + }.bind(this), 0); } }, From c72c2b7e2e8f029fb5f7af4f348184656ce98dd3 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 24 Jul 2015 07:10:29 -0400 Subject: [PATCH 51/90] Bug 1186844 - deploy updates to talos. r=parkouss --- testing/talos/talos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/talos/talos.json b/testing/talos/talos.json index 8ec6bbdf17c3..41a16d16c1be 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -5,7 +5,7 @@ }, "global": { "talos_repo": "https://hg.mozilla.org/build/talos", - "talos_revision": "deca965654a3" + "talos_revision": "e47c566d1c11" }, "extra_options": { "android": [ "--apkPath=%(apk_path)s" ] From e3ad172cbaba2f364f86f68a1bb8c9aa283b0e7b Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Jul 2015 19:37:18 +0100 Subject: [PATCH 52/90] Bug 1184557 - part 1 - StructuredCloneHelper class for window to window postMessage, r=smaug --- dom/base/PostMessageEvent.cpp | 278 +---------------------------- dom/base/PostMessageEvent.h | 58 +----- dom/base/StructuredCloneHelper.cpp | 233 +++++++++++++++++++++++- dom/base/StructuredCloneHelper.h | 105 +++++++++++ dom/base/nsGlobalWindow.cpp | 2 +- 5 files changed, 343 insertions(+), 333 deletions(-) diff --git a/dom/base/PostMessageEvent.cpp b/dom/base/PostMessageEvent.cpp index 97b4f4bdb1fb..9f0a1a56875b 100644 --- a/dom/base/PostMessageEvent.cpp +++ b/dom/base/PostMessageEvent.cpp @@ -23,246 +23,6 @@ namespace mozilla { namespace dom { -namespace { - -struct StructuredCloneInfo -{ - PostMessageEvent* event; - nsPIDOMWindow* window; - - // This hashtable contains the transferred ports - used to avoid duplicates. - nsTArray> transferredPorts; - - // This array is populated when the ports are cloned. - nsTArray> clonedPorts; -}; - -} // namespace - -const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = { - PostMessageEvent::ReadStructuredClone, - PostMessageEvent::WriteStructuredClone, - nullptr, - PostMessageEvent::ReadTransferStructuredClone, - PostMessageEvent::TransferStructuredClone, - PostMessageEvent::FreeTransferStructuredClone -}; - -/* static */ JSObject* -PostMessageEvent::ReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_BLOB) { - NS_ASSERTION(!data, "Data should be empty"); - - // What we get back from the reader is a BlobImpl. - // From that we create a new File. - BlobImpl* blobImpl; - if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { - MOZ_ASSERT(blobImpl); - - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(cx); - { - nsRefPtr blob = Blob::Create(scInfo->window, blobImpl); - if (!ToJSValue(cx, blob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - if (tag == SCTAG_DOM_FILELIST) { - NS_ASSERTION(!data, "Data should be empty"); - - // What we get back from the reader is a FileListClonedData. - // From that we create a new FileList. - FileListClonedData* fileListClonedData; - if (JS_ReadBytes(reader, &fileListClonedData, sizeof(fileListClonedData))) { - MOZ_ASSERT(fileListClonedData); - - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(cx); - { - nsRefPtr fileList = - FileList::Create(scInfo->window, fileListClonedData); - if (!fileList || !ToJSValue(cx, fileList, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->read(cx, reader, tag, data, nullptr); - } - - return nullptr; -} - -/* static */ bool -PostMessageEvent::WriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - // See if this is a File/Blob object. - { - Blob* blob = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && - JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { - scInfo->event->StoreISupports(blobImpl); - return true; - } - } - } - - // See if this is a FileList object. - { - FileList* fileList = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, obj, fileList))) { - nsRefPtr fileListClonedData = - fileList->CreateClonedData(); - MOZ_ASSERT(fileListClonedData); - FileListClonedData* ptr = fileListClonedData.get(); - if (JS_WriteUint32Pair(writer, SCTAG_DOM_FILELIST, 0) && - JS_WriteBytes(writer, &ptr, sizeof(ptr))) { - scInfo->event->StoreISupports(fileListClonedData); - return true; - } - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->write(cx, writer, obj, nullptr); - } - - return false; -} - -/* static */ bool -PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* aData, - uint64_t aExtraData, - void* aClosure, - JS::MutableHandle returnObject) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(!aData); - // aExtraData is the index of this port identifier. - ErrorResult rv; - nsRefPtr port = - MessagePort::Create(scInfo->window, - scInfo->event->GetPortIdentifier(aExtraData), - rv); - if (NS_WARN_IF(rv.Failed())) { - return false; - } - - scInfo->clonedPorts.AppendElement(port); - - JS::Rooted value(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - returnObject.set(&value.toObject()); - return true; - } - - return false; -} - -/* static */ bool -PostMessageEvent::TransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - if (scInfo->transferredPorts.Contains(port)) { - // No duplicates. - return false; - } - - // We use aExtraData to store the index of this new port identifier. - MessagePortIdentifier* identifier = - scInfo->event->NewPortIdentifier(aExtraData); - - if (!port->CloneAndDisentangle(*identifier)) { - return false; - } - - scInfo->transferredPorts.AppendElement(port); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - - return true; - } - - return false; -} - -/* static */ void -PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void *aContent, - uint64_t aExtraData, - void* aClosure) -{ - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(aClosure); - MOZ_ASSERT(!aContent); - - StructuredCloneInfo* scInfo = static_cast(aClosure); - MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData)); - } -} - PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource, const nsAString& aCallerOrigin, nsGlobalWindow* aTargetWindow, @@ -282,20 +42,6 @@ PostMessageEvent::~PostMessageEvent() MOZ_COUNT_DTOR(PostMessageEvent); } -const MessagePortIdentifier& -PostMessageEvent::GetPortIdentifier(uint64_t aId) -{ - MOZ_ASSERT(aId < mPortIdentifiers.Length()); - return mPortIdentifiers[aId]; -} - -MessagePortIdentifier* -PostMessageEvent::NewPortIdentifier(uint64_t* aPosition) -{ - *aPosition = mPortIdentifiers.Length(); - return mPortIdentifiers.AppendElement(); -} - NS_IMETHODIMP PostMessageEvent::Run() { @@ -347,13 +93,9 @@ PostMessageEvent::Run() } } - // Deserialize the structured clone data JS::Rooted messageData(cx); - StructuredCloneInfo scInfo; - scInfo.event = this; - scInfo.window = targetWindow; - - if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) { + nsCOMPtr window = targetWindow.get(); + if (!Read(window, cx, &messageData)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } @@ -368,7 +110,7 @@ PostMessageEvent::Run() EmptyString(), mSource); event->SetPorts(new MessagePortList(static_cast(event.get()), - scInfo.clonedPorts)); + GetTransferredPorts())); // We can't simply call dispatchEvent on the window because doing so ends // up flipping the trusted bit on the event, and we don't want that to @@ -392,19 +134,5 @@ PostMessageEvent::Run() return NS_OK; } -bool -PostMessageEvent::Write(JSContext* aCx, JS::Handle aMessage, - JS::Handle aTransfer, nsPIDOMWindow* aWindow) -{ - // We *must* clone the data here, or the JS::Value could be modified - // by script - StructuredCloneInfo scInfo; - scInfo.event = this; - scInfo.window = aWindow; - - return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks, - &scInfo); -} - } // namespace dom } // namespace mozilla diff --git a/dom/base/PostMessageEvent.h b/dom/base/PostMessageEvent.h index 80cd5da10e36..2e4eb0812220 100644 --- a/dom/base/PostMessageEvent.h +++ b/dom/base/PostMessageEvent.h @@ -7,7 +7,7 @@ #ifndef mozilla_dom_PostMessageEvent_h #define mozilla_dom_PostMessageEvent_h -#include "js/StructuredClone.h" +#include "mozilla/dom/StructuredCloneHelper.h" #include "nsCOMPtr.h" #include "nsRefPtr.h" #include "nsTArray.h" @@ -28,6 +28,7 @@ class MessagePortIdentifier; * which asynchronously creates and dispatches events. */ class PostMessageEvent final : public nsRunnable + , public StructuredCloneHelper { public: NS_DECL_NSIRUNNABLE @@ -38,69 +39,14 @@ public: nsIPrincipal* aProvidedPrincipal, bool aTrustedCaller); - bool Write(JSContext* aCx, JS::Handle aMessage, - JS::Handle aTransfer, nsPIDOMWindow* aWindow); - private: ~PostMessageEvent(); - const MessagePortIdentifier& GetPortIdentifier(uint64_t aId); - - MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition); - - bool StoreISupports(nsISupports* aSupports) - { - mSupportsArray.AppendElement(aSupports); - return true; - } - - static JSObject* - ReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure); - - static bool - WriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure); - - static bool - ReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* aData, - uint64_t aExtraData, - void* aClosure, - JS::MutableHandle returnObject); - - static bool - TransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData); - - static void - FreeTransferStructuredClone(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void *aContent, - uint64_t aExtraData, - void* aClosure); - - static const JSStructuredCloneCallbacks sPostMessageCallbacks; - - JSAutoStructuredCloneBuffer mBuffer; nsRefPtr mSource; nsString mCallerOrigin; nsRefPtr mTargetWindow; nsCOMPtr mProvidedPrincipal; bool mTrustedCaller; - nsTArray> mSupportsArray; - nsTArray mPortIdentifiers; }; } // namespace dom diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index be8306b672c5..fd8e984406a6 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -6,6 +6,10 @@ #include "StructuredCloneHelper.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/FileListBinding.h" +#include "mozilla/dom/StructuredCloneTags.h" + namespace mozilla { namespace dom { @@ -99,6 +103,8 @@ const JSStructuredCloneCallbacks gCallbacks = { } // anonymous namespace +// StructuredCloneHelperInternal class + bool StructuredCloneHelperInternal::Write(JSContext* aCx, JS::Handle aValue) @@ -109,6 +115,17 @@ StructuredCloneHelperInternal::Write(JSContext* aCx, return mBuffer->write(aCx, aValue, &gCallbacks, this); } +bool +StructuredCloneHelperInternal::Write(JSContext* aCx, + JS::Handle aValue, + JS::Handle aTransfer) +{ + MOZ_ASSERT(!mBuffer, "Double Write is not allowed"); + + mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this); + return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this); +} + bool StructuredCloneHelperInternal::Read(JSContext* aCx, JS::MutableHandle aValue) @@ -132,7 +149,6 @@ StructuredCloneHelperInternal::ReadTransferCallback(JSContext* aCx, return false; } - bool StructuredCloneHelperInternal::WriteTransferCallback(JSContext* aCx, JS::Handle aObj, @@ -154,5 +170,220 @@ StructuredCloneHelperInternal::FreeTransferCallback(uint32_t aTag, MOZ_CRASH("Nothing to free."); } +// StructuredCloneHelper class + +StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags) + : mFlags(aFlags) + , mParent(nullptr) +{} + +StructuredCloneHelper::~StructuredCloneHelper() +{} + +bool +StructuredCloneHelper::Write(JSContext* aCx, + JS::Handle aValue, + JS::Handle aTransfer) +{ + bool ok = StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer); + mTransferringPort.Clear(); + return ok; +} + +bool +StructuredCloneHelper::Read(nsISupports* aParent, + JSContext* aCx, + JS::MutableHandle aValue) +{ + mozilla::AutoRestore guard(mParent); + mParent = aParent; + + return StructuredCloneHelperInternal::Read(aCx, aValue); +} + +JSObject* +StructuredCloneHelper::ReadCallback(JSContext* aCx, + JSStructuredCloneReader* aReader, + uint32_t aTag, + uint32_t aIndex) +{ + if (aTag == SCTAG_DOM_BLOB) { + MOZ_ASSERT(!(mFlags & eBlobNotSupported)); + + BlobImpl* blobImpl; + if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) { + MOZ_ASSERT(blobImpl); + + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(aCx); + { + nsRefPtr blob = Blob::Create(mParent, blobImpl); + if (!ToJSValue(aCx, blob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + if (aTag == SCTAG_DOM_FILELIST) { + MOZ_ASSERT(!(mFlags & eFileListNotSupported)); + + FileListClonedData* fileListClonedData; + if (JS_ReadBytes(aReader, &fileListClonedData, + sizeof(fileListClonedData))) { + MOZ_ASSERT(fileListClonedData); + + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(aCx); + { + nsRefPtr fileList = + FileList::Create(mParent, fileListClonedData); + if (!fileList || !ToJSValue(aCx, fileList, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr); +} + +bool +StructuredCloneHelper::WriteCallback(JSContext* aCx, + JSStructuredCloneWriter* aWriter, + JS::Handle aObj) +{ + // See if this is a File/Blob object. + if (!(mFlags & eBlobNotSupported)) { + Blob* blob = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { + BlobImpl* blobImpl = blob->Impl(); + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, 0) && + JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl)) && + StoreISupports(blobImpl); + } + } + + if (!(mFlags & eFileListNotSupported)) { + FileList* fileList = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) { + nsRefPtr fileListClonedData = + fileList->CreateClonedData(); + MOZ_ASSERT(fileListClonedData); + FileListClonedData* ptr = fileListClonedData.get(); + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, 0) && + JS_WriteBytes(aWriter, &ptr, sizeof(ptr)) && + StoreISupports(fileListClonedData); + } + } + + return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); +} + +bool +StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, + JSStructuredCloneReader* aReader, + uint32_t aTag, + void* aContent, + uint64_t aExtraData, + JS::MutableHandleObject aReturnObject) +{ + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); + + // This can be null. + nsCOMPtr window = do_QueryInterface(mParent); + + MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); + const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData]; + + // aExtraData is the index of this port identifier. + ErrorResult rv; + nsRefPtr port = + MessagePort::Create(window, portIdentifier, rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + mTransferredPorts.AppendElement(port); + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; + } + + return false; +} + + +bool +StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, + JS::Handle aObj, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData) +{ + if (!(mFlags & eMessagePortNotSupported)) { + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + if (mTransferringPort.Contains(port)) { + // No duplicates. + return false; + } + + // We use aExtraData to store the index of this new port identifier. + *aExtraData = mPortIdentifiers.Length(); + MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement(); + + if (!port->CloneAndDisentangle(*identifier)) { + return false; + } + + mTransferringPort.AppendElement(port); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + + return true; + } + } + + return false; +} + +void +StructuredCloneHelper::FreeTransferCallback(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void* aContent, + uint64_t aExtraData) +{ + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); + MOZ_ASSERT(!aContent); + MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); + MessagePort::ForceClose(mPortIdentifiers[aExtraData]); + } +} + } // dom namespace } // mozilla namespace diff --git a/dom/base/StructuredCloneHelper.h b/dom/base/StructuredCloneHelper.h index 1a508d175de5..4b19d05b0471 100644 --- a/dom/base/StructuredCloneHelper.h +++ b/dom/base/StructuredCloneHelper.h @@ -8,6 +8,8 @@ #include "js/StructuredClone.h" #include "nsAutoPtr.h" +#include "nsISupports.h" +#include "nsTArray.h" namespace mozilla { namespace dom { @@ -69,6 +71,109 @@ protected: nsAutoPtr mBuffer; }; +class MessagePortBase; +class MessagePortIdentifier; + +class StructuredCloneHelper : public StructuredCloneHelperInternal +{ +public: + enum StructuredCloneHelperFlags { + eAll = 0, + + // Disable the cloning of blobs. If a blob is part of the cloning value, + // an exception will be thrown. + eBlobNotSupported = 1 << 0, + + // Disable the cloning of FileLists. If a FileList is part of the cloning + // value, an exception will be thrown. + eFileListNotSupported = 1 << 1, + + // MessagePort can just be transfered. Using this flag we do not support + // the transfering. + eMessagePortNotSupported = 1 << 2, + }; + + // aFlags is a bitmap of StructuredCloneHelperFlags. + explicit StructuredCloneHelper(uint32_t aFlags = eAll); + virtual ~StructuredCloneHelper(); + + bool Write(JSContext* aCx, + JS::Handle aValue, + JS::Handle aTransfer); + + bool Read(nsISupports* aParent, + JSContext* aCx, + JS::MutableHandle aValue); + + nsTArray>& GetTransferredPorts() + { + MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); + return mTransferredPorts; + } + + // Custom Callbacks + + virtual JSObject* ReadCallback(JSContext* aCx, + JSStructuredCloneReader* aReader, + uint32_t aTag, + uint32_t aIndex) override; + + virtual bool WriteCallback(JSContext* aCx, + JSStructuredCloneWriter* aWriter, + JS::Handle aObj) override; + + virtual bool ReadTransferCallback(JSContext* aCx, + JSStructuredCloneReader* aReader, + uint32_t aTag, + void* aContent, + uint64_t aExtraData, + JS::MutableHandleObject aReturnObject) override; + + virtual bool WriteTransferCallback(JSContext* aCx, + JS::Handle aObj, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData) override; + + virtual void FreeTransferCallback(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void* aContent, + uint64_t aExtraData) override; +private: + bool StoreISupports(nsISupports* aSupports) + { + MOZ_ASSERT(aSupports); + mSupportsArray.AppendElement(aSupports); + return true; + } + + // This is our bitmap. + uint32_t mFlags; + + // Useful for the structured clone algorithm: + + nsTArray> mSupportsArray; + + // This raw pointer is set and unset into the ::Read(). It's always null + // outside that method. For this reason it's a raw pointer. + nsISupports* MOZ_NON_OWNING_REF mParent; + + // This hashtable contains the ports while doing write (transferring and + // mapping transferred objects to the objects in the clone). It's an empty + // array outside the 'Write()' method. + nsTArray> mTransferringPort; + + // This array contains the ports once we've finished the reading. It's + // generated from the mPortIdentifiers array. + nsTArray> mTransferredPorts; + + // This array contains the identifiers of the MessagePorts. Based on these we + // are able to reconnect the new transferred ports with the other + // MessageChannel ports. + nsTArray mPortIdentifiers; +}; + } // dom namespace } // mozilla namespace diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index d8f645461df9..3827f6b57a01 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8582,7 +8582,7 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle aMessa JS::Rooted message(aCx, aMessage); JS::Rooted transfer(aCx, aTransfer); - if (!event->Write(aCx, message, transfer, this)) { + if (!event->Write(aCx, message, transfer)) { aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } From 5b0ddb95624b729eea19fb5093e579db2f1fc973 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 24 Jul 2015 12:12:51 +0100 Subject: [PATCH 53/90] Bug 1184557 - part 2 - StructuredCloneHelperInternal::Shutdown, r=smaug --- dom/base/Console.cpp | 2 ++ dom/base/StructuredCloneHelper.cpp | 33 ++++++++++++++++++++++++++++-- dom/base/StructuredCloneHelper.h | 13 ++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 9abb96abc302..1e8c76c1e507 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -207,6 +207,8 @@ public: virtual ~ConsoleRunnable() { + // Shutdown the StructuredCloneHelperInternal class. + Shutdown(); } bool diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index fd8e984406a6..15e49afc5a26 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -89,7 +89,7 @@ void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId) { - NS_WARNING("Failed to clone data for the Console API in workers."); + NS_WARNING("Failed to clone data."); } const JSStructuredCloneCallbacks gCallbacks = { @@ -105,11 +105,36 @@ const JSStructuredCloneCallbacks gCallbacks = { // StructuredCloneHelperInternal class +StructuredCloneHelperInternal::StructuredCloneHelperInternal() +#ifdef DEBUG + : mShutdownCalled(false) +#endif +{} + +StructuredCloneHelperInternal::~StructuredCloneHelperInternal() +{ +#ifdef DEBUG + MOZ_ASSERT(mShutdownCalled); +#endif +} + +void +StructuredCloneHelperInternal::Shutdown() +{ +#ifdef DEBUG + MOZ_ASSERT(!mShutdownCalled, "Shutdown already called!"); + mShutdownCalled = true; +#endif + + mBuffer = nullptr; +} + bool StructuredCloneHelperInternal::Write(JSContext* aCx, JS::Handle aValue) { MOZ_ASSERT(!mBuffer, "Double Write is not allowed"); + MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown."); mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this); return mBuffer->write(aCx, aValue, &gCallbacks, this); @@ -121,6 +146,7 @@ StructuredCloneHelperInternal::Write(JSContext* aCx, JS::Handle aTransfer) { MOZ_ASSERT(!mBuffer, "Double Write is not allowed"); + MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown."); mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this); return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this); @@ -131,6 +157,7 @@ StructuredCloneHelperInternal::Read(JSContext* aCx, JS::MutableHandle aValue) { MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed."); + MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown."); bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this); mBuffer = nullptr; @@ -178,7 +205,9 @@ StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags) {} StructuredCloneHelper::~StructuredCloneHelper() -{} +{ + Shutdown(); +} bool StructuredCloneHelper::Write(JSContext* aCx, diff --git a/dom/base/StructuredCloneHelper.h b/dom/base/StructuredCloneHelper.h index 4b19d05b0471..1141f08318b9 100644 --- a/dom/base/StructuredCloneHelper.h +++ b/dom/base/StructuredCloneHelper.h @@ -17,6 +17,9 @@ namespace dom { class StructuredCloneHelperInternal { public: + StructuredCloneHelperInternal(); + virtual ~StructuredCloneHelperInternal(); + // These methods should be implemented in order to clone data. // Read more documentation in js/public/StructuredClone.h. @@ -29,6 +32,12 @@ public: JSStructuredCloneWriter* aWriter, JS::Handle aObj) = 0; + // This method has to be called when this object is not needed anymore. + // It will free memory and the buffer. This has to be called because + // otherwise the buffer will be freed in the DTOR of this class and at that + // point we cannot use the overridden methods. + void Shutdown(); + // If these 3 methods are not implement, transfering objects will not be // allowed. @@ -69,6 +78,10 @@ public: protected: nsAutoPtr mBuffer; + +#ifdef DEBUG + bool mShutdownCalled; +#endif }; class MessagePortBase; From f75c7dfbe8abde594c52fa39e04c954380131f62 Mon Sep 17 00:00:00 2001 From: Masatoshi Kimura Date: Fri, 24 Jul 2015 20:29:52 +0900 Subject: [PATCH 54/90] Bug 1186636 - Add a pref to configure -moz prefixed gradients support. r=dholbert --- layout/style/nsCSSParser.cpp | 6 +++++- modules/libpref/init/all.js | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index ea368aa742e0..f17299297d85 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -58,6 +58,7 @@ typedef nsCSSProps::KTableValue KTableValue; // pref-backed bool values (hooked up in nsCSSParser::Startup) static bool sOpentypeSVGEnabled; static bool sUnprefixingServiceEnabled; +static bool sMozGradientsEnabled; const uint32_t nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = { @@ -7416,7 +7417,8 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, // a generated gradient nsDependentString tmp(tk->mIdent, 0); bool isLegacy = false; - if (StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) { + if (sMozGradientsEnabled && + StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) { tmp.Rebind(tmp, 5); isLegacy = true; } @@ -15675,6 +15677,8 @@ nsCSSParser::Startup() "gfx.font_rendering.opentype_svg.enabled"); Preferences::AddBoolVarCache(&sUnprefixingServiceEnabled, "layout.css.unprefixing-service.enabled"); + Preferences::AddBoolVarCache(&sMozGradientsEnabled, + "layout.css.prefixes.gradients"); } nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader, diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 20bd13480cfe..fbbab15fb332 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2259,6 +2259,7 @@ pref("layout.css.prefixes.transitions", true); pref("layout.css.prefixes.animations", true); pref("layout.css.prefixes.box-sizing", true); pref("layout.css.prefixes.font-features", true); +pref("layout.css.prefixes.gradients", true); // Is the CSS Unprefixing Service enabled? (This service emulates support // for certain vendor-prefixed properties & values, for sites on a "fixlist".) From 9a563a0d8fb83a86bf8a18b6aba36901f5d7df15 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 15 Jul 2015 11:50:38 +0100 Subject: [PATCH 55/90] Bug 1182428 - Refactor bytecode compilation r=luke --- js/src/frontend/BytecodeCompiler.cpp | 931 ++++++++++++++++----------- js/src/frontend/BytecodeCompiler.h | 2 +- js/src/jsapi.cpp | 2 +- 3 files changed, 560 insertions(+), 375 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 38d63c097762..ad6e9a450269 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -39,6 +39,87 @@ class MOZ_STACK_CLASS AutoCompilationTraceLogger AutoTraceLog typeLogger; }; +// The BytecodeCompiler class contains resources common to compiling scripts and +// function bodies. +class MOZ_STACK_CLASS BytecodeCompiler +{ + public: + // Construct an object passing mandatory arguments. + BytecodeCompiler(ExclusiveContext* cx, + LifoAlloc* alloc, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& sourceBuffer, + TraceLoggerTextId logId); + + // Call setters for optional arguments. + void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor); + void setEnclosingStaticScope(Handle scope); + void setSourceArgumentsNotIncluded(); + + JSScript* compileScript(HandleObject scopeChain, HandleScript evalCaller, + unsigned staticLevel); + bool compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals, + GeneratorKind generatorKind); + + private: + bool checkLength(); + bool createScriptSource(); + bool maybeCompressSource(); + bool canLazilyParse(); + bool createParser(); + bool createSourceAndParser(); + bool createScript(bool savedCallerFun = false, unsigned staticLevel = 0); + bool createEmitter(SharedContext* sharedContext, HandleScript evalCaller = nullptr, + bool insideNonGlobalEval = false); + bool isInsideNonGlobalEval(); + bool createParseContext(Maybe>& parseContext, + GlobalSharedContext& globalsc, unsigned staticLevel = 0, + uint32_t blockScopeDepth = 0); + bool saveCallerFun(HandleScript evalCaller, ParseContext& parseContext); + bool handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller, + unsigned staticLevel, + Maybe>& parseContext, + GlobalSharedContext& globalsc); + bool handleParseFailure(const Directives& newDirectives); + bool prepareAndEmitTree(ParseNode** pn); + bool checkArgumentsWithinEval(JSContext* cx, HandleFunction fun); + bool maybeCheckEvalFreeVariables(HandleScript evalCaller, HandleObject scopeChain, + ParseContext& pc); + bool maybeSetDisplayURL(TokenStream& tokenStream); + bool maybeSetSourceMap(TokenStream& tokenStream); + bool maybeSetSourceMapFromOptions(); + bool emitFinalReturn(); + bool initGlobalBindings(ParseContext& pc); + void markFunctionsWithinEvalScript(); + bool maybeCompleteCompressSource(); + + AutoCompilationTraceLogger traceLogger; + AutoKeepAtoms keepAtoms; + + ExclusiveContext* cx; + LifoAlloc* alloc; + const ReadOnlyCompileOptions& options; + SourceBufferHolder& sourceBuffer; + + Rooted enclosingStaticScope; + bool sourceArgumentsNotIncluded; + + RootedScriptSource sourceObject; + ScriptSource* scriptSource; + + Maybe maybeSourceCompressor; + SourceCompressionTask* sourceCompressor; + + Maybe> syntaxParser; + Maybe> parser; + + Directives directives; + TokenStream::Position startPosition; + + RootedScript script; + Maybe emitter; + }; + AutoCompilationTraceLogger::AutoCompilationTraceLogger(ExclusiveContext* cx, const TraceLoggerTextId id) : logger(cx->isJSContext() ? TraceLoggerForMainThread(cx->asJSContext()->runtime()) : TraceLoggerForCurrentThread()), @@ -47,13 +128,53 @@ AutoCompilationTraceLogger::AutoCompilationTraceLogger(ExclusiveContext* cx, con typeLogger(logger, id) {} -static bool -CheckLength(ExclusiveContext* cx, SourceBufferHolder& srcBuf) +BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx, + LifoAlloc* alloc, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& sourceBuffer, + TraceLoggerTextId logId) + : traceLogger(cx, logId), + keepAtoms(cx->perThreadData), + cx(cx), + alloc(alloc), + options(options), + sourceBuffer(sourceBuffer), + enclosingStaticScope(cx), + sourceArgumentsNotIncluded(false), + sourceObject(cx), + scriptSource(nullptr), + sourceCompressor(nullptr), + directives(options.strictOption), + startPosition(keepAtoms), + script(cx) +{ +} + +void +BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor) +{ + this->sourceCompressor = sourceCompressor; +} + +void +BytecodeCompiler::setEnclosingStaticScope(Handle scope) +{ + enclosingStaticScope = scope; +} + +void +BytecodeCompiler::setSourceArgumentsNotIncluded() +{ + sourceArgumentsNotIncluded = true; +} + +bool +BytecodeCompiler::checkLength() { // Note this limit is simply so we can store sourceStart and sourceEnd in // JSScript as 32-bits. It could be lifted fairly easily, since the compiler // is using size_t internally already. - if (srcBuf.length() > UINT32_MAX) { + if (sourceBuffer.length() > UINT32_MAX) { if (cx->isJSContext()) JS_ReportErrorNumber(cx->asJSContext(), GetErrorMessage, nullptr, JSMSG_SOURCE_TOO_LONG); @@ -62,34 +183,260 @@ CheckLength(ExclusiveContext* cx, SourceBufferHolder& srcBuf) return true; } -static bool -SetDisplayURL(ExclusiveContext* cx, TokenStream& tokenStream, ScriptSource* ss) +bool +BytecodeCompiler::createScriptSource() +{ + if (!checkLength()) + return false; + + sourceObject = CreateScriptSourceObject(cx, options); + if (!sourceObject) + return false; + + scriptSource = sourceObject->source(); + return true; +} + +bool +BytecodeCompiler::maybeCompressSource() +{ + if (!sourceCompressor) { + maybeSourceCompressor.emplace(cx); + sourceCompressor = maybeSourceCompressor.ptr(); + } + + if (!cx->compartment()->options().discardSource()) { + if (options.sourceIsLazy) { + scriptSource->setSourceRetrievable(); + } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded, + sourceCompressor)) + { + return nullptr; + } + } + + return true; +} + +bool +BytecodeCompiler::canLazilyParse() +{ + return options.canLazilyParse && + !HasNonSyntacticStaticScopeChain(enclosingStaticScope) && + !cx->compartment()->options().disableLazyParsing() && + !cx->compartment()->options().discardSource() && + !options.sourceIsLazy; +} + +bool +BytecodeCompiler::createParser() +{ + if (canLazilyParse()) { + syntaxParser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(), + /* foldConstants = */ false, (Parser*) nullptr, + (LazyScript*) nullptr); + + if (!syntaxParser->checkOptions()) + return false; + } + + parser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(), + /* foldConstants = */ true, syntaxParser.ptrOr(nullptr), nullptr); + parser->sct = sourceCompressor; + parser->ss = scriptSource; + if (!parser->checkOptions()) + return false; + + parser->tokenStream.tell(&startPosition); + return true; +} + +bool +BytecodeCompiler::createSourceAndParser() +{ + return createScriptSource() && + maybeCompressSource() && + createParser(); +} + +bool +BytecodeCompiler::createScript(bool savedCallerFun, unsigned staticLevel) +{ + script = JSScript::Create(cx, enclosingStaticScope, savedCallerFun, + options, staticLevel, + sourceObject, /* sourceStart = */ 0, + sourceBuffer.length()); + + return script != nullptr; +} + +bool +BytecodeCompiler::createEmitter(SharedContext* sharedContext, HandleScript evalCaller, + bool insideNonGlobalEval) +{ + BytecodeEmitter::EmitterMode emitterMode = + options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal; + emitter.emplace(/* parent = */ nullptr, parser.ptr(), sharedContext, script, + /* lazyScript = */ nullptr, options.forEval, evalCaller, + insideNonGlobalEval, options.lineno, emitterMode); + return emitter->init(); +} + +bool BytecodeCompiler::isInsideNonGlobalEval() +{ + return enclosingStaticScope && enclosingStaticScope->is() && + enclosingStaticScope->as().enclosingScopeForStaticScopeIter(); +} + +bool +BytecodeCompiler::createParseContext(Maybe>& parseContext, + GlobalSharedContext& globalsc, unsigned staticLevel, + uint32_t blockScopeDepth) +{ + parseContext.emplace(parser.ptr(), (GenericParseContext*) nullptr, (ParseNode*) nullptr, + &globalsc, (Directives*) nullptr, staticLevel, /* bodyid = */ 0, + blockScopeDepth); + return parseContext->init(parser->tokenStream); +} + +bool +BytecodeCompiler::saveCallerFun(HandleScript evalCaller, + ParseContext& parseContext) +{ + /* + * An eval script in a caller frame needs to have its enclosing + * function captured in case it refers to an upvar, and someone + * wishes to decompile it while it's running. + * + * This ends up as script->objects()->vector[0] in the compiled script. + */ + JSFunction* fun = evalCaller->functionOrCallerFunction(); + MOZ_ASSERT_IF(fun->strict(), options.strictOption); + Directives directives(/* strict = */ options.strictOption); + ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext, + directives, fun->generatorKind()); + if (!funbox) + return false; + + emitter->objectList.add(funbox); + return true; +} + +bool +BytecodeCompiler::handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller, + unsigned staticLevel, + Maybe>& parseContext, + GlobalSharedContext& globalsc) +{ + if (!parser->hadAbortedSyntaxParse()) + return false; + + // Parsing inner functions lazily may lead the parser into an + // unrecoverable state and may require starting over on the top + // level statement. Restart the parse; syntax parsing has + // already been disabled for the parser and the result will not + // be ambiguous. + parser->clearAbortedSyntaxParse(); + parser->tokenStream.seek(startPosition); + + // Destroying the parse context will destroy its free + // variables, so check if any deoptimization is needed. + if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, parseContext.ref())) + return nullptr; + + parseContext.reset(); + if (!createParseContext(parseContext, globalsc, staticLevel, script->bindings.numBlockScoped())) + return false; + + MOZ_ASSERT(parser->pc == parseContext.ptr()); + return true; +} + +bool +BytecodeCompiler::handleParseFailure(const Directives& newDirectives) +{ + if (parser->hadAbortedSyntaxParse()) { + // Hit some unrecoverable ambiguity during an inner syntax parse. + // Syntax parsing has now been disabled in the parser, so retry + // the parse. + parser->clearAbortedSyntaxParse(); + } else if (parser->tokenStream.hadError() || directives == newDirectives) { + return false; + } + + parser->tokenStream.seek(startPosition); + + // Assignment must be monotonic to prevent reparsing iloops + MOZ_ASSERT_IF(directives.strict(), newDirectives.strict()); + MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); + directives = newDirectives; + return true; +} + +bool +BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn) +{ + if (!FoldConstants(cx, ppn, parser.ptr()) || + !NameFunctions(cx, *ppn) || + !emitter->updateLocalsToFrameSlots() || + !emitter->emitTree(*ppn)) + { + return false; + } + + return true; +} + +bool +BytecodeCompiler::maybeSetDisplayURL(TokenStream& tokenStream) { if (tokenStream.hasDisplayURL()) { - if (!ss->setDisplayURL(cx, tokenStream.displayURL())) + if (!scriptSource->setDisplayURL(cx, tokenStream.displayURL())) return false; } return true; } -static bool -SetSourceMap(ExclusiveContext* cx, TokenStream& tokenStream, ScriptSource* ss) +bool +BytecodeCompiler::maybeSetSourceMap(TokenStream& tokenStream) { if (tokenStream.hasSourceMapURL()) { - MOZ_ASSERT(!ss->hasSourceMapURL()); - if (!ss->setSourceMapURL(cx, tokenStream.sourceMapURL())) + MOZ_ASSERT(!scriptSource->hasSourceMapURL()); + if (!scriptSource->setSourceMapURL(cx, tokenStream.sourceMapURL())) return false; } return true; } -static bool -CheckArgumentsWithinEval(JSContext* cx, Parser& parser, HandleFunction fun) +bool +BytecodeCompiler::maybeSetSourceMapFromOptions() +{ + /* + * Source map URLs passed as a compile option (usually via a HTTP source map + * header) override any source map urls passed as comment pragmas. + */ + if (options.sourceMapURL()) { + // Warn about the replacement, but use the new one. + if (scriptSource->hasSourceMapURL()) { + if(!parser->report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA, + scriptSource->filename(), "//# sourceMappingURL")) + return false; + } + + if (!scriptSource->setSourceMapURL(cx, options.sourceMapURL())) + return false; + } + + return true; +} + +bool +BytecodeCompiler::checkArgumentsWithinEval(JSContext* cx, HandleFunction fun) { if (fun->hasRest()) { // It's an error to use |arguments| in a function that has a rest // parameter. - parser.report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST); + parser->report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST); return false; } @@ -98,6 +445,7 @@ CheckArgumentsWithinEval(JSContext* cx, Parser& parser, Handle RootedScript script(cx, fun->getOrCreateScript(cx)); if (!script) return false; + if (script->argumentsHasVarBinding()) { if (!JSScript::argumentsOptimizationFailed(cx, script)) return false; @@ -105,23 +453,22 @@ CheckArgumentsWithinEval(JSContext* cx, Parser& parser, Handle // It's an error to use |arguments| in a legacy generator expression. if (script->isGeneratorExp() && script->isLegacyGenerator()) { - parser.report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str); + parser->report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str); return false; } return true; } -static bool -MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, HandleObject scopeChain, - Parser& parser, - ParseContext& pc) +bool +BytecodeCompiler::maybeCheckEvalFreeVariables(HandleScript evalCaller, HandleObject scopeChain, + ParseContext& pc) { if (!evalCaller || !evalCaller->functionOrCallerFunction()) return true; // Eval scripts are only compiled on the main thread. - JSContext* cx = cxArg->asJSContext(); + JSContext* cx = this->cx->asJSContext(); // Watch for uses of 'arguments' within the evaluated script, both as // free variables and as variables redeclared with 'var'. @@ -129,13 +476,13 @@ MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, Ha HandlePropertyName arguments = cx->names().arguments; for (AtomDefnRange r = pc.lexdeps->all(); !r.empty(); r.popFront()) { if (r.front().key() == arguments) { - if (!CheckArgumentsWithinEval(cx, parser, fun)) + if (!checkArgumentsWithinEval(cx, fun)) return false; } } for (AtomDefnListMap::Range r = pc.decls().all(); !r.empty(); r.popFront()) { if (r.front().key() == arguments) { - if (!CheckArgumentsWithinEval(cx, parser, fun)) + if (!checkArgumentsWithinEval(cx, fun)) return false; } } @@ -163,19 +510,36 @@ MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, Ha return true; } -static inline bool -CanLazilyParse(ExclusiveContext* cx, HandleObject staticScope, - const ReadOnlyCompileOptions& options) +bool +BytecodeCompiler::emitFinalReturn() { - return options.canLazilyParse && - !HasNonSyntacticStaticScopeChain(staticScope) && - !cx->compartment()->options().disableLazyParsing() && - !cx->compartment()->options().discardSource() && - !options.sourceIsLazy; + /* + * Nowadays the threaded interpreter needs a last return instruction, so we + * do have to emit that here. + */ + return emitter->emit1(JSOP_RETRVAL); } -static void -MarkFunctionsWithinEvalScript(JSScript* script) +bool +BytecodeCompiler::initGlobalBindings(ParseContext& pc) +{ + // Global/eval script bindings are always empty (all names are added to the + // scope dynamically via JSOP_DEFFUN/VAR). They may have block-scoped + // locals, however, which are allocated to the fixed part of the stack + // frame. + Rooted bindings(cx, script->bindings); + if (!Bindings::initWithTemporaryStorage(cx, &bindings, 0, 0, 0, + pc.blockScopeDepth, 0, 0, nullptr)) + { + return false; + } + + script->bindings = bindings; + return true; +} + +void +BytecodeCompiler::markFunctionsWithinEvalScript() { // Mark top level functions in an eval script as being within an eval. @@ -197,6 +561,158 @@ MarkFunctionsWithinEvalScript(JSScript* script) } } +bool +BytecodeCompiler::maybeCompleteCompressSource() +{ + return !maybeSourceCompressor || maybeSourceCompressor->complete(); +} + +JSScript* +BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller, + unsigned staticLevel) +{ + if (!createSourceAndParser()) + return nullptr; + + bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction(); + if (!createScript(savedCallerFun, staticLevel)) + return nullptr; + + GlobalSharedContext globalsc(cx, directives, enclosingStaticScope, options.extraWarningsOption); + if (!createEmitter(&globalsc, evalCaller, isInsideNonGlobalEval())) + return nullptr; + + // Syntax parsing may cause us to restart processing of top level + // statements in the script. Use Maybe<> so that the parse context can be + // reset when this occurs. + Maybe> pc; + if (!createParseContext(pc, globalsc, staticLevel)) + return nullptr; + + if (savedCallerFun && !saveCallerFun(evalCaller, pc.ref())) + return nullptr; + + bool canHaveDirectives = true; + for (;;) { + TokenKind tt; + if (!parser->tokenStream.peekToken(&tt, TokenStream::Operand)) + return nullptr; + if (tt == TOK_EOF) + break; + + parser->tokenStream.tell(&startPosition); + + ParseNode* pn = parser->statement(YieldIsName, canHaveDirectives); + if (!pn) { + if (!handleStatementParseFailure(scopeChain, evalCaller, staticLevel, pc, globalsc)) + return nullptr; + + pn = parser->statement(YieldIsName); + if (!pn) { + MOZ_ASSERT(!parser->hadAbortedSyntaxParse()); + return nullptr; + } + } + + // Accumulate the maximum block scope depth, so that emitTree can assert + // when emitting JSOP_GETLOCAL that the local is indeed within the fixed + // part of the stack frame. + script->bindings.updateNumBlockScoped(pc->blockScopeDepth); + + if (canHaveDirectives) { + if (!parser->maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives)) + return nullptr; + } + + if (!prepareAndEmitTree(&pn)) + return nullptr; + + parser->handler.freeTree(pn); + } + + if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, *pc) || + !maybeSetDisplayURL(parser->tokenStream) || + !maybeSetSourceMap(parser->tokenStream) || + !maybeSetSourceMapFromOptions() || + !emitFinalReturn() || + !initGlobalBindings(pc.ref()) || + !JSScript::fullyInitFromEmitter(cx, script, emitter.ptr())) + { + return nullptr; + } + + // Note that this marking must happen before we tell Debugger + // about the new script, in case Debugger delazifies the script's + // inner functions. + if (options.forEval) + markFunctionsWithinEvalScript(); + + emitter->tellDebuggerAboutCompiledScript(cx); + + if (!maybeCompleteCompressSource()) + return nullptr; + + MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending()); + return script; +} + +bool +BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, const AutoNameVector& formals, + GeneratorKind generatorKind) +{ + MOZ_ASSERT(fun); + MOZ_ASSERT(fun->isTenured()); + + fun->setArgCount(formals.length()); + + if (!createSourceAndParser()) + return false; + + // Speculatively parse using the default directives implied by the context. + // If a directive is encountered (e.g., "use strict") that changes how the + // function should have been parsed, we backup and reparse with the new set + // of directives. + + ParseNode* fn; + do { + Directives newDirectives = directives; + fn = parser->standaloneFunctionBody(fun, formals, generatorKind, directives, + &newDirectives); + if (!fn && !handleParseFailure(newDirectives)) + return false; + } while (!fn); + + if (!NameFunctions(cx, fn) || + !maybeSetDisplayURL(parser->tokenStream) || + !maybeSetSourceMap(parser->tokenStream)) + { + return false; + } + + if (fn->pn_funbox->function()->isInterpreted()) { + MOZ_ASSERT(fun == fn->pn_funbox->function()); + + if (!createScript()) + return false; + + script->bindings = fn->pn_funbox->bindings; + + if (!createEmitter(fn->pn_funbox) || + !emitter->emitFunctionScript(fn->pn_body)) + { + return false; + } + } else { + fun.set(fn->pn_funbox->function()); + MOZ_ASSERT(IsAsmJSModuleNative(fun->native())); + } + + if (!maybeCompleteCompressSource()) + return false; + + return true; +} + ScriptSourceObject* frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options) { @@ -241,10 +757,6 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco { MOZ_ASSERT(srcBuf.get()); - RootedString source(cx, source_); - - AutoCompilationTraceLogger traceLogger(cx, TraceLogger_ParserCompileScript); - /* * The scripted callerFrame can only be given for compile-and-go scripts * and non-zero static level requires callerFrame. @@ -253,225 +765,12 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco MOZ_ASSERT_IF(evalCaller, options.forEval); MOZ_ASSERT_IF(evalCaller && evalCaller->strict(), options.strictOption); MOZ_ASSERT_IF(staticLevel != 0, evalCaller); - - if (!CheckLength(cx, srcBuf)) - return nullptr; MOZ_ASSERT_IF(staticLevel != 0, !options.sourceIsLazy); - RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options)); - if (!sourceObject) - return nullptr; - - ScriptSource* ss = sourceObject->source(); - - SourceCompressionTask mysct(cx); - SourceCompressionTask* sct = extraSct ? extraSct : &mysct; - - if (!cx->compartment()->options().discardSource()) { - if (options.sourceIsLazy) - ss->setSourceRetrievable(); - else if (!ss->setSourceCopy(cx, srcBuf, false, sct)) - return nullptr; - } - - bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); - - Maybe > syntaxParser; - if (canLazilyParse) { - syntaxParser.emplace(cx, alloc, options, srcBuf.get(), srcBuf.length(), - /* foldConstants = */ false, - (Parser*) nullptr, - (LazyScript*) nullptr); - - if (!syntaxParser->checkOptions()) - return nullptr; - } - - Parser parser(cx, alloc, options, srcBuf.get(), srcBuf.length(), - /* foldConstants = */ true, - canLazilyParse ? syntaxParser.ptr() : nullptr, nullptr); - parser.sct = sct; - parser.ss = ss; - - if (!parser.checkOptions()) - return nullptr; - - bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction(); - Directives directives(options.strictOption); - GlobalSharedContext globalsc(cx, directives, enclosingStaticScope, options.extraWarningsOption); - - Rooted script(cx, JSScript::Create(cx, enclosingStaticScope, savedCallerFun, - options, staticLevel, sourceObject, 0, - srcBuf.length())); - if (!script) - return nullptr; - - bool insideNonGlobalEval = - enclosingStaticScope && enclosingStaticScope->is() && - enclosingStaticScope->as().enclosingScopeForStaticScopeIter(); - BytecodeEmitter::EmitterMode emitterMode = - options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal; - BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, - /* lazyScript = */ nullptr, options.forEval, - evalCaller, insideNonGlobalEval, options.lineno, emitterMode); - if (!bce.init()) - return nullptr; - - // Syntax parsing may cause us to restart processing of top level - // statements in the script. Use Maybe<> so that the parse context can be - // reset when this occurs. - Maybe > pc; - - pc.emplace(&parser, (GenericParseContext*) nullptr, (ParseNode*) nullptr, &globalsc, - (Directives*) nullptr, staticLevel, /* bodyid = */ 0, - /* blockScopeDepth = */ 0); - if (!pc->init(parser.tokenStream)) - return nullptr; - - if (savedCallerFun) { - /* - * An eval script in a caller frame needs to have its enclosing - * function captured in case it refers to an upvar, and someone - * wishes to decompile it while it's running. - */ - JSFunction* fun = evalCaller->functionOrCallerFunction(); - MOZ_ASSERT_IF(fun->strict(), options.strictOption); - Directives directives(/* strict = */ options.strictOption); - ObjectBox* funbox = parser.newFunctionBox(/* fn = */ nullptr, fun, pc.ptr(), - directives, fun->generatorKind()); - if (!funbox) - return nullptr; - bce.objectList.add(funbox); - } - - bool canHaveDirectives = true; - for (;;) { - TokenKind tt; - if (!parser.tokenStream.peekToken(&tt, TokenStream::Operand)) - return nullptr; - if (tt == TOK_EOF) - break; - - TokenStream::Position pos(parser.keepAtoms); - parser.tokenStream.tell(&pos); - - ParseNode* pn = parser.statement(YieldIsName, canHaveDirectives); - if (!pn) { - if (parser.hadAbortedSyntaxParse()) { - // Parsing inner functions lazily may lead the parser into an - // unrecoverable state and may require starting over on the top - // level statement. Restart the parse; syntax parsing has - // already been disabled for the parser and the result will not - // be ambiguous. - parser.clearAbortedSyntaxParse(); - parser.tokenStream.seek(pos); - - // Destroying the parse context will destroy its free - // variables, so check if any deoptimization is needed. - if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, *pc)) - return nullptr; - - pc.reset(); - pc.emplace(&parser, (GenericParseContext*) nullptr, (ParseNode*) nullptr, - &globalsc, (Directives*) nullptr, staticLevel, /* bodyid = */ 0, - script->bindings.numBlockScoped()); - if (!pc->init(parser.tokenStream)) - return nullptr; - MOZ_ASSERT(parser.pc == pc.ptr()); - - pn = parser.statement(YieldIsName); - } - if (!pn) { - MOZ_ASSERT(!parser.hadAbortedSyntaxParse()); - return nullptr; - } - } - - // Accumulate the maximum block scope depth, so that emitTree can assert - // when emitting JSOP_GETLOCAL that the local is indeed within the fixed - // part of the stack frame. - script->bindings.updateNumBlockScoped(pc->blockScopeDepth); - - if (canHaveDirectives) { - if (!parser.maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives)) - return nullptr; - } - - if (!FoldConstants(cx, &pn, &parser)) - return nullptr; - - if (!NameFunctions(cx, pn)) - return nullptr; - - if (!bce.updateLocalsToFrameSlots()) - return nullptr; - - if (!bce.emitTree(pn)) - return nullptr; - - parser.handler.freeTree(pn); - } - - if (!MaybeCheckEvalFreeVariables(cx, evalCaller, scopeChain, parser, *pc)) - return nullptr; - - if (!SetDisplayURL(cx, parser.tokenStream, ss)) - return nullptr; - - if (!SetSourceMap(cx, parser.tokenStream, ss)) - return nullptr; - - /* - * Source map URLs passed as a compile option (usually via a HTTP source map - * header) override any source map urls passed as comment pragmas. - */ - if (options.sourceMapURL()) { - // Warn about the replacement, but use the new one. - if (ss->hasSourceMapURL()) { - if(!parser.report(ParseWarning, false, nullptr, JSMSG_ALREADY_HAS_PRAGMA, - ss->filename(), "//# sourceMappingURL")) - return nullptr; - } - - if (!ss->setSourceMapURL(cx, options.sourceMapURL())) - return nullptr; - } - - /* - * Nowadays the threaded interpreter needs a last return instruction, so we - * do have to emit that here. - */ - if (!bce.emit1(JSOP_RETRVAL)) - return nullptr; - - // Global/eval script bindings are always empty (all names are added to the - // scope dynamically via JSOP_DEFFUN/VAR). They may have block-scoped - // locals, however, which are allocated to the fixed part of the stack - // frame. - Rooted bindings(cx, script->bindings); - if (!Bindings::initWithTemporaryStorage(cx, &bindings, 0, 0, 0, - pc->blockScopeDepth, 0, 0, nullptr)) - { - return nullptr; - } - script->bindings = bindings; - - if (!JSScript::fullyInitFromEmitter(cx, script, &bce)) - return nullptr; - - // Note that this marking must happen before we tell Debugger - // about the new script, in case Debugger delazifies the script's - // inner functions. - if (options.forEval) - MarkFunctionsWithinEvalScript(script); - - bce.tellDebuggerAboutCompiledScript(cx); - - if (sct && !extraSct && !sct->complete()) - return nullptr; - - MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending()); - return script; + BytecodeCompiler compiler(cx, alloc, options, srcBuf, TraceLogger_ParserCompileScript); + compiler.maybeSetSourceCompressor(extraSct); + compiler.setEnclosingStaticScope(enclosingStaticScope); + return compiler.compileScript(scopeChain, evalCaller, staticLevel); } bool @@ -546,139 +845,25 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha static bool CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, const AutoNameVector& formals, SourceBufferHolder& srcBuf, - HandleObject enclosingStaticScope, GeneratorKind generatorKind) + Handle enclosingStaticScope, GeneratorKind generatorKind) { MOZ_ASSERT(!options.isRunOnce); - AutoCompilationTraceLogger traceLogger(cx, TraceLogger_ParserCompileFunction); - // FIXME: make Function pass in two strings and parse them as arguments and // ProgramElements respectively. - if (!CheckLength(cx, srcBuf)) - return false; - - RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options)); - if (!sourceObject) - return false; - ScriptSource* ss = sourceObject->source(); - - SourceCompressionTask sct(cx); - MOZ_ASSERT(!options.sourceIsLazy); - if (!cx->compartment()->options().discardSource()) { - if (!ss->setSourceCopy(cx, srcBuf, true, &sct)) - return false; - } - - bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options); - - Maybe > syntaxParser; - if (canLazilyParse) { - syntaxParser.emplace(cx, &cx->tempLifoAlloc(), - options, srcBuf.get(), srcBuf.length(), - /* foldConstants = */ false, - (Parser*) nullptr, - (LazyScript*) nullptr); - if (!syntaxParser->checkOptions()) - return false; - } - - MOZ_ASSERT(!options.forEval); - - Parser parser(cx, &cx->tempLifoAlloc(), - options, srcBuf.get(), srcBuf.length(), - /* foldConstants = */ true, - canLazilyParse ? syntaxParser.ptr() : nullptr, nullptr); - parser.sct = &sct; - parser.ss = ss; - - if (!parser.checkOptions()) - return false; - - MOZ_ASSERT(fun); - MOZ_ASSERT(fun->isTenured()); - - fun->setArgCount(formals.length()); - - // Speculatively parse using the default directives implied by the context. - // If a directive is encountered (e.g., "use strict") that changes how the - // function should have been parsed, we backup and reparse with the new set - // of directives. - Directives directives(options.strictOption); - - TokenStream::Position start(parser.keepAtoms); - parser.tokenStream.tell(&start); - - ParseNode* fn; - while (true) { - Directives newDirectives = directives; - fn = parser.standaloneFunctionBody(fun, formals, generatorKind, directives, &newDirectives); - if (fn) - break; - - if (parser.hadAbortedSyntaxParse()) { - // Hit some unrecoverable ambiguity during an inner syntax parse. - // Syntax parsing has now been disabled in the parser, so retry - // the parse. - parser.clearAbortedSyntaxParse(); - } else { - if (parser.tokenStream.hadError() || directives == newDirectives) - return false; - - // Assignment must be monotonic to prevent reparsing iloops - MOZ_ASSERT_IF(directives.strict(), newDirectives.strict()); - MOZ_ASSERT_IF(directives.asmJS(), newDirectives.asmJS()); - directives = newDirectives; - } - - parser.tokenStream.seek(start); - } - - if (!NameFunctions(cx, fn)) - return false; - - if (!SetDisplayURL(cx, parser.tokenStream, ss)) - return false; - - if (!SetSourceMap(cx, parser.tokenStream, ss)) - return false; - - if (fn->pn_funbox->function()->isInterpreted()) { - MOZ_ASSERT(fun == fn->pn_funbox->function()); - - Rooted script(cx, JSScript::Create(cx, enclosingStaticScope, false, options, - /* staticLevel = */ 0, sourceObject, - /* sourceStart = */ 0, srcBuf.length())); - if (!script) - return false; - - script->bindings = fn->pn_funbox->bindings; - - BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script, - /* lazyScript = */ nullptr, /* insideEval = */ false, - /* evalCaller = */ nullptr, - /* insideNonGlobalEval = */ false, options.lineno); - if (!funbce.init()) - return false; - - if (!funbce.emitFunctionScript(fn->pn_body)) - return false; - } else { - fun.set(fn->pn_funbox->function()); - MOZ_ASSERT(IsAsmJSModuleNative(fun->native())); - } - - if (!sct.complete()) - return false; - - return true; + BytecodeCompiler compiler(cx, &cx->tempLifoAlloc(), options, srcBuf, + TraceLogger_ParserCompileFunction); + compiler.setEnclosingStaticScope(enclosingStaticScope); + compiler.setSourceArgumentsNotIncluded(); + return compiler.compileFunctionBody(fun, formals, generatorKind); } bool frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf, - HandleObject enclosingStaticScope) + Handle enclosingStaticScope) { return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope, NotGenerator); diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 4474f9836efa..a6f374aeb0d0 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -40,7 +40,7 @@ bool CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, const AutoNameVector& formals, JS::SourceBufferHolder& srcBuf, - HandleObject enclosingStaticScope); + Handle enclosingStaticScope); bool CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 2305230a04b1..946ba63cc99e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4199,7 +4199,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char* name, unsigned nargs, const char* const* argnames, SourceBufferHolder& srcBuf, HandleObject enclosingDynamicScope, - HandleObject enclosingStaticScope, + Handle enclosingStaticScope, MutableHandleFunction fun) { MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); From 671ebd98dec0b861b51675f1861e88fe7af5ab3f Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 24 Jul 2015 13:55:19 +0100 Subject: [PATCH 56/90] Bug 1182428 - Fix bustage from returning nullptr in bool function r=me on a CLOSED TREE --- js/src/frontend/BytecodeCompiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index ad6e9a450269..9c05281d21b1 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -211,7 +211,7 @@ BytecodeCompiler::maybeCompressSource() } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded, sourceCompressor)) { - return nullptr; + return false; } } @@ -342,7 +342,7 @@ BytecodeCompiler::handleStatementParseFailure(HandleObject scopeChain, HandleScr // Destroying the parse context will destroy its free // variables, so check if any deoptimization is needed. if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, parseContext.ref())) - return nullptr; + return false; parseContext.reset(); if (!createParseContext(parseContext, globalsc, staticLevel, script->bindings.numBlockScoped())) From d614b68bdf98a4cae1ee6471cfacf9102b00f1bf Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 22 Jul 2015 20:20:53 +1000 Subject: [PATCH 57/90] Bug 1183888: Report empty buffered ranges unless we have a start time. r=bholley --- dom/media/MediaDecoderReader.cpp | 4 +++- dom/media/MediaFormatReader.cpp | 10 +++++++--- dom/media/ogg/OggReader.cpp | 4 +++- dom/media/webm/WebMReader.cpp | 4 +++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index f4915f6375a1..8d18ccac0035 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -238,7 +238,9 @@ media::TimeIntervals MediaDecoderReader::GetBuffered() { MOZ_ASSERT(OnTaskQueue()); - NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals()); + if (!HaveStartTime()) { + return media::TimeIntervals(); + } AutoPinned stream(mDecoder->GetResource()); if (!mDuration.Ref().isSome()) { diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 2904b9e48b65..81f8c9b5463b 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -1449,10 +1449,14 @@ MediaFormatReader::GetBuffered() return intervals; } int64_t startTime; - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals()); + if (!ForceZeroStartTime()) { + if (!HaveStartTime()) { + return intervals; + } startTime = StartTime(); + } else { + // MSE, start time is assumed to be 0 we can proceeed with what we have. + startTime = 0; } // Ensure we have up to date buffered time range. if (HasVideo()) { diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp index 33bde80070db..88f5688287e4 100644 --- a/dom/media/ogg/OggReader.cpp +++ b/dom/media/ogg/OggReader.cpp @@ -1840,7 +1840,9 @@ nsresult OggReader::SeekBisection(int64_t aTarget, media::TimeIntervals OggReader::GetBuffered() { MOZ_ASSERT(OnTaskQueue()); - NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals()); + if (!HaveStartTime()) { + return media::TimeIntervals(); + } { mozilla::ReentrantMonitorAutoEnter mon(mMonitor); if (mIsChained) { diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 5ae7e335cf2c..22f758344811 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -786,7 +786,9 @@ nsresult WebMReader::SeekInternal(int64_t aTarget) media::TimeIntervals WebMReader::GetBuffered() { MOZ_ASSERT(OnTaskQueue()); - NS_ENSURE_TRUE(HaveStartTime(), media::TimeIntervals()); + if (!HaveStartTime()) { + return media::TimeIntervals(); + } AutoPinned resource(mDecoder->GetResource()); media::TimeIntervals buffered; From 219d7420578ce4cd3bf627bd1a4a39d631021806 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 24 Jul 2015 23:06:50 +1000 Subject: [PATCH 58/90] Bug 1186784 - Disable snprintf definition in libav on VC2015. r=glandium --HG-- extra : source : 03d4ebfe2c987137c006e18ca7787d246d3826a9 --- media/libav/libavcommon.mozbuild | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/media/libav/libavcommon.mozbuild b/media/libav/libavcommon.mozbuild index 119de5cf55e7..40f410a97253 100644 --- a/media/libav/libavcommon.mozbuild +++ b/media/libav/libavcommon.mozbuild @@ -12,8 +12,9 @@ if CONFIG['OS_ARCH'] == 'WINNT': # Fix inline symbols and math defines for windows. DEFINES['_USE_MATH_DEFINES'] = True DEFINES['inline'] = "__inline" - # snprintf is prefixed with an underscore on windows. - DEFINES['snprintf'] = "_snprintf" + if CONFIG['_MSC_VER'] and CONFIG['_MSC_VER'] < 1900: + # snprintf is prefixed with an underscore on MSVC 2013. + DEFINES['snprintf'] = "_snprintf" ASFLAGS += ['-Pconfig_win.asm'] # 32-bit windows need to prefix symbols with an underscore. if CONFIG['CPU_ARCH'] == 'x86': From 658cb19c1f71c5f730e1811b848e38201617c69f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 24 Jul 2015 23:06:50 +1000 Subject: [PATCH 59/90] Bug 1187201 - Add char16 wrapper constructor for NS_ConvertUTF16toUTF8 in external string API. r=froydnj --HG-- extra : source : 0facdb6085164a2f5a1674f795fc7a2df4332ca3 --- xpcom/glue/nsStringAPI.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xpcom/glue/nsStringAPI.h b/xpcom/glue/nsStringAPI.h index fa473c8d704a..19279481a7f2 100644 --- a/xpcom/glue/nsStringAPI.h +++ b/xpcom/glue/nsStringAPI.h @@ -1225,6 +1225,14 @@ public: NS_CSTRING_ENCODING_UTF8, *this); } +#ifdef MOZ_USE_CHAR16_WRAPPER + explicit NS_ConvertUTF16toUTF8(char16ptr_t aString, + uint32_t aLength = UINT32_MAX) + : NS_ConvertUTF16toUTF8(static_cast(aString)) + { + } +#endif + private: self_type& operator=(const self_type& aString) = delete; }; From b4774f9ee56d1422dafaba3c17821831cd1b220f Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 15:09:18 +0200 Subject: [PATCH 60/90] Bug 1185176 - Crashtest. r=karlt --- dom/media/test/crashtests/1185176.html | 24 +++++++++++++++++++++++ dom/media/test/crashtests/crashtests.list | 1 + 2 files changed, 25 insertions(+) create mode 100644 dom/media/test/crashtests/1185176.html diff --git a/dom/media/test/crashtests/1185176.html b/dom/media/test/crashtests/1185176.html new file mode 100644 index 000000000000..d5e9b68a2970 --- /dev/null +++ b/dom/media/test/crashtests/1185176.html @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index c0adb51bfa8d..63630aeb6440 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -81,6 +81,7 @@ load 1157994.html load 1122218.html load 1127188.html load audiocontext-double-suspend.html +load 1185176.html include ../../mediasource/test/crashtests/crashtests.list # This needs to run at the end to avoid leaking busted state into other tests. From 6175cb8a69f32f66635e9a6cdf35caac883dbe7e Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 15:09:19 +0200 Subject: [PATCH 61/90] Bug 1185176 - Account for the fact that it is possible for nodes to not have streams. r=karlt We can now destroy a stream earlier than the node for performance reasons. --- dom/media/webaudio/AudioNode.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dom/media/webaudio/AudioNode.cpp b/dom/media/webaudio/AudioNode.cpp index f3b576117656..872dbcb9d27b 100644 --- a/dom/media/webaudio/AudioNode.cpp +++ b/dom/media/webaudio/AudioNode.cpp @@ -294,9 +294,10 @@ AudioNode::SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& void AudioNode::SendChannelMixingParametersToStream() { - MOZ_ASSERT(mStream, "How come we don't have a stream here?"); - mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode, - mChannelInterpretation); + if (mStream) { + mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode, + mChannelInterpretation); + } } void @@ -422,8 +423,9 @@ AudioNode::SetPassThrough(bool aPassThrough) { MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1); mPassThrough = aPassThrough; - MOZ_ASSERT(mStream, "How come we don't have a stream here?"); - mStream->SetPassThrough(mPassThrough); + if (mStream) { + mStream->SetPassThrough(mPassThrough); + } } } // namespace dom From 0788bfab9c4fe24f3003ad474a737eaee2455d06 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 15:09:21 +0200 Subject: [PATCH 62/90] Bug 1185192 - Make promise resolving sequentially consistent when switching graph driver and closing a graph during the same iteration. r=roc --- dom/media/MediaStreamGraph.cpp | 7 +++++++ dom/media/test/crashtests/1185192.html | 18 ++++++++++++++++++ dom/media/test/crashtests/crashtests.list | 1 + 3 files changed, 26 insertions(+) create mode 100644 dom/media/test/crashtests/1185192.html diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index a8ebde584b72..53144c054893 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -3473,6 +3473,13 @@ MediaStreamGraphImpl::ApplyAudioContextOperationImpl(AudioNodeStream* aStream, mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver()); CurrentDriver()->SwitchAtNextIteration(driver); } + // We are closing or suspending an AudioContext, but we just got resumed. + // Queue the operation on the next driver so that the ordering is + // preserved. + } else if (!audioTrackPresent && CurrentDriver()->Switching()) { + MOZ_ASSERT(CurrentDriver()->NextDriver()->AsAudioCallbackDriver()); + CurrentDriver()->NextDriver()->AsAudioCallbackDriver()-> + EnqueueStreamAndPromiseForOperation(aStream, aPromise, aOperation); } else { // We are closing or suspending an AudioContext, but something else is // using the audio stream, we can resolve the promise now. diff --git a/dom/media/test/crashtests/1185192.html b/dom/media/test/crashtests/1185192.html new file mode 100644 index 000000000000..46fa311aa2a6 --- /dev/null +++ b/dom/media/test/crashtests/1185192.html @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index 63630aeb6440..69589149f7b1 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -82,6 +82,7 @@ load 1122218.html load 1127188.html load audiocontext-double-suspend.html load 1185176.html +load 1185192.html include ../../mediasource/test/crashtests/crashtests.list # This needs to run at the end to avoid leaking busted state into other tests. From 45b8168e8fb4b3b3caa248a928468387857a3a78 Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Fri, 24 Jul 2015 10:42:12 +0100 Subject: [PATCH 63/90] Bug 1186911 - Fix progressive paint when using tiled-drawtarget. r=nical The commit for bug 1176077 did not correctly handle the code path for when both progressive paint and tiled-drawtarget are enabled. This fixes it. --HG-- extra : rebase_source : 51a55a6a64b38b7171032c8e790bb5f770f64f94 --- gfx/layers/client/TiledContentClient.cpp | 12 +++++++----- gfx/layers/client/TiledContentClient.h | 9 ++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 9205146be894..9c6bc34b7d63 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -953,7 +953,7 @@ ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, js::ProfileEntry::Category::GRAPHICS); mNewValidRegion = aNewValidRegion; - Update(aNewValidRegion, aPaintRegion); + Update(aNewValidRegion, aPaintRegion, aDirtyRegion); #ifdef GFX_TILEDLAYER_PREF_WARNINGS if (PR_IntervalNow() - start > 10) { @@ -1049,7 +1049,8 @@ void PadDrawTargetOutFromRegion(RefPtr drawTarget, nsIntRegion ®i } void -ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion) +ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion) { if (gfxPrefs::TiledDrawTargetEnabled() && mMoz2DTiles.size() > 0) { gfx::TileSet tileset; @@ -1065,7 +1066,7 @@ ClientTiledLayerBuffer::PostValidate(const nsIntRegion& aPaintRegion) ctx->SetMatrix( ctx->CurrentMatrix().Scale(mResolution, mResolution).Translate(ThebesPoint(-mTilingOrigin))); - mCallback(mPaintedLayer, ctx, aPaintRegion, aPaintRegion, + mCallback(mPaintedLayer, ctx, aPaintRegion, aDirtyRegion, DrawRegionClip::DRAW, nsIntRegion(), mCallbackData); mMoz2DTiles.clear(); // Reset: @@ -1095,7 +1096,8 @@ ClientTiledLayerBuffer::UnlockTile(TileClient& aTile) } void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion, - const nsIntRegion& aPaintRegion) + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion) { const IntSize scaledTileSize = GetScaledTileSize(); const gfx::IntRect newBounds = newValidRegion.GetBounds(); @@ -1148,7 +1150,7 @@ void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion, } } - PostValidate(aPaintRegion); + PostValidate(aPaintRegion, aDirtyRegion); for (TileClient& tile : mRetainedTiles) { UnlockTile(tile); diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 0bccf254e663..b8b9c9f1136d 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -419,7 +419,9 @@ public: LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData); - void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion); + void Update(const nsIntRegion& aNewValidRegion, + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion); void ReadLock(); @@ -449,7 +451,7 @@ public: return; } - Update(nsIntRegion(), nsIntRegion()); + Update(nsIntRegion(), nsIntRegion(), nsIntRegion()); mResolution = aResolution; } @@ -467,7 +469,8 @@ protected: const nsIntPoint& aTileRect, const nsIntRegion& dirtyRect); - void PostValidate(const nsIntRegion& aPaintRegion); + void PostValidate(const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion); void UnlockTile(TileClient& aTile); From 00b7bf66d21e0059910cbf78677e740772f30c92 Mon Sep 17 00:00:00 2001 From: "ISHIKAWA, Chiaki" Date: Thu, 23 Jul 2015 16:47:00 +0200 Subject: [PATCH 64/90] Bug 1187124 - Refer to $ANDROID_VERSION "... -ge 18" only when it is a non-empty string. r=gps --HG-- extra : rebase_source : 7e29fbc1e71ae5a639a194293450849090a29bc4 --- configure.in | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index b92c11a4a8b2..b719191d1871 100644 --- a/configure.in +++ b/configure.in @@ -5389,11 +5389,15 @@ if test -n "$MOZ_FMP4"; then MOZ_EME=1 fi; -if test "$MOZ_WIDGET_TOOLKIT" = "gonk" -a -n "$MOZ_FMP4" -a "$ANDROID_VERSION" -ge "18"; then - MOZ_GONK_MEDIACODEC=1 - AC_SUBST(MOZ_GONK_MEDIACODEC) +if test x"$MOZ_WIDGET_TOOLKIT" = x"gonk" -a -n "$MOZ_FMP4" -a -n "$ANDROID_VERSION"; then + # we now know for sure that $ANDROID_VERSION is not an empty string! + if test "$ANDROID_VERSION" -ge "18"; then + MOZ_GONK_MEDIACODEC=1 + AC_SUBST(MOZ_GONK_MEDIACODEC) + fi fi + dnl ======================================================== dnl = EME support dnl ======================================================== From dc0830276fb2a063527a9175d3c128a6d594d265 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Fri, 24 Jul 2015 02:25:00 +0200 Subject: [PATCH 65/90] Bug 1187193 - Use UserData() instead of Data() in ConstIter loops that used to be EnumerateRead's. r=njn --HG-- extra : rebase_source : db4109bfb53210a8b228c7e91427a636e2b5ea32 --- dom/media/gmp/GMPServiceParent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 3434763ff59d..3830030edf18 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -432,13 +432,13 @@ GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::Update(const nsCString note += pluginIt.Key(); note += ":{"; bool firstInstance = true; - for (auto instanceIt = pluginIt.Data()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) { + for (auto instanceIt = pluginIt.UserData()->ConstIter(); !instanceIt.Done(); instanceIt.Next()) { if (!firstInstance) { note += ','; } else { firstInstance = false; } note += instanceIt.Key(); note += ":\""; - note += instanceIt.Data()->mStateSequence; + note += instanceIt.UserData()->mStateSequence; note += '='; - note += instanceIt.Data()->mLastStateDescription; + note += instanceIt.UserData()->mLastStateDescription; note += '"'; } note += '}'; From 0d90569d2f23dc03333fe3b4d5a04bf6362b8d6b Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Fri, 24 Jul 2015 09:30:18 -0400 Subject: [PATCH 66/90] Bug 1186963 - Ignore files generated by running a Mozharness script. DONTBUILD. r=gps --- .hgignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.hgignore b/.hgignore index 411dd586ee79..6eed30b621b9 100644 --- a/.hgignore +++ b/.hgignore @@ -88,3 +88,7 @@ GPATH # XCode project cruft ^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata ^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata + +# Ignore mozharness execution files +^testing/mozharness/logs/ +^testing/mozharness/build/ From 8af3ab8b39c37b6a08d8d8082f845a79baa7a28b Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Sat, 25 Jul 2015 00:08:40 +1000 Subject: [PATCH 67/90] Bug 1186784 followup - Fix bustage on CLOSED TREE --HG-- extra : source : f960cf576fabd6347a513a8c38f27d4150b416a9 --- media/libav/libavcommon.mozbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libav/libavcommon.mozbuild b/media/libav/libavcommon.mozbuild index 40f410a97253..7def15201832 100644 --- a/media/libav/libavcommon.mozbuild +++ b/media/libav/libavcommon.mozbuild @@ -12,7 +12,7 @@ if CONFIG['OS_ARCH'] == 'WINNT': # Fix inline symbols and math defines for windows. DEFINES['_USE_MATH_DEFINES'] = True DEFINES['inline'] = "__inline" - if CONFIG['_MSC_VER'] and CONFIG['_MSC_VER'] < 1900: + if CONFIG['_MSC_VER'] and CONFIG['_MSC_VER'] < '1900': # snprintf is prefixed with an underscore on MSVC 2013. DEFINES['snprintf'] = "_snprintf" ASFLAGS += ['-Pconfig_win.asm'] From 9871ff062665685e1542d9aedc80bfa52e9717f6 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Fri, 24 Jul 2015 07:13:59 -0700 Subject: [PATCH 68/90] Bug 1186968 - Fix Compositor::SetScreenRotation() call r=nical --- gfx/layers/ipc/CompositorParent.cpp | 1 + gfx/layers/ipc/LayerTransactionParent.cpp | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 69b4d803bad6..f736c4d48318 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1264,6 +1264,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, // race condition. mLayerManager->UpdateRenderBounds(aTargetConfig.naturalBounds()); mLayerManager->SetRegionToClear(aTargetConfig.clearRegion()); + mLayerManager->GetCompositor()->SetScreenRotation(aTargetConfig.rotation()); mCompositionManager->Updated(aIsFirstPaint, aTargetConfig); Layer* root = aLayerTree->GetRoot(); diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 97e2b4a9995d..a719686aa5d8 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -245,11 +245,6 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray&& cset, return true; } - if (mLayerManager && mLayerManager->GetCompositor() && - !targetConfig.naturalBounds().IsEmpty()) { - mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation()); - } - EditReplyVector replyv; AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this); From dd5a9ed71e668868b7fda026586b38805dd9d321 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 24 Jul 2015 16:15:07 +0200 Subject: [PATCH 69/90] Backed out changeset a9241b319f14 (bug 1177951) on request per garndt in #taskcluster --HG-- extra : rebase_source : 307d50170829294e641b8a2193da4fcd3a46bb7d --- .../scripts/builder/install-packages.sh | 27 ++++++++++++++----- testing/taskcluster/tasks/build.yml | 2 -- .../tasks/builds/b2g_desktop_base.yml | 3 ++- .../taskcluster/tasks/builds/mulet_linux.yml | 1 - 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/testing/taskcluster/scripts/builder/install-packages.sh b/testing/taskcluster/scripts/builder/install-packages.sh index 710881eb3c06..2a290ea1c578 100755 --- a/testing/taskcluster/scripts/builder/install-packages.sh +++ b/testing/taskcluster/scripts/builder/install-packages.sh @@ -2,11 +2,26 @@ gecko_dir=$1 test -d $gecko_dir -test -n "$TOOLTOOL_CACHE" -test -n "$TOOLTOOL_MANIFEST" -test -n "$TOOLTOOL_REPO" -test -n "$TOOLTOOL_REV" -tc-vcs checkout $gecko_dir/tooltool $TOOLTOOL_REPO $TOOLTOOL_REPO $TOOLTOOL_REV +if [ ! -d "$gecko_dir/gcc" ]; then + cd $gecko_dir + curl https://s3-us-west-2.amazonaws.com/test-caching/packages/gcc.tar.xz | tar Jx + cd - +fi -(cd $gecko_dir; python $gecko_dir/tooltool/tooltool.py --url https://api.pub.build.mozilla.org/tooltool/ --overwrite -m $gecko_dir/$TOOLTOOL_MANIFEST fetch -c $TOOLTOOL_CACHE) +if [ ! -d "$gecko_dir/sccache" ]; then + cd $gecko_dir + curl https://s3-us-west-2.amazonaws.com/test-caching/packages/sccache.tar.bz2 | tar jx + cd - +fi + +# Remove cached moztt directory if it exists when a user supplied a git url/revision +if [ ! -z $MOZTT_GIT_URL ] || [ ! -z $MOZTT_REVISION ]; then + echo "Removing cached moztt package" + rm -rf moztt +fi + +moztt_url=${MOZTT_GIT_URL:=https://github.com/mozilla-b2g/moztt} +moztt_revision=${MOZTT_REVISION:=master} + +tc-vcs checkout $gecko_dir/moztt $moztt_url $moztt_url $moztt_revision diff --git a/testing/taskcluster/tasks/build.yml b/testing/taskcluster/tasks/build.yml index 79a9764249d9..02c2245227b4 100644 --- a/testing/taskcluster/tasks/build.yml +++ b/testing/taskcluster/tasks/build.yml @@ -55,8 +55,6 @@ task: MOZHARNESS_REPOSITORY: '{{mozharness_repository}}' MOZHARNESS_REV: '{{mozharness_rev}}' MOZHARNESS_REF: '{{mozharness_ref}}' - TOOLTOOL_REPO: 'https://github.com/mozilla/build-tooltool' - TOOLTOOL_REV: 'master' extra: index: diff --git a/testing/taskcluster/tasks/builds/b2g_desktop_base.yml b/testing/taskcluster/tasks/builds/b2g_desktop_base.yml index 2651e141c340..b86b35f428fa 100644 --- a/testing/taskcluster/tasks/builds/b2g_desktop_base.yml +++ b/testing/taskcluster/tasks/builds/b2g_desktop_base.yml @@ -9,7 +9,8 @@ task: payload: env: MOZCONFIG: 'b2g/config/mozconfigs/linux64_gecko/nightly' - TOOLTOOL_MANIFEST: 'b2g/config/tooltool-manifests/linux64/releng.manifest' + MOZTT_GIT_URL: '{{moztt_git_url}}' + MOZTT_REVISION: '{{moztt_revision}}' command: - /bin/bash diff --git a/testing/taskcluster/tasks/builds/mulet_linux.yml b/testing/taskcluster/tasks/builds/mulet_linux.yml index 572c47051dcd..158b718fcf6a 100644 --- a/testing/taskcluster/tasks/builds/mulet_linux.yml +++ b/testing/taskcluster/tasks/builds/mulet_linux.yml @@ -29,7 +29,6 @@ task: env: MOZCONFIG: 'b2g/dev/config/mozconfigs/linux64/mulet' - TOOLTOOL_MANIFEST: 'b2g/dev/config/tooltool-manifests/linux64/releng.manifest' maxRunTime: 3600 From bae1e652bf12203097a8ad9e898b604b1d62b1f8 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Thu, 9 Jul 2015 16:40:08 +0200 Subject: [PATCH 70/90] Bug 1156472 - Part 1 - Allow to capture all HTMLMediaElements and AudioContexts for a document. r=baku,padenot This is built on top of the AudioChannel infrastructure. This patch does not actually implement the capture, it just does the plumbing to be able to notify all HTMLMediaElement/AudioContext for a document. --- dom/audiochannel/AudioChannelAgent.cpp | 20 ++++++++++++++++++ dom/audiochannel/AudioChannelAgent.h | 2 ++ dom/audiochannel/AudioChannelService.cpp | 23 +++++++++++++++++++++ dom/audiochannel/AudioChannelService.h | 8 +++++++ dom/audiochannel/nsIAudioChannelAgent.idl | 7 ++++++- dom/base/nsGlobalWindow.cpp | 22 +++++++++++++++++++- dom/base/nsPIDOMWindow.h | 5 +++++ dom/fmradio/FMRadio.cpp | 6 ++++++ dom/html/HTMLMediaElement.cpp | 15 +++++++++++++- dom/media/webaudio/AudioDestinationNode.cpp | 17 +++++++++++++++ 10 files changed, 122 insertions(+), 3 deletions(-) diff --git a/dom/audiochannel/AudioChannelAgent.cpp b/dom/audiochannel/AudioChannelAgent.cpp index c02602db25de..3a68bdd371ac 100644 --- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -35,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent) AudioChannelAgent::AudioChannelAgent() : mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR) + , mInnerWindowID(0) , mIsRegToService(false) { } @@ -104,6 +105,10 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType, } if (aWindow) { + nsCOMPtr pInnerWindow = do_QueryInterface(aWindow); + MOZ_ASSERT(pInnerWindow->IsInnerWindow()); + mInnerWindowID = pInnerWindow->WindowID(); + nsCOMPtr topWindow; aWindow->GetScriptableTop(getter_AddRefs(topWindow)); mWindow = do_QueryInterface(topWindow); @@ -191,3 +196,18 @@ AudioChannelAgent::WindowID() const { return mWindow ? mWindow->WindowID() : 0; } + +void +AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID) +{ + if (aInnerWindowID != mInnerWindowID) { + return; + } + + nsCOMPtr callback = GetCallback(); + if (!callback) { + return; + } + + callback->WindowAudioCaptureChanged(); +} diff --git a/dom/audiochannel/AudioChannelAgent.h b/dom/audiochannel/AudioChannelAgent.h index 75b2fd335edc..809d34f2a1e7 100644 --- a/dom/audiochannel/AudioChannelAgent.h +++ b/dom/audiochannel/AudioChannelAgent.h @@ -34,6 +34,7 @@ public: AudioChannelAgent(); void WindowVolumeChanged(); + void WindowAudioCaptureChanged(uint64_t aInnerWindowID); nsPIDOMWindow* Window() const { @@ -61,6 +62,7 @@ private: nsWeakPtr mWeakCallback; int32_t mAudioChannelType; + uint64_t mInnerWindowID; bool mIsRegToService; }; diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index c3b858ab7761..b71b491c5078 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -546,6 +546,29 @@ AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow) } } +void +AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow, + uint64_t aInnerWindowID) +{ + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aWindow->IsOuterWindow()); + + nsCOMPtr topWindow; + aWindow->GetScriptableTop(getter_AddRefs(topWindow)); + nsCOMPtr pTopWindow = do_QueryInterface(topWindow); + if (!pTopWindow) { + return; + } + + AudioChannelWindow* winData = GetWindowData(pTopWindow->WindowID()); + + nsTObserverArray::ForwardIterator + iter(winData->mAgents); + while (iter.HasMore()) { + iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID); + } +} + /* static */ const nsAttrValue::EnumTable* AudioChannelService::GetAudioChannelTable() { diff --git a/dom/audiochannel/AudioChannelService.h b/dom/audiochannel/AudioChannelService.h index a0a65d8c737a..4dc0bedb7475 100644 --- a/dom/audiochannel/AudioChannelService.h +++ b/dom/audiochannel/AudioChannelService.h @@ -102,6 +102,14 @@ public: void RefreshAgentsVolume(nsPIDOMWindow* aWindow); + // This method needs to know the inner window that wants to capture audio. We + // group agents per top outer window, but we can have multiple innerWindow per + // top outerWindow (subiframes, etc.) and we have to identify all the agents + // just for a particular innerWindow. + void RefreshAgentsCapture(nsPIDOMWindow* aWindow, + uint64_t aInnerWindowID); + + #ifdef MOZ_WIDGET_GONK void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager) { diff --git a/dom/audiochannel/nsIAudioChannelAgent.idl b/dom/audiochannel/nsIAudioChannelAgent.idl index a35f54c09530..87934d4bacc0 100644 --- a/dom/audiochannel/nsIAudioChannelAgent.idl +++ b/dom/audiochannel/nsIAudioChannelAgent.idl @@ -6,13 +6,18 @@ interface nsIDOMWindow; -[uuid(4f537c88-3722-4946-9a09-ce559fa0591d)] +[uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)] interface nsIAudioChannelAgentCallback : nsISupports { /** * Notified when the window volume/mute is changed */ void windowVolumeChanged(in float aVolume, in bool aMuted); + + /** + * Notified when the capture state is changed. + */ + void windowAudioCaptureChanged(); }; /** diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 3827f6b57a01..59483a458bd1 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -564,7 +564,7 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow) mMayHavePointerEnterLeaveEventListener(false), mIsModalContentWindow(false), mIsActive(false), mIsBackground(false), - mAudioMuted(false), mAudioVolume(1.0), + mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false), mDesktopModeViewport(false), mInnerWindow(nullptr), mOuterWindow(aOuterWindow), // Make sure no actual window ends up with mWindowID == 0 @@ -3745,6 +3745,26 @@ nsPIDOMWindow::RefreshMediaElements() service->RefreshAgentsVolume(GetOuterWindow()); } +bool +nsPIDOMWindow::GetAudioCaptured() const +{ + MOZ_ASSERT(IsInnerWindow()); + return mAudioCaptured; +} + +nsresult +nsPIDOMWindow::SetAudioCapture(bool aCapture) +{ + MOZ_ASSERT(IsInnerWindow()); + + mAudioCaptured = aCapture; + + nsRefPtr service = AudioChannelService::GetOrCreate(); + service->RefreshAgentsCapture(GetOuterWindow(), mWindowID); + + return NS_OK; +} + // nsISpeechSynthesisGetter #ifdef MOZ_WEBSPEECH diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index b9f17bb801a4..3e6404e9950c 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -185,6 +185,9 @@ public: float GetAudioVolume() const; nsresult SetAudioVolume(float aVolume); + bool GetAudioCaptured() const; + nsresult SetAudioCapture(bool aCapture); + virtual void SetServiceWorkersTestingEnabled(bool aEnabled) { MOZ_ASSERT(IsOuterWindow()); @@ -822,6 +825,8 @@ protected: bool mAudioMuted; float mAudioVolume; + bool mAudioCaptured; + // current desktop mode flag. bool mDesktopModeViewport; diff --git a/dom/fmradio/FMRadio.cpp b/dom/fmradio/FMRadio.cpp index 1f5d8de3f0e1..150ee703a1f7 100644 --- a/dom/fmradio/FMRadio.cpp +++ b/dom/fmradio/FMRadio.cpp @@ -471,6 +471,12 @@ FMRadio::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } +NS_IMETHODIMP +FMRadio::WindowAudioCaptureChanged() +{ + return NS_OK; +} + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 493bbd26678a..42c5f63f7774 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4492,7 +4492,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() if (!mAudioChannelAgent) { return; } - mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(), + mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(), static_cast(mAudioChannel), this); } @@ -4504,6 +4504,10 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() void HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) { + // Immediately check if this should go to the MSG instead of the normal + // media playback route. + WindowAudioCaptureChanged(); + // This is needed to pass nsContentUtils::IsCallerChrome(). // AudioChannel API should not called from content but it can happen that // this method has some content JS in its stack. @@ -4674,6 +4678,15 @@ HTMLMediaElement::GetTopLevelPrincipal() } #endif // MOZ_EME +NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged() +{ + MOZ_ASSERT(mAudioChannelAgent); + DebugOnly captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured(); + + // Something is going to happen here!! + return NS_OK; +} + AudioTrackList* HTMLMediaElement::AudioTracks() { diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 95ab1b413459..3f5a3650a0df 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -505,6 +505,21 @@ AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } +NS_IMETHODIMP +AudioDestinationNode::WindowAudioCaptureChanged() +{ + MOZ_ASSERT(mAudioChannelAgent); + + if (!mStream) { + return NS_OK; + } + + DebugOnly captured = GetOwner()->GetAudioCaptured(); + + // XXXtodopadenot actually capture + return NS_OK; +} + AudioChannel AudioDestinationNode::MozAudioChannelType() const { @@ -591,6 +606,8 @@ AudioDestinationNode::CreateAudioChannelAgent() // The AudioChannelAgent must start playing immediately in order to avoid // race conditions with mozinterruptbegin/end events. InputMuted(false); + + WindowAudioCaptureChanged(); } void From f6609f50c3085af1798540a21c83858731b9fddd Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:16 +0200 Subject: [PATCH 71/90] Bug 1156472 - Part 2 - Rename MediaEngineWebRTCAudioSource to MediaEngineWebRTCMicrophoneSource. r=jesup There are now two different possible audio source, so this was getting confusing. --- dom/media/webrtc/MediaEngineWebRTC.cpp | 7 ++- dom/media/webrtc/MediaEngineWebRTC.h | 18 +++++--- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 48 +++++++++++---------- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp index 8771ef79af7c..34adf582ed88 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.cpp +++ b/dom/media/webrtc/MediaEngineWebRTC.cpp @@ -358,15 +358,14 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource, strcpy(uniqueId,deviceName); // safe given assert and initialization/error-check } - nsRefPtr aSource; + nsRefPtr aSource; NS_ConvertUTF8toUTF16 uuid(uniqueId); if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) { // We've already seen this device, just append. aASources->AppendElement(aSource.get()); } else { - aSource = new MediaEngineWebRTCAudioSource( - mThread, mVoiceEngine, i, deviceName, uniqueId - ); + aSource = new MediaEngineWebRTCMicrophoneSource(mThread, mVoiceEngine, i, + deviceName, uniqueId); mAudioSources.Put(uuid, aSource); // Hashtable takes ownership. aASources->AppendElement(aSource); } diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 105cca560048..8b05480718b6 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -133,13 +133,16 @@ private: void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) override; }; -class MediaEngineWebRTCAudioSource : public MediaEngineAudioSource, - public webrtc::VoEMediaProcess, - private MediaConstraintsHelper +class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource, + public webrtc::VoEMediaProcess, + private MediaConstraintsHelper { public: - MediaEngineWebRTCAudioSource(nsIThread* aThread, webrtc::VoiceEngine* aVoiceEnginePtr, - int aIndex, const char* name, const char* uuid) + MediaEngineWebRTCMicrophoneSource(nsIThread* aThread, + webrtc::VoiceEngine* aVoiceEnginePtr, + int aIndex, + const char* name, + const char* uuid) : MediaEngineAudioSource(kReleased) , mVoiceEngine(aVoiceEnginePtr) , mMonitor("WebRTCMic.Monitor") @@ -207,7 +210,7 @@ public: virtual void Shutdown() override; protected: - ~MediaEngineWebRTCAudioSource() { Shutdown(); } + ~MediaEngineWebRTCMicrophoneSource() { Shutdown(); } private: void Init(); @@ -294,7 +297,8 @@ private: // Store devices we've already seen in a hashtable for quick return. // Maps UUID to MediaEngineSource (one set for audio, one for video). nsRefPtrHashtable mVideoSources; - nsRefPtrHashtable mAudioSources; + nsRefPtrHashtable + mAudioSources; }; } diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index c85c5710c193..2aca1ecbbf99 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -41,9 +41,9 @@ extern PRLogModuleInfo* GetMediaManagerLog(); #define LOG_FRAMES(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg) /** - * Webrtc audio source. + * Webrtc microphone source source. */ -NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioSource) +NS_IMPL_ISUPPORTS0(MediaEngineWebRTCMicrophoneSource) // XXX temp until MSG supports registration StaticRefPtr gFarendObserver; @@ -177,7 +177,7 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame } void -MediaEngineWebRTCAudioSource::GetName(nsAString& aName) +MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) { if (mInitDone) { aName.Assign(mDeviceName); @@ -187,7 +187,7 @@ MediaEngineWebRTCAudioSource::GetName(nsAString& aName) } void -MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID) +MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID) { if (mInitDone) { aUUID.Assign(mDeviceUUID); @@ -197,10 +197,10 @@ MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID) } nsresult -MediaEngineWebRTCAudioSource::Config(bool aEchoOn, uint32_t aEcho, - bool aAgcOn, uint32_t aAGC, - bool aNoiseOn, uint32_t aNoise, - int32_t aPlayoutDelay) +MediaEngineWebRTCMicrophoneSource::Config(bool aEchoOn, uint32_t aEcho, + bool aAgcOn, uint32_t aAGC, + bool aNoiseOn, uint32_t aNoise, + int32_t aPlayoutDelay) { LOG(("Audio config: aec: %d, agc: %d, noise: %d", aEchoOn ? aEcho : -1, @@ -281,9 +281,9 @@ uint32_t MediaEngineWebRTCAudioSource::GetBestFitnessDistance( } nsresult -MediaEngineWebRTCAudioSource::Allocate(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs, - const nsString& aDeviceId) +MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) { if (mState == kReleased) { if (mInitDone) { @@ -309,7 +309,7 @@ MediaEngineWebRTCAudioSource::Allocate(const dom::MediaTrackConstraints &aConstr } nsresult -MediaEngineWebRTCAudioSource::Deallocate() +MediaEngineWebRTCMicrophoneSource::Deallocate() { bool empty; { @@ -331,7 +331,8 @@ MediaEngineWebRTCAudioSource::Deallocate() } nsresult -MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID) +MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream, + TrackID aID) { if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; @@ -384,7 +385,7 @@ MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID) } nsresult -MediaEngineWebRTCAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) +MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID) { { MonitorAutoLock lock(mMonitor); @@ -421,17 +422,17 @@ MediaEngineWebRTCAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) } void -MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph, - SourceMediaStream *aSource, - TrackID aID, - StreamTime aDesiredTime) +MediaEngineWebRTCMicrophoneSource::NotifyPull(MediaStreamGraph *aGraph, + SourceMediaStream *aSource, + TrackID aID, + StreamTime aDesiredTime) { // Ignore - we push audio data LOG_FRAMES(("NotifyPull, desired = %ld", (int64_t) aDesiredTime)); } void -MediaEngineWebRTCAudioSource::Init() +MediaEngineWebRTCMicrophoneSource::Init() { mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine); @@ -496,7 +497,7 @@ MediaEngineWebRTCAudioSource::Init() } void -MediaEngineWebRTCAudioSource::Shutdown() +MediaEngineWebRTCMicrophoneSource::Shutdown() { if (!mInitDone) { // duplicate these here in case we failed during Init() @@ -551,9 +552,10 @@ MediaEngineWebRTCAudioSource::Shutdown() typedef int16_t sample; void -MediaEngineWebRTCAudioSource::Process(int channel, - webrtc::ProcessingTypes type, sample* audio10ms, - int length, int samplingFreq, bool isStereo) +MediaEngineWebRTCMicrophoneSource::Process(int channel, + webrtc::ProcessingTypes type, + sample *audio10ms, int length, + int samplingFreq, bool isStereo) { // On initial capture, throw away all far-end data except the most recent sample // since it's already irrelevant and we want to keep avoid confusing the AEC far-end From 4eb22368c825dffe6bcf166a47b48fec4338acfe Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:16 +0200 Subject: [PATCH 72/90] Bug 1156472 - Part 3 - Implement AudioCaptureStream. r=roc It is a ProcessMediaStream that simply mixes its inputs into a mono stream, up/down mixing appropriately. --- dom/media/AudioCaptureStream.cpp.rej | 133 +++++++++++++++++++++++++++ dom/media/AudioCaptureStream.h.rej | 43 +++++++++ dom/media/AudioMixer.h | 6 +- dom/media/AudioSegment.cpp | 97 +++++++++++++++++++ dom/media/AudioSegment.h | 9 +- dom/media/DOMMediaStream.cpp | 30 ++++++ dom/media/DOMMediaStream.h | 15 +++ dom/media/moz.build | 1 + 8 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 dom/media/AudioCaptureStream.cpp.rej create mode 100644 dom/media/AudioCaptureStream.h.rej diff --git a/dom/media/AudioCaptureStream.cpp.rej b/dom/media/AudioCaptureStream.cpp.rej new file mode 100644 index 000000000000..5a0dcd271be8 --- /dev/null +++ b/dom/media/AudioCaptureStream.cpp.rej @@ -0,0 +1,133 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "MediaStreamGraphImpl.h" ++#include "mozilla/MathAlgorithms.h" ++#include "mozilla/unused.h" ++ ++#include "AudioSegment.h" ++#include "mozilla/Logging.h" ++#include "mozilla/Attributes.h" ++#include "AudioCaptureStream.h" ++#include "ImageContainer.h" ++#include "AudioNodeEngine.h" ++#include "AudioNodeStream.h" ++#include "AudioNodeExternalInputStream.h" ++#include "webaudio/MediaStreamAudioDestinationNode.h" ++#include ++#include "DOMMediaStream.h" ++ ++using namespace mozilla::layers; ++using namespace mozilla::dom; ++using namespace mozilla::gfx; ++ ++namespace mozilla ++{ ++ ++// We are mixing to mono until PeerConnection can accept stereo ++static const uint32_t MONO = 1; ++ ++AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper) ++ : ProcessedMediaStream(aWrapper), mTrackCreated(false) ++{ ++ MOZ_ASSERT(NS_IsMainThread()); ++ MOZ_COUNT_CTOR(AudioCaptureStream); ++ mMixer.AddCallback(this); ++} ++ ++AudioCaptureStream::~AudioCaptureStream() ++{ ++ MOZ_COUNT_DTOR(AudioCaptureStream); ++ mMixer.RemoveCallback(this); ++} ++ ++void ++AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, ++ uint32_t aFlags) ++{ ++ uint32_t inputCount = mInputs.Length(); ++ StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); ++ // Notify the DOM everything is in order. ++ if (!mTrackCreated) { ++ for (uint32_t i = 0; i < mListeners.Length(); i++) { ++ MediaStreamListener* l = mListeners[i]; ++ AudioSegment tmp; ++ l->NotifyQueuedTrackChanges( ++ Graph(), AUDIO_TRACK, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp); ++ l->NotifyFinishedTrackCreation(Graph()); ++ } ++ mTrackCreated = true; ++ } ++ ++ // If the captured stream is connected back to a object on the page (be it an ++ // HTMLMediaElement with a stream as source, or an AudioContext), a cycle ++ // situation occur. This can work if it's an AudioContext with at least one ++ // DelayNode, but the MSG will mute the whole cycle otherwise. ++ bool blocked = mFinished || mBlocked.GetAt(aFrom); ++ if (blocked || InMutedCycle() || inputCount == 0) { ++ track->Get()->AppendNullData(aTo - aFrom); ++ } else { ++ // We mix down all the tracks of all inputs, to a stereo track. Everything ++ // is {up,down}-mixed to stereo. ++ mMixer.StartMixing(); ++ AudioSegment output; ++ for (uint32_t i = 0; i < inputCount; i++) { ++ MediaStream* s = mInputs[i]->GetSource(); ++ StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO); ++ while (!tracks.IsEnded()) { ++ AudioSegment* inputSegment = tracks->Get(); ++ StreamTime inputStart = s->GraphTimeToStreamTime(aFrom); ++ StreamTime inputEnd = s->GraphTimeToStreamTime(aTo); ++ AudioSegment toMix; ++ toMix.AppendSlice(*inputSegment, inputStart, inputEnd); ++ // Care for streams blocked in the [aTo, aFrom] range. ++ if (inputEnd - inputStart < aTo - aFrom) { ++ toMix.AppendNullData((aTo - aFrom) - (inputEnd - inputStart)); ++ } ++ toMix.Mix(mMixer, MONO, Graph()->GraphRate()); ++ tracks.Next(); ++ } ++ } ++ // This calls MixerCallback below ++ mMixer.FinishMixing(); ++ } ++ ++ // Regardless of the status of the input tracks, we go foward. ++ mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime((aTo))); ++} ++ ++void ++AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer, ++ AudioSampleFormat aFormat, uint32_t aChannels, ++ uint32_t aFrames, uint32_t aSampleRate) ++{ ++ nsAutoTArray, MONO> output; ++ nsAutoTArray bufferPtrs; ++ output.SetLength(MONO); ++ bufferPtrs.SetLength(MONO); ++ ++ uint32_t written = 0; ++ // We need to copy here, because the mixer will reuse the storage, we should ++ // not hold onto it. Buffers are in planar format. ++ for (uint32_t channel = 0; channel < aChannels; channel++) { ++ float* out = output[channel].AppendElements(aFrames); ++ PodCopy(out, aMixedBuffer + written, aFrames); ++ bufferPtrs[channel] = out; ++ written += aFrames; ++ } ++ AudioChunk chunk; ++ chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(&output); ++ chunk.mDuration = aFrames; ++ chunk.mBufferFormat = AUDIO_FORMAT_FLOAT32; ++ chunk.mVolume = 1.0f; ++ chunk.mChannelData.SetLength(MONO); ++ for (uint32_t channel = 0; channel < aChannels; channel++) { ++ chunk.mChannelData[channel] = bufferPtrs[channel]; ++ } ++ ++ // Now we have mixed data, simply append it to out track. ++ EnsureTrack(AUDIO_TRACK)->Get()->AppendAndConsumeChunk(&chunk); ++} ++} diff --git a/dom/media/AudioCaptureStream.h.rej b/dom/media/AudioCaptureStream.h.rej new file mode 100644 index 000000000000..3c05c50e8525 --- /dev/null +++ b/dom/media/AudioCaptureStream.h.rej @@ -0,0 +1,43 @@ +--- AudioCaptureStream.h ++++ AudioCaptureStream.h +@@ -0,0 +1,40 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef MOZILLA_AUDIOCAPTURESTREAM_H_ ++#define MOZILLA_AUDIOCAPTURESTREAM_H_ ++ ++#include "MediaStreamGraph.h" ++#include "AudioMixer.h" ++#include ++ ++namespace mozilla ++{ ++ ++class DOMMediaStream; ++ ++/** ++ * See MediaStreamGraph::CreateAudioCaptureStream. ++ */ ++class AudioCaptureStream : public ProcessedMediaStream, ++ public MixerCallbackReceiver ++{ ++public: ++ explicit AudioCaptureStream(DOMMediaStream* aWrapper); ++ virtual ~AudioCaptureStream(); ++ ++ void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override; ++ ++protected: ++ enum { AUDIO_TRACK = 1 }; ++ void MixerCallback(AudioDataValue* aMixedBuffer, AudioSampleFormat aFormat, ++ uint32_t aChannels, uint32_t aFrames, ++ uint32_t aSampleRate) override; ++ AudioMixer mMixer; ++ bool mTrackCreated; ++}; ++} ++ ++#endif /* MOZILLA_AUDIOCAPTURESTREAM_H_ */ diff --git a/dom/media/AudioMixer.h b/dom/media/AudioMixer.h index c992942e25f9..c86aa33455b3 100644 --- a/dom/media/AudioMixer.h +++ b/dom/media/AudioMixer.h @@ -26,7 +26,9 @@ struct MixerCallbackReceiver { * stream. * * AudioMixer::Mix is to be called repeatedly with buffers that have the same - * length, sample rate, sample format and channel count. + * length, sample rate, sample format and channel count. This class works with + * interleaved and plannar buffers, but the buffer mixed must be of the same + * type during a mixing cycle. * * When all the tracks have been mixed, calling FinishMixing will call back with * a buffer containing the mixed audio data. @@ -71,7 +73,7 @@ public: mSampleRate = mChannels = mFrames = 0; } - /* Add a buffer to the mix. aSamples is interleaved. */ + /* Add a buffer to the mix. */ void Mix(AudioDataValue* aSamples, uint32_t aChannels, uint32_t aFrames, diff --git a/dom/media/AudioSegment.cpp b/dom/media/AudioSegment.cpp index ddd16bbe16a5..15ac13e5537b 100644 --- a/dom/media/AudioSegment.cpp +++ b/dom/media/AudioSegment.cpp @@ -146,6 +146,103 @@ void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler, uint32_t aInR } } +// This helps to to safely get a pointer to the position we want to start +// writing a planar audio buffer, depending on the channel and the offset in the +// buffer. +static AudioDataValue* +PointerForOffsetInChannel(AudioDataValue* aData, size_t aLengthSamples, + uint32_t aChannelCount, uint32_t aChannel, + uint32_t aOffsetSamples) +{ + size_t samplesPerChannel = aLengthSamples / aChannelCount; + size_t beginningOfChannel = samplesPerChannel * aChannel; + MOZ_ASSERT(aChannel * samplesPerChannel + aOffsetSamples < aLengthSamples, + "Offset request out of bounds."); + return aData + beginningOfChannel + aOffsetSamples; +} + +void +AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels, + uint32_t aSampleRate) +{ + nsAutoTArray + buf; + nsAutoTArray channelData; + uint32_t offsetSamples = 0; + uint32_t duration = GetDuration(); + + if (duration <= 0) { + MOZ_ASSERT(duration == 0); + return; + } + + uint32_t outBufferLength = duration * aOutputChannels; + buf.SetLength(outBufferLength); + + for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) { + AudioChunk& c = *ci; + uint32_t frames = c.mDuration; + + // If the chunk is silent, simply write the right number of silence in the + // buffers. + if (c.mBufferFormat == AUDIO_FORMAT_SILENCE) { + for (uint32_t channel = 0; channel < aOutputChannels; channel++) { + AudioDataValue* ptr = + PointerForOffsetInChannel(buf.Elements(), outBufferLength, + aOutputChannels, channel, offsetSamples); + PodZero(ptr, frames); + } + } else { + // Othewise, we need to upmix or downmix appropriately, depending on the + // desired input and output channels. + channelData.SetLength(c.mChannelData.Length()); + for (uint32_t i = 0; i < channelData.Length(); ++i) { + channelData[i] = c.mChannelData[i]; + } + if (channelData.Length() < aOutputChannels) { + // Up-mix. + AudioChannelsUpMix(&channelData, aOutputChannels, gZeroChannel); + for (uint32_t channel = 0; channel < aOutputChannels; channel++) { + AudioDataValue* ptr = + PointerForOffsetInChannel(buf.Elements(), outBufferLength, + aOutputChannels, channel, offsetSamples); + PodCopy(ptr, reinterpret_cast(channelData[channel]), + frames); + } + MOZ_ASSERT(channelData.Length() == aOutputChannels); + } else if (channelData.Length() > aOutputChannels) { + // Down mix. + nsAutoTArray outChannelPtrs; + outChannelPtrs.SetLength(aOutputChannels); + uint32_t offsetSamples = 0; + for (uint32_t channel = 0; channel < aOutputChannels; channel++) { + outChannelPtrs[channel] = + PointerForOffsetInChannel(buf.Elements(), outBufferLength, + aOutputChannels, channel, offsetSamples); + } + AudioChannelsDownMix(channelData, outChannelPtrs.Elements(), + aOutputChannels, frames); + } else { + // The channel count is already what we want, just copy it over. + for (uint32_t channel = 0; channel < aOutputChannels; channel++) { + AudioDataValue* ptr = + PointerForOffsetInChannel(buf.Elements(), outBufferLength, + aOutputChannels, channel, offsetSamples); + PodCopy(ptr, reinterpret_cast(channelData[channel]), + frames); + } + } + } + offsetSamples += frames; + } + + if (offsetSamples) { + MOZ_ASSERT(offsetSamples == outBufferLength / aOutputChannels, + "We forgot to write some samples?"); + aMixer.Mix(buf.Elements(), aOutputChannels, offsetSamples, aSampleRate); + } +} + void AudioSegment::WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aOutputChannels, uint32_t aSampleRate) { diff --git a/dom/media/AudioSegment.h b/dom/media/AudioSegment.h index 22bad4e7790a..25c0057f1b7f 100644 --- a/dom/media/AudioSegment.h +++ b/dom/media/AudioSegment.h @@ -299,7 +299,14 @@ public: return chunk; } void ApplyVolume(float aVolume); - void WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aChannelCount, uint32_t aSampleRate); + // Mix the segment into a mixer, interleaved. This is useful to output a + // segment to a system audio callback. It up or down mixes to aChannelCount + // channels. + void WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aChannelCount, + uint32_t aSampleRate); + // Mix the segment into a mixer, keeping it planar, up or down mixing to + // aChannelCount channels. + void Mix(AudioMixer& aMixer, uint32_t aChannelCount, uint32_t aSampleRate); int ChannelCount() { NS_WARN_IF_FALSE(!mChunks.IsEmpty(), diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 40bdee8bd364..e75d5fbfad02 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -301,6 +301,18 @@ DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, InitStreamCommon(aGraph->CreateTrackUnionStream(this)); } +void +DOMMediaStream::InitAudioCaptureStream(nsIDOMWindow* aWindow, + MediaStreamGraph* aGraph) +{ + mWindow = aWindow; + + if (!aGraph) { + aGraph = MediaStreamGraph::GetInstance(); + } + InitStreamCommon(aGraph->CreateAudioCaptureStream(this)); +} + void DOMMediaStream::InitStreamCommon(MediaStream* aStream) { @@ -329,6 +341,15 @@ DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, return stream.forget(); } +already_AddRefed +DOMMediaStream::CreateAudioCaptureStream(nsIDOMWindow* aWindow, + MediaStreamGraph* aGraph) +{ + nsRefPtr stream = new DOMMediaStream(); + stream->InitAudioCaptureStream(aWindow, aGraph); + return stream.forget(); +} + void DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled) { @@ -653,6 +674,15 @@ DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, return stream.forget(); } +already_AddRefed +DOMLocalMediaStream::CreateAudioCaptureStream(nsIDOMWindow* aWindow, + MediaStreamGraph* aGraph) +{ + nsRefPtr stream = new DOMLocalMediaStream(); + stream->InitAudioCaptureStream(aWindow, aGraph); + return stream.forget(); +} + DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(AudioNode* aNode) : mStreamNode(aNode) { diff --git a/dom/media/DOMMediaStream.h b/dom/media/DOMMediaStream.h index ebad4e70afbc..fb7bac8733b4 100644 --- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -198,6 +198,13 @@ public: static already_AddRefed CreateTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); + /** + * Create an nsDOMMediaStream whose underlying stream is an + * AudioCaptureStream + */ + static already_AddRefed CreateAudioCaptureStream( + nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); + void SetLogicalStreamStartTime(StreamTime aTime) { mLogicalStreamStartTime = aTime; @@ -261,6 +268,8 @@ protected: MediaStreamGraph* aGraph = nullptr); void InitTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); + void InitAudioCaptureStream(nsIDOMWindow* aWindow, + MediaStreamGraph* aGraph = nullptr); void InitStreamCommon(MediaStream* aStream); already_AddRefed CreateAudioTrack(AudioStreamTrack* aStreamTrack); already_AddRefed CreateVideoTrack(VideoStreamTrack* aStreamTrack); @@ -351,6 +360,12 @@ public: CreateTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); + /** + * Create an nsDOMLocalMediaStream whose underlying stream is an + * AudioCaptureStream. */ + static already_AddRefed CreateAudioCaptureStream( + nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); + protected: virtual ~DOMLocalMediaStream(); }; diff --git a/dom/media/moz.build b/dom/media/moz.build index 63c6fa3366bd..25d2dbb728d1 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -196,6 +196,7 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'AbstractThread.cpp', + 'AudioCaptureStream.cpp', 'AudioChannelFormat.cpp', 'AudioCompactor.cpp', 'AudioSegment.cpp', From 4bc48d01347b9b80a19734f86e86f73e334e1261 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:16 +0200 Subject: [PATCH 73/90] Bug 1156472 - Part 4 - Add a new MediaStreamGraph API to connect a MediaStream to a capture stream. r=jesup,roc --- dom/media/MediaStreamGraph.cpp | 73 ++++++++++++++++++++++++++++++++ dom/media/MediaStreamGraph.h | 10 +++++ dom/media/MediaStreamGraphImpl.h | 17 ++++++++ 3 files changed, 100 insertions(+) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 53144c054893..a23fba28f998 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -18,6 +18,7 @@ #include "mozilla/Attributes.h" #include "TrackUnionStream.h" #include "ImageContainer.h" +#include "AudioCaptureStream.h" #include "AudioChannelService.h" #include "AudioNodeEngine.h" #include "AudioNodeStream.h" @@ -3192,6 +3193,17 @@ MediaStreamGraph::CreateTrackUnionStream(DOMMediaStream* aWrapper) return stream; } +ProcessedMediaStream* +MediaStreamGraph::CreateAudioCaptureStream(DOMMediaStream* aWrapper) +{ + AudioCaptureStream* stream = new AudioCaptureStream(aWrapper); + NS_ADDREF(stream); + MediaStreamGraphImpl* graph = static_cast(this); + stream->SetGraphImpl(graph); + graph->AppendMessage(new CreateMessage(stream)); + return stream; +} + AudioNodeExternalInputStream* MediaStreamGraph::CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate) { @@ -3556,4 +3568,65 @@ ProcessedMediaStream::AddInput(MediaInputPort* aPort) GraphImpl()->SetStreamOrderDirty(); } +void +MediaStreamGraph::RegisterCaptureStreamForWindow( + uint64_t aWindowId, ProcessedMediaStream* aCaptureStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + MediaStreamGraphImpl* graphImpl = static_cast(this); + graphImpl->RegisterCaptureStreamForWindow(aWindowId, aCaptureStream); +} + +void +MediaStreamGraphImpl::RegisterCaptureStreamForWindow( + uint64_t aWindowId, ProcessedMediaStream* aCaptureStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + WindowAndStream winAndStream; + winAndStream.mWindowId = aWindowId; + winAndStream.mCaptureStreamSink = aCaptureStream; + mWindowCaptureStreams.AppendElement(winAndStream); +} + +void +MediaStreamGraph::UnregisterCaptureStreamForWindow(uint64_t aWindowId) +{ + MOZ_ASSERT(NS_IsMainThread()); + MediaStreamGraphImpl* graphImpl = static_cast(this); + graphImpl->UnregisterCaptureStreamForWindow(aWindowId); +} + +void +MediaStreamGraphImpl::UnregisterCaptureStreamForWindow(uint64_t aWindowId) +{ + MOZ_ASSERT(NS_IsMainThread()); + for (uint32_t i = 0; i < mWindowCaptureStreams.Length(); i++) { + if (mWindowCaptureStreams[i].mWindowId == aWindowId) { + mWindowCaptureStreams.RemoveElementAt(i); + } + } +} + +already_AddRefed +MediaStreamGraph::ConnectToCaptureStream(uint64_t aWindowId, + MediaStream* aMediaStream) +{ + return aMediaStream->GraphImpl()->ConnectToCaptureStream(aWindowId, + aMediaStream); +} + +already_AddRefed +MediaStreamGraphImpl::ConnectToCaptureStream(uint64_t aWindowId, + MediaStream* aMediaStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + for (uint32_t i = 0; i < mWindowCaptureStreams.Length(); i++) { + if (mWindowCaptureStreams[i].mWindowId == aWindowId) { + ProcessedMediaStream* sink = mWindowCaptureStreams[i].mCaptureStreamSink; + return sink->AllocateInputPort(aMediaStream, 0); + } + } + return nullptr; +} + } // namespace mozilla diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index 312aad706052..ac770fe1396a 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -1262,6 +1262,10 @@ public: * particular tracks of each input stream. */ ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper); + /** + * Create a stream that will mix all its audio input. + */ + ProcessedMediaStream* CreateAudioCaptureStream(DOMMediaStream* aWrapper); // Internal AudioNodeStreams can only pass their output to another // AudioNode, whereas external AudioNodeStreams can pass their output // to an nsAudioStream for playback. @@ -1318,6 +1322,12 @@ public: */ TrackRate GraphRate() const { return mSampleRate; } + void RegisterCaptureStreamForWindow(uint64_t aWindowId, + ProcessedMediaStream* aCaptureStream); + void UnregisterCaptureStreamForWindow(uint64_t aWindowId); + already_AddRefed ConnectToCaptureStream( + uint64_t aWindowId, MediaStream* aMediaStream); + protected: explicit MediaStreamGraph(TrackRate aSampleRate) : mNextGraphUpdateIndex(1) diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 262cae526c2e..15ded10c470c 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -532,6 +532,13 @@ public: } } + // Capture Stream API. This allows to get a mixed-down output for a window. + void RegisterCaptureStreamForWindow(uint64_t aWindowId, + ProcessedMediaStream* aCaptureStream); + void UnregisterCaptureStreamForWindow(uint64_t aWindowId); + already_AddRefed + ConnectToCaptureStream(uint64_t aWindowId, MediaStream* aMediaStream); + // Data members // /** @@ -755,6 +762,16 @@ private: * Used to pass memory report information across threads. */ nsTArray mAudioStreamSizes; + + struct WindowAndStream + { + uint64_t mWindowId; + nsRefPtr mCaptureStreamSink; + }; + /** + * Stream for window audio capture. + */ + nsTArray mWindowCaptureStreams; /** * Indicates that the MSG thread should gather data for a memory report. */ From e1e882cb5679fd885c158f3f61ff857fe1edc8ff Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:16 +0200 Subject: [PATCH 74/90] Bug 1156472 - Part 5 - Add MediaEngineWebRTCAudioCaptureSource as a new audio source, and "audioCapture" as a new MediaSource. r=jesup,bz --- dom/media/MediaManager.cpp | 117 ++++++++++++-------- dom/media/MediaManager.h | 2 +- dom/media/webrtc/MediaEngineWebRTC.cpp | 14 ++- dom/media/webrtc/MediaEngineWebRTC.h | 64 ++++++++++- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 52 +++++++++ dom/webidl/Constraints.webidl | 1 + 6 files changed, 194 insertions(+), 56 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 7af74e55c71a..d989563b8057 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -300,7 +300,8 @@ protected: NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice) MediaDevice::MediaDevice(MediaEngineSource* aSource, bool aIsVideo) - : mSource(aSource) + : mMediaSource(aSource->GetMediaSource()) + , mSource(aSource) , mIsVideo(aIsVideo) { mSource->GetName(mName); @@ -311,9 +312,7 @@ MediaDevice::MediaDevice(MediaEngineSource* aSource, bool aIsVideo) VideoDevice::VideoDevice(MediaEngineVideoSource* aSource) : MediaDevice(aSource, true) -{ - mMediaSource = aSource->GetMediaSource(); -} +{} /** * Helper functions that implement the constraints algorithm from @@ -439,6 +438,8 @@ MediaDevice::GetMediaSource(nsAString& aMediaSource) { if (mMediaSource == dom::MediaSourceEnum::Microphone) { aMediaSource.Assign(NS_LITERAL_STRING("microphone")); + } else if (mMediaSource == dom::MediaSourceEnum::AudioCapture) { + aMediaSource.Assign(NS_LITERAL_STRING("audioCapture")); } else if (mMediaSource == dom::MediaSourceEnum::Window) { // this will go away aMediaSource.Assign(NS_LITERAL_STRING("window")); } else { // all the rest are shared @@ -784,11 +785,52 @@ public: } } #endif - // Create a media stream. - nsRefPtr trackunion = - nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, - mAudioSource, mVideoSource); - if (!trackunion || sInShutdown) { + + MediaStreamGraph* msg = MediaStreamGraph::GetInstance(); + nsRefPtr stream = msg->CreateSourceStream(nullptr); + + nsRefPtr domStream; + // AudioCapture is a special case, here, in the sense that we're not really + // using the audio source and the SourceMediaStream, which acts as + // placeholders. We re-route a number of stream internaly in the MSG and mix + // them down instead. + if (mAudioSource && + mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { + domStream = DOMLocalMediaStream::CreateAudioCaptureStream(window); + msg->RegisterCaptureStreamForWindow( + mWindowID, domStream->GetStream()->AsProcessedStream()); + window->SetAudioCapture(true); + } else { + // Normal case, connect the source stream to the track union stream to + // avoid us blocking + nsRefPtr trackunion = + nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, + mAudioSource, mVideoSource); + trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true); + nsRefPtr port = trackunion->GetStream()->AsProcessedStream()-> + AllocateInputPort(stream, MediaInputPort::FLAG_BLOCK_OUTPUT); + trackunion->mSourceStream = stream; + trackunion->mPort = port.forget(); + // Log the relationship between SourceMediaStream and TrackUnion stream + // Make sure logger starts before capture + AsyncLatencyLogger::Get(true); + LogLatency(AsyncLatencyLogger::MediaStreamCreate, + reinterpret_cast(stream.get()), + reinterpret_cast(trackunion->GetStream())); + + nsCOMPtr principal; + if (mPeerIdentity) { + principal = nsNullPrincipal::Create(); + trackunion->SetPeerIdentity(mPeerIdentity.forget()); + } else { + principal = window->GetExtantDoc()->NodePrincipal(); + } + trackunion->CombineWithPrincipal(principal); + + domStream = trackunion.forget(); + } + + if (!domStream || sInShutdown) { nsCOMPtr onFailure = mOnFailure.forget(); LOG(("Returning error for getUserMedia() - no stream")); @@ -802,36 +844,6 @@ public: } return NS_OK; } - trackunion->AudioConfig(aec_on, (uint32_t) aec, - agc_on, (uint32_t) agc, - noise_on, (uint32_t) noise, - playout_delay); - - - MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); - nsRefPtr stream = gm->CreateSourceStream(nullptr); - - // connect the source stream to the track union stream to avoid us blocking - trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true); - nsRefPtr port = trackunion->GetStream()->AsProcessedStream()-> - AllocateInputPort(stream, MediaInputPort::FLAG_BLOCK_OUTPUT); - trackunion->mSourceStream = stream; - trackunion->mPort = port.forget(); - // Log the relationship between SourceMediaStream and TrackUnion stream - // Make sure logger starts before capture - AsyncLatencyLogger::Get(true); - LogLatency(AsyncLatencyLogger::MediaStreamCreate, - reinterpret_cast(stream.get()), - reinterpret_cast(trackunion->GetStream())); - - nsCOMPtr principal; - if (mPeerIdentity) { - principal = nsNullPrincipal::Create(); - trackunion->SetPeerIdentity(mPeerIdentity.forget()); - } else { - principal = window->GetExtantDoc()->NodePrincipal(); - } - trackunion->CombineWithPrincipal(principal); // The listener was added at the beginning in an inactive state. // Activate our listener. We'll call Start() on the source when get a callback @@ -841,7 +853,7 @@ public: // Note: includes JS callbacks; must be released on MainThread TracksAvailableCallback* tracksAvailableCallback = - new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, trackunion); + new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, domStream); mListener->AudioConfig(aec_on, (uint32_t) aec, agc_on, (uint32_t) agc, @@ -852,11 +864,11 @@ public: // because that can take a while. // Pass ownership of trackunion to the MediaOperationTask // to ensure it's kept alive until the MediaOperationTask runs (at least). - MediaManager::PostTask(FROM_HERE, - new MediaOperationTask(MEDIA_START, mListener, trackunion, - tracksAvailableCallback, - mAudioSource, mVideoSource, false, mWindowID, - mOnFailure.forget())); + MediaManager::PostTask( + FROM_HERE, new MediaOperationTask(MEDIA_START, mListener, domStream, + tracksAvailableCallback, mAudioSource, + mVideoSource, false, mWindowID, + mOnFailure.forget())); // We won't need mOnFailure now. mOnFailure = nullptr; @@ -2075,7 +2087,7 @@ StopSharingCallback(MediaManager *aThis, listener->Invalidate(); } listener->Remove(); - listener->StopScreenWindowSharing(); + listener->StopSharing(); } aListeners->Clear(); aThis->RemoveWindowID(aWindowID); @@ -2398,7 +2410,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, uint64_t windowID = PromiseFlatString(Substring(data, strlen("screen:"))).ToInteger64(&rv); MOZ_ASSERT(NS_SUCCEEDED(rv)); if (NS_SUCCEEDED(rv)) { - LOG(("Revoking Screeen/windowCapture access for window %llu", windowID)); + LOG(("Revoking Screen/windowCapture access for window %llu", windowID)); StopScreensharing(windowID); } } else { @@ -2579,7 +2591,7 @@ StopScreensharingCallback(MediaManager *aThis, if (aListeners) { auto length = aListeners->Length(); for (size_t i = 0; i < length; ++i) { - aListeners->ElementAt(i)->StopScreenWindowSharing(); + aListeners->ElementAt(i)->StopSharing(); } } } @@ -2741,7 +2753,7 @@ GetUserMediaCallbackMediaStreamListener::Invalidate() // Doesn't kill audio // XXX refactor to combine with Invalidate()? void -GetUserMediaCallbackMediaStreamListener::StopScreenWindowSharing() +GetUserMediaCallbackMediaStreamListener::StopSharing() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); if (mVideoSource && !mStopped && @@ -2754,6 +2766,13 @@ GetUserMediaCallbackMediaStreamListener::StopScreenWindowSharing() this, nullptr, nullptr, nullptr, mVideoSource, mFinished, mWindowID, nullptr)); + } else if (mAudioSource && + mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { + nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); + MOZ_ASSERT(window); + window->SetAudioCapture(false); + MediaStreamGraph::GetInstance()->UnregisterCaptureStreamForWindow(mWindowID); + mStream->Destroy(); } } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index d7af9c5a7b99..68ab74269201 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -103,7 +103,7 @@ public: return mStream->AsSourceStream(); } - void StopScreenWindowSharing(); + void StopSharing(); void StopTrack(TrackID aID, bool aIsAudio); diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp index 34adf582ed88..207e97acb33e 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.cpp +++ b/dom/media/webrtc/MediaEngineWebRTC.cpp @@ -291,6 +291,13 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource, // We spawn threads to handle gUM runnables, so we must protect the member vars MutexAutoLock lock(mMutex); + if (aMediaSource == dom::MediaSourceEnum::AudioCapture) { + nsRefPtr audioCaptureSource = + new MediaEngineWebRTCAudioCaptureSource(nullptr); + aASources->AppendElement(audioCaptureSource); + return; + } + #ifdef MOZ_WIDGET_ANDROID jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef(); @@ -358,7 +365,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource, strcpy(uniqueId,deviceName); // safe given assert and initialization/error-check } - nsRefPtr aSource; + nsRefPtr aSource; NS_ConvertUTF8toUTF16 uuid(uniqueId); if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) { // We've already seen this device, just append. @@ -384,9 +391,8 @@ ClearVideoSource (const nsAString&, // unused } static PLDHashOperator -ClearAudioSource (const nsAString&, // unused - MediaEngineWebRTCAudioSource* aData, - void *userArg) +ClearAudioSource(const nsAString &, // unused + MediaEngineAudioSource *aData, void *userArg) { if (aData) { aData->Shutdown(); diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 8b05480718b6..112c5134d607 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -133,6 +133,67 @@ private: void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) override; }; +class MediaEngineWebRTCAudioCaptureSource : public MediaEngineAudioSource +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid) + : MediaEngineAudioSource(kReleased) + { + } + void GetName(nsAString& aName) override; + void GetUUID(nsACString& aUUID) override; + nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs& aPrefs, + const nsString& aDeviceId) override + { + // Nothing to do here, everything is managed in MediaManager.cpp + return NS_OK; + } + nsresult Deallocate() override + { + // Nothing to do here, everything is managed in MediaManager.cpp + return NS_OK; + } + void Shutdown() override + { + // Nothing to do here, everything is managed in MediaManager.cpp + } + nsresult Start(SourceMediaStream* aMediaStream, TrackID aId) override; + nsresult Stop(SourceMediaStream* aMediaStream, TrackID aId) override; + void SetDirectListeners(bool aDirect) override + {} + nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, + uint32_t aAGC, bool aNoiseOn, uint32_t aNoise, + int32_t aPlayoutDelay) override + { + return NS_OK; + } + void NotifyPull(MediaStreamGraph* aGraph, SourceMediaStream* aSource, + TrackID aID, StreamTime aDesiredTime) override + {} + const dom::MediaSourceEnum GetMediaSource() override + { + return dom::MediaSourceEnum::AudioCapture; + } + bool IsFake() override + { + return false; + } + nsresult TakePhoto(PhotoCallback* aCallback) override + { + return NS_ERROR_NOT_IMPLEMENTED; + } + uint32_t GetBestFitnessDistance( + const nsTArray& aConstraintSets, + const nsString& aDeviceId) override; + +protected: + virtual ~MediaEngineWebRTCAudioCaptureSource() { Shutdown(); } + nsCString mUUID; +}; + class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource, public webrtc::VoEMediaProcess, private MediaConstraintsHelper @@ -297,8 +358,7 @@ private: // Store devices we've already seen in a hashtable for quick return. // Maps UUID to MediaEngineSource (one set for audio, one for video). nsRefPtrHashtable mVideoSources; - nsRefPtrHashtable - mAudioSources; + nsRefPtrHashtable mAudioSources; }; } diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 2aca1ecbbf99..223a5acde76e 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -44,6 +44,7 @@ extern PRLogModuleInfo* GetMediaManagerLog(); * Webrtc microphone source source. */ NS_IMPL_ISUPPORTS0(MediaEngineWebRTCMicrophoneSource) +NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioCaptureSource) // XXX temp until MSG supports registration StaticRefPtr gFarendObserver; @@ -620,4 +621,55 @@ MediaEngineWebRTCMicrophoneSource::Process(int channel, return; } +void +MediaEngineWebRTCAudioCaptureSource::GetName(nsAString &aName) +{ + aName.AssignLiteral("AudioCapture"); +} +void +MediaEngineWebRTCAudioCaptureSource::GetUUID(nsACString &aUUID) +{ + nsID uuid; + char uuidBuffer[NSID_LENGTH]; + nsCString asciiString; + ErrorResult rv; + + rv = nsContentUtils::GenerateUUIDInPlace(uuid); + if (rv.Failed()) { + aUUID.AssignLiteral(""); + return; + } + + + uuid.ToProvidedString(uuidBuffer); + asciiString.AssignASCII(uuidBuffer); + + // Remove {} and the null terminator + aUUID.Assign(Substring(asciiString, 1, NSID_LENGTH - 3)); +} + +nsresult +MediaEngineWebRTCAudioCaptureSource::Start(SourceMediaStream *aMediaStream, + TrackID aId) +{ + aMediaStream->AddTrack(aId, 0, new AudioSegment()); + return NS_OK; +} + +nsresult +MediaEngineWebRTCAudioCaptureSource::Stop(SourceMediaStream *aMediaStream, + TrackID aId) +{ + aMediaStream->EndAllTrackAndFinish(); + return NS_OK; +} + +uint32_t +MediaEngineWebRTCAudioCaptureSource::GetBestFitnessDistance( + const nsTArray& aConstraintSets, + const nsString& aDeviceId) +{ + // There is only one way of capturing audio for now, and it's always adequate. + return 0; +} } diff --git a/dom/webidl/Constraints.webidl b/dom/webidl/Constraints.webidl index fc6275b59b4e..f7f0c706a9d7 100644 --- a/dom/webidl/Constraints.webidl +++ b/dom/webidl/Constraints.webidl @@ -25,6 +25,7 @@ enum MediaSourceEnum { "window", "browser", "microphone", + "audioCapture", "other" }; From c1a9ba0ab9272900d69049bc5b6f352e15f01a1d Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 75/90] Bug 1156472 - Part 6 - Connect HTMLMediaElement and AudioContext to the capture stream when capturing is needed. r=roc --- dom/html/HTMLMediaElement.cpp | 45 ++++++++++++++++----- dom/html/HTMLMediaElement.h | 6 +++ dom/media/webaudio/AudioDestinationNode.cpp | 29 ++++++++----- dom/media/webaudio/AudioDestinationNode.h | 2 + 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 42c5f63f7774..81f1ed36079f 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2030,6 +2030,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo mAllowCasting(false), mIsCasting(false), mAudioCaptured(false), + mAudioCapturedByWindow(false), mPlayingBeforeSeek(false), mPlayingThroughTheAudioChannelBeforeSeek(false), mPausedForInactiveDocumentOrChannel(false), @@ -2097,6 +2098,11 @@ HTMLMediaElement::~HTMLMediaElement() EndSrcMediaStreamPlayback(); } + if (mCaptureStreamPort) { + mCaptureStreamPort->Destroy(); + mCaptureStreamPort = nullptr; + } + NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0, "Destroyed media element should no longer be in element table"); @@ -4475,8 +4481,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() (!mPaused && (HasAttr(kNameSpaceID_None, nsGkAtoms::loop) || (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && - !IsPlaybackEnded() && - (!mSrcStream || HasAudio())) || + !IsPlaybackEnded()) || mPlayingThroughTheAudioChannelBeforeSeek)); if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) { mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel; @@ -4504,9 +4509,9 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() void HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) { - // Immediately check if this should go to the MSG instead of the normal - // media playback route. - WindowAudioCaptureChanged(); + // Immediately check if this should go to the MSG instead of the normal + // media playback route. + WindowAudioCaptureChanged(); // This is needed to pass nsContentUtils::IsCallerChrome(). // AudioChannel API should not called from content but it can happen that @@ -4680,11 +4685,33 @@ HTMLMediaElement::GetTopLevelPrincipal() NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged() { - MOZ_ASSERT(mAudioChannelAgent); - DebugOnly captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured(); + MOZ_ASSERT(mAudioChannelAgent); - // Something is going to happen here!! - return NS_OK; + if (!OwnerDoc()->GetInnerWindow()) { + return NS_OK; + } + bool captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured(); + + if (captured != mAudioCapturedByWindow) { + if (captured) { + mAudioCapturedByWindow = true; + nsCOMPtr window = + do_QueryInterface(OwnerDoc()->GetParentObject()); + uint64_t id = window->WindowID(); + MediaStreamGraph* msg = MediaStreamGraph::GetInstance(); + + if (!mPlaybackStream) { + nsRefPtr stream = CaptureStreamInternal(false, msg); + mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetStream()); + } else { + mCaptureStreamPort = msg->ConnectToCaptureStream(id, mPlaybackStream->GetStream()); + } + } else { + // TODO: uncapture + } + } + + return NS_OK; } AudioTrackList* diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index 84f4ed0d9cd8..406478fc507c 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1074,6 +1074,9 @@ protected: // Holds a reference to a MediaInputPort connecting mSrcStream to mPlaybackStream. nsRefPtr mPlaybackStreamInputPort; + // Holds a reference to the stream connecting this stream to the capture sink. + nsRefPtr mCaptureStreamPort; + // Holds a reference to a stream with mSrcStream as input but intended for // playback. Used so we don't block playback of other video elements // playing the same mSrcStream. @@ -1283,6 +1286,9 @@ protected: // True if the sound is being captured. bool mAudioCaptured; + // True if the sound is being captured by the window. + bool mAudioCapturedByWindow; + // If TRUE then the media element was actively playing before the currently // in progress seeking. If FALSE then the media element is either not seeking // or was not actively playing before the current seek. Used to decide whether diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 3f5a3650a0df..d37145ef547a 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -313,12 +313,9 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, bool aIsOffline, AudioChannel aChannel, uint32_t aNumberOfChannels, - uint32_t aLength, - float aSampleRate) - : AudioNode(aContext, - aIsOffline ? aNumberOfChannels : 2, - ChannelCountMode::Explicit, - ChannelInterpretation::Speakers) + uint32_t aLength, float aSampleRate) + : AudioNode(aContext, aIsOffline ? aNumberOfChannels : 2, + ChannelCountMode::Explicit, ChannelInterpretation::Speakers) , mFramesToProduce(aLength) , mAudioChannel(AudioChannel::Normal) , mIsOffline(aIsOffline) @@ -326,6 +323,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, , mExtraCurrentTime(0) , mExtraCurrentTimeSinceLastStartedBlocking(0) , mExtraCurrentTimeUpdatedSinceLastStableState(false) + , mCaptured(false) { bool startWithAudioDriver = true; MediaStreamGraph* graph = aIsOffline ? @@ -510,13 +508,25 @@ AudioDestinationNode::WindowAudioCaptureChanged() { MOZ_ASSERT(mAudioChannelAgent); - if (!mStream) { + if (!mStream || Context()->IsOffline()) { return NS_OK; } - DebugOnly captured = GetOwner()->GetAudioCaptured(); + bool captured = GetOwner()->GetAudioCaptured(); + + if (captured != mCaptured) { + if (captured) { + nsCOMPtr window = Context()->GetParentObject(); + uint64_t id = window->WindowID(); + mCaptureStreamPort = + mStream->Graph()->ConnectToCaptureStream(id, mStream); + } else { + mCaptureStreamPort->Disconnect(); + mCaptureStreamPort->Destroy(); + } + mCaptured = captured; + } - // XXXtodopadenot actually capture return NS_OK; } @@ -699,6 +709,7 @@ AudioDestinationNode::InputMuted(bool aMuted) return; } + WindowAudioCaptureChanged(); WindowVolumeChanged(volume, muted); } diff --git a/dom/media/webaudio/AudioDestinationNode.h b/dom/media/webaudio/AudioDestinationNode.h index db5418a9cb51..724e44d61d3c 100644 --- a/dom/media/webaudio/AudioDestinationNode.h +++ b/dom/media/webaudio/AudioDestinationNode.h @@ -99,6 +99,7 @@ private: uint32_t mFramesToProduce; nsCOMPtr mAudioChannelAgent; + nsRefPtr mCaptureStreamPort; nsRefPtr mOfflineRenderingPromise; @@ -111,6 +112,7 @@ private: double mExtraCurrentTime; double mExtraCurrentTimeSinceLastStartedBlocking; bool mExtraCurrentTimeUpdatedSinceLastStableState; + bool mCaptured; }; } // namespace dom From 27a91916bfca77ba9404beb26b0704538bdb50ad Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 76/90] Bug 1156472 - Part 7 - Allow to un-capture an HTMLMediaElement. r=pehrsons,jwwang --- dom/html/HTMLMediaElement.cpp | 18 +++++++++++++++- dom/media/DecodedStream.cpp | 8 +++++++ dom/media/DecodedStream.h | 1 + dom/media/MediaDecoder.cpp | 7 +++++++ dom/media/MediaDecoder.h | 2 ++ dom/media/MediaDecoderStateMachine.cpp | 29 ++++++++++++++++++++++++++ dom/media/MediaDecoderStateMachine.h | 3 +++ 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 81f1ed36079f..f511ef93f51c 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4707,7 +4707,23 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged() mCaptureStreamPort = msg->ConnectToCaptureStream(id, mPlaybackStream->GetStream()); } } else { - // TODO: uncapture + mAudioCapturedByWindow = false; + if (mDecoder) { + ProcessedMediaStream* ps = + mCaptureStreamPort->GetSource()->AsProcessedStream(); + MOZ_ASSERT(ps); + + for (uint32_t i = 0; i < mOutputStreams.Length(); i++) { + if (mOutputStreams[i].mStream->GetStream() == ps) { + mOutputStreams.RemoveElementAt(i); + break; + } + } + + mDecoder->RemoveOutputStream(ps); + } + mCaptureStreamPort->Destroy(); + mCaptureStreamPort = nullptr; } } diff --git a/dom/media/DecodedStream.cpp b/dom/media/DecodedStream.cpp index dcc950228f72..913f68203e21 100644 --- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -289,6 +289,14 @@ DecodedStream::OutputStreams() return mOutputStreams; } +bool +DecodedStream::HasConsumers() const +{ + MOZ_ASSERT(NS_IsMainThread()); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + return mOutputStreams.IsEmpty(); +} + ReentrantMonitor& DecodedStream::GetReentrantMonitor() const { diff --git a/dom/media/DecodedStream.h b/dom/media/DecodedStream.h index 8b25b95c9f7d..ebad8330c865 100644 --- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -114,6 +114,7 @@ public: int64_t AudioEndTime() const; int64_t GetPosition() const; bool IsFinished() const; + bool HasConsumers() const; // Return true if stream is finished. bool SendData(double aVolume, bool aIsSameOrigin); diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 59f7e5fcc59b..3f0cdadc6a19 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -326,6 +326,13 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream, mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded); } +void MediaDecoder::RemoveOutputStream(MediaStream* aStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load()."); + mDecoderStateMachine->RemoveOutputStream(aStream); +} + double MediaDecoder::GetDuration() { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index c2a01bb07465..d216bf9c7666 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -399,6 +399,8 @@ public: // The stream is initially blocked. The decoder is responsible for unblocking // it while it is playing back. virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); + // Remove an output stream added with AddOutputStream. + virtual void RemoveOutputStream(MediaStream* aStream); // Return the duration of the video in seconds. virtual double GetDuration(); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 2ca215ca06f9..9b7ab7e0e092 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -3177,6 +3177,25 @@ void MediaDecoderStateMachine::DispatchAudioCaptured() OwnerThread()->Dispatch(r.forget()); } +void MediaDecoderStateMachine::DispatchAudioUncaptured() +{ + nsRefPtr self = this; + nsCOMPtr r = NS_NewRunnableFunction([self] () -> void + { + MOZ_ASSERT(self->OnTaskQueue()); + ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor()); + if (self->mAudioCaptured) { + // Start again the audio sink + self->mAudioCaptured = false; + if (self->IsPlaying()) { + self->StartAudioThread(); + } + self->ScheduleStateMachine(); + } + }); + OwnerThread()->Dispatch(r.forget()); +} + void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded) { @@ -3186,6 +3205,16 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, DispatchAudioCaptured(); } +void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + DECODER_LOG("RemoveOutputStream=%p!", aStream); + mDecodedStream->Remove(aStream); + if (!mDecodedStream->HasConsumers()) { + DispatchAudioUncaptured(); + } +} + } // namespace mozilla // avoid redefined macro in unified build diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index ea485d4e9d08..8670d0569baa 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -149,6 +149,8 @@ public: }; void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); + // Remove an output stream added with AddOutputStream. + void RemoveOutputStream(MediaStream* aStream); // Set/Unset dormant state. void SetDormant(bool aDormant); @@ -160,6 +162,7 @@ private: void InitializationTask(); void DispatchAudioCaptured(); + void DispatchAudioUncaptured(); void Shutdown(); public: From 5ed058488afa194ca3428783d17ebbccaa454693 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 77/90] Bug 1156472 - Part 8 - Use fatal asserts in AudioChannelUpmix, because it would have crashed anyways. r=roc --- dom/media/AudioChannelFormat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/media/AudioChannelFormat.cpp b/dom/media/AudioChannelFormat.cpp index a447b1dd5d73..2534851bed17 100644 --- a/dom/media/AudioChannelFormat.cpp +++ b/dom/media/AudioChannelFormat.cpp @@ -76,8 +76,8 @@ AudioChannelsUpMix(nsTArray* aChannelArray, GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount); NS_ASSERTION(outputChannelCount > inputChannelCount, "No up-mix needed"); - NS_ASSERTION(inputChannelCount > 0, "Bad number of channels"); - NS_ASSERTION(outputChannelCount > 0, "Bad number of channels"); + MOZ_ASSERT(inputChannelCount > 0, "Bad number of channels"); + MOZ_ASSERT(outputChannelCount > 0, "Bad number of channels"); aChannelArray->SetLength(outputChannelCount); From 4397423937395f659d05321df00777fb49f1a474 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 78/90] Bug 1156472 - Part 9 - Implement the minimum frontend to play with the feature. r=gijs,florian --- .../locales/en-US/chrome/browser/browser.dtd | 1 + .../en-US/chrome/browser/browser.properties | 23 ++++++++- browser/modules/ContentWebRTC.jsm | 14 ++++-- browser/modules/webrtcUI.jsm | 50 +++++++++++-------- 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index 89981e6936c4..fe7439e0a445 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -758,6 +758,7 @@ you can use these alternative items. Otherwise, their values should be empty. - + diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index 766446fac755..1a71d59b1b09 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -553,13 +553,17 @@ identity.loggedIn.signOut.accessKey = O # LOCALIZATION NOTE (getUserMedia.shareCamera.message, getUserMedia.shareMicrophone.message, # getUserMedia.shareScreen.message, getUserMedia.shareCameraAndMicrophone.message, -# getUserMedia.shareScreenAndMicrophone.message): +# getUserMedia.shareScreenAndMicrophone.message, getUserMedia.shareCameraAndAudioCapture.message, +# getUserMedia.shareAudioCapture.message, getUserMedia.shareScreenAndAudioCapture.message): # %S is the website origin (e.g. www.mozilla.org) getUserMedia.shareCamera.message = Would you like to share your camera with %S? getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S? getUserMedia.shareScreen.message = Would you like to share your screen with %S? getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S? +getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab's audio with %S? getUserMedia.shareScreenAndMicrophone.message = Would you like to share your microphone and screen with %S? +getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab's audio and your screen with %S? +getUserMedia.shareAudioCapture.message = Would you like to share this tab's audio with %S? getUserMedia.selectWindow.label=Window to share: getUserMedia.selectWindow.accesskey=W getUserMedia.selectScreen.label=Screen to share: @@ -601,6 +605,7 @@ getUserMedia.sharingApplication.message = You are currently sharing an applicati getUserMedia.sharingScreen.message = You are currently sharing your screen with this page. getUserMedia.sharingWindow.message = You are currently sharing a window with this page. getUserMedia.sharingBrowser.message = You are currently sharing a tab with this page. +getUserMedia.sharingAudioCapture.message = You are currently sharing a tab's audio with this page. getUserMedia.continueSharing.label = Continue Sharing getUserMedia.continueSharing.accesskey = C getUserMedia.stopSharing.label = Stop Sharing @@ -610,6 +615,7 @@ getUserMedia.sharingMenu.label = Tabs sharing devices getUserMedia.sharingMenu.accesskey = d # LOCALIZATION NOTE (getUserMedia.sharingMenuCamera # getUserMedia.sharingMenuMicrophone, +# getUserMedia.sharingMenuAudioCapture, # getUserMedia.sharingMenuApplication, # getUserMedia.sharingMenuScreen, # getUserMedia.sharingMenuWindow, @@ -619,6 +625,11 @@ getUserMedia.sharingMenu.accesskey = d # getUserMedia.sharingMenuCameraMicrophoneScreen, # getUserMedia.sharingMenuCameraMicrophoneWindow, # getUserMedia.sharingMenuCameraMicrophoneBrowser, +# getUserMedia.sharingMenuCameraAudioCapture, +# getUserMedia.sharingMenuCameraAudioCaptureApplication, +# getUserMedia.sharingMenuCameraAudioCaptureScreen, +# getUserMedia.sharingMenuCameraAudioCaptureWindow, +# getUserMedia.sharingMenuCameraAudioCaptureBrowser, # getUserMedia.sharingMenuCameraApplication, # getUserMedia.sharingMenuCameraScreen, # getUserMedia.sharingMenuCameraWindow, @@ -630,6 +641,7 @@ getUserMedia.sharingMenu.accesskey = d # %S is the website origin (e.g. www.mozilla.org) getUserMedia.sharingMenuCamera = %S (camera) getUserMedia.sharingMenuMicrophone = %S (microphone) +getUserMedia.sharingMenuAudioCapture = %S (tab audio) getUserMedia.sharingMenuApplication = %S (application) getUserMedia.sharingMenuScreen = %S (screen) getUserMedia.sharingMenuWindow = %S (window) @@ -639,6 +651,11 @@ getUserMedia.sharingMenuCameraMicrophoneApplication = %S (camera, microphone and getUserMedia.sharingMenuCameraMicrophoneScreen = %S (camera, microphone and screen) getUserMedia.sharingMenuCameraMicrophoneWindow = %S (camera, microphone and window) getUserMedia.sharingMenuCameraMicrophoneBrowser = %S (camera, microphone and tab) +getUserMedia.sharingMenuCameraAudioCapture = %S (camera and tab audio) +getUserMedia.sharingMenuCameraAudioCaptureApplication = %S (camera, tab audio and application) +getUserMedia.sharingMenuCameraAudioCaptureScreen = %S (camera, tab audio and screen) +getUserMedia.sharingMenuCameraAudioCaptureWindow = %S (camera, tab audio and window) +getUserMedia.sharingMenuCameraAudioCaptureBrowser = %S (camera, tab audio and tab) getUserMedia.sharingMenuCameraApplication = %S (camera and application) getUserMedia.sharingMenuCameraScreen = %S (camera and screen) getUserMedia.sharingMenuCameraWindow = %S (camera and window) @@ -647,6 +664,10 @@ getUserMedia.sharingMenuMicrophoneApplication = %S (microphone and application) getUserMedia.sharingMenuMicrophoneScreen = %S (microphone and screen) getUserMedia.sharingMenuMicrophoneWindow = %S (microphone and window) getUserMedia.sharingMenuMicrophoneBrowser = %S (microphone and tab) +getUserMedia.sharingMenuMicrophoneApplication = %S (tab audio and application) +getUserMedia.sharingMenuMicrophoneScreen = %S (tab audio and screen) +getUserMedia.sharingMenuMicrophoneWindow = %S (tab audio and window) +getUserMedia.sharingMenuMicrophoneBrowser = %S (tab audio and tab) # LOCALIZATION NOTE(getUserMedia.sharingMenuUnknownHost): this is used for the website # origin for the sharing menu if no readable origin could be deduced from the URL. getUserMedia.sharingMenuUnknownHost = Unknown origin diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm index 5f0514170d6b..e059c60d3d2f 100644 --- a/browser/modules/ContentWebRTC.jsm +++ b/browser/modules/ContentWebRTC.jsm @@ -86,14 +86,21 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec // MediaStreamConstraints defines video as 'boolean or MediaTrackConstraints'. let video = aConstraints.video || aConstraints.picture; + let audio = aConstraints.audio; let sharingScreen = video && typeof(video) != "boolean" && video.mediaSource != "camera"; + let sharingAudio = audio && typeof(audio) != "boolean" && + audio.mediaSource != "microphone"; for (let device of aDevices) { device = device.QueryInterface(Ci.nsIMediaDevice); switch (device.type) { case "audio": - if (aConstraints.audio) { - audioDevices.push({name: device.name, deviceIndex: devices.length}); + // Check that if we got a microphone, we have not requested an audio + // capture, and if we have requested an audio capture, we are not + // getting a microphone instead. + if (audio && (device.mediaSource == "microphone") != sharingAudio) { + audioDevices.push({name: device.name, deviceIndex: devices.length, + mediaSource: device.mediaSource}); devices.push(device); } break; @@ -113,7 +120,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec if (videoDevices.length) requestTypes.push(sharingScreen ? "Screen" : "Camera"); if (audioDevices.length) - requestTypes.push("Microphone"); + requestTypes.push(sharingAudio ? "AudioCapture" : "Microphone"); if (!requestTypes.length) { denyRequest({callID: aCallID}, "NotFoundError"); @@ -133,6 +140,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec secure: aSecure, requestTypes: requestTypes, sharingScreen: sharingScreen, + sharingAudio: sharingAudio, audioDevices: audioDevices, videoDevices: videoDevices }; diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index be52cb8350f8..792c58bf1dcd 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -188,7 +188,8 @@ function getHost(uri, href) { function prompt(aBrowser, aRequest) { let {audioDevices: audioDevices, videoDevices: videoDevices, - sharingScreen: sharingScreen, requestTypes: requestTypes} = aRequest; + sharingScreen: sharingScreen, sharingAudio: sharingAudio, + requestTypes: requestTypes} = aRequest; let uri = Services.io.newURI(aRequest.documentURI, null, null); let host = getHost(uri); let chromeDoc = aBrowser.ownerDocument; @@ -198,10 +199,9 @@ function prompt(aBrowser, aRequest) { let message = stringBundle.getFormattedString(stringId, [host]); let mainLabel; - if (sharingScreen) { + if (sharingScreen || sharingAudio) { mainLabel = stringBundle.getString("getUserMedia.shareSelectedItems.label"); - } - else { + } else { let string = stringBundle.getString("getUserMedia.shareSelectedDevices.label"); mainLabel = PluralForm.get(requestTypes.length, string); } @@ -225,8 +225,8 @@ function prompt(aBrowser, aRequest) { } } ]; - - if (!sharingScreen) { // Bug 1037438: implement 'never' for screen sharing. + // Bug 1037438: implement 'never' for screen sharing. + if (!sharingScreen && !sharingAudio) { secondaryActions.push({ label: stringBundle.getString("getUserMedia.never.label"), accessKey: stringBundle.getString("getUserMedia.never.accesskey"), @@ -243,10 +243,10 @@ function prompt(aBrowser, aRequest) { }); } - if (aRequest.secure && !sharingScreen) { + if (aRequest.secure && !sharingScreen && !sharingAudio) { // Don't show the 'Always' action if the connection isn't secure, or for - // screen sharing (because we can't guess which window the user wants to - // share without prompting). + // screen/audio sharing (because we can't guess which window the user wants + // to share without prompting). secondaryActions.unshift({ label: stringBundle.getString("getUserMedia.always.label"), accessKey: stringBundle.getString("getUserMedia.always.accesskey"), @@ -266,7 +266,8 @@ function prompt(aBrowser, aRequest) { if (aTopic == "shown") { let PopupNotifications = chromeDoc.defaultView.PopupNotifications; let popupId = "Devices"; - if (requestTypes.length == 1 && requestTypes[0] == "Microphone") + if (requestTypes.length == 1 && (requestTypes[0] == "Microphone" || + requestTypes[0] == "AudioCapture")) popupId = "Microphone"; if (requestTypes.indexOf("Screen") != -1) popupId = "Screen"; @@ -384,7 +385,7 @@ function prompt(aBrowser, aRequest) { chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length || sharingScreen; chromeDoc.getElementById("webRTC-selectWindowOrScreen").hidden = !sharingScreen || !videoDevices.length; - chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length; + chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length || sharingAudio; let camMenupopup = chromeDoc.getElementById("webRTC-selectCamera-menupopup"); let windowMenupopup = chromeDoc.getElementById("webRTC-selectWindow-menupopup"); @@ -393,12 +394,16 @@ function prompt(aBrowser, aRequest) { listScreenShareDevices(windowMenupopup, videoDevices); else listDevices(camMenupopup, videoDevices); - listDevices(micMenupopup, audioDevices); + + if (!sharingAudio) + listDevices(micMenupopup, audioDevices); + if (requestTypes.length == 2) { let stringBundle = chromeDoc.defaultView.gNavigatorBundle; if (!sharingScreen) addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1"); - addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); + if (!sharingAudio) + addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); } this.mainAction.callback = function(aRemember) { @@ -416,13 +421,18 @@ function prompt(aBrowser, aRequest) { } } if (audioDevices.length) { - let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; - let allowMic = audioDeviceIndex != "-1"; - if (allowMic) - allowedDevices.push(audioDeviceIndex); - if (aRemember) { - perms.add(uri, "microphone", - allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION); + if (!sharingAudio) { + let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; + let allowMic = audioDeviceIndex != "-1"; + if (allowMic) + allowedDevices.push(audioDeviceIndex); + if (aRemember) { + perms.add(uri, "microphone", + allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION); + } + } else { + // Only one device possible for audio capture. + allowedDevices.push(0); } } From e45365d260306c3de7963908d746fbea3fae342b Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 79/90] Bug 1156472 - Part 10 - Test AudioCaptureStream. r=pehrsons --- dom/media/tests/mochitest/head.js | 113 +++++++++++++++++- dom/media/tests/mochitest/mochitest.ini | 1 + dom/media/tests/mochitest/pc.js | 39 +----- .../test_getUserMedia_audioCapture.html | 110 +++++++++++++++++ .../test_peerConnection_replaceTrack.html | 2 +- .../test_peerConnection_webAudio.html | 2 +- 6 files changed, 228 insertions(+), 39 deletions(-) create mode 100644 dom/media/tests/mochitest/test_getUserMedia_audioCapture.html diff --git a/dom/media/tests/mochitest/head.js b/dom/media/tests/mochitest/head.js index 68158f28ee59..dfe4a2874806 100644 --- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -20,6 +20,114 @@ try { FAKE_ENABLED = true; } +/** + * This class provides helpers around analysing the audio content in a stream + * using WebAudio AnalyserNodes. + * + * @constructor + * @param {object} stream + * A MediaStream object whose audio track we shall analyse. + */ +function AudioStreamAnalyser(ac, stream) { + if (stream.getAudioTracks().length === 0) { + throw new Error("No audio track in stream"); + } + this.audioContext = ac; + this.stream = stream; + this.sourceNode = this.audioContext.createMediaStreamSource(this.stream); + this.analyser = this.audioContext.createAnalyser(); + this.sourceNode.connect(this.analyser); + this.data = new Uint8Array(this.analyser.frequencyBinCount); +} + +AudioStreamAnalyser.prototype = { + /** + * Get an array of frequency domain data for our stream's audio track. + * + * @returns {array} A Uint8Array containing the frequency domain data. + */ + getByteFrequencyData: function() { + this.analyser.getByteFrequencyData(this.data); + return this.data; + }, + + /** + * Append a canvas to the DOM where the frequency data are drawn. + * Useful to debug tests. + */ + enableDebugCanvas: function() { + var cvs = document.createElement("canvas"); + document.getElementById("content").appendChild(cvs); + + // Easy: 1px per bin + cvs.width = this.analyser.frequencyBinCount; + cvs.height = 256; + cvs.style.border = "1px solid red"; + + var c = cvs.getContext('2d'); + + var self = this; + function render() { + c.clearRect(0, 0, cvs.width, cvs.height); + var array = self.getByteFrequencyData(); + for (var i = 0; i < array.length; i++) { + c.fillRect(i, (256 - (array[i])), 1, 256); + } + requestAnimationFrame(render); + } + requestAnimationFrame(render); + }, + + /** + * Return a Promise, that will be resolved when the function passed as + * argument, when called, returns true (meaning the analysis was a + * success). + * + * @param {function} analysisFunction + * A fonction that performs an analysis, and returns true if the + * analysis was a success (i.e. it found what it was looking for) + */ + waitForAnalysisSuccess: function(analysisFunction) { + var self = this; + return new Promise((resolve, reject) => { + function analysisLoop() { + var success = analysisFunction(self.getByteFrequencyData()); + if (success) { + resolve(); + return; + } + // else, we need more time + requestAnimationFrame(analysisLoop); + } + analysisLoop(); + }); + }, + + /** + * Return the FFT bin index for a given frequency. + * + * @param {double} frequency + * The frequency for whicht to return the bin number. + * @returns {integer} the index of the bin in the FFT array. + */ + binIndexForFrequency: function(frequency) { + return 1 + Math.round(frequency * + this.analyser.fftSize / + this.audioContext.sampleRate); + }, + + /** + * Reverse operation, get the frequency for a bin index. + * + * @param {integer} index an index in an FFT array + * @returns {double} the frequency for this bin + */ + frequencyForBinIndex: function(index) { + return (index - 1) * + this.audioContext.sampleRate / + this.analyser.fftSize; + } +}; /** * Create the necessary HTML elements for head and body as used by Mochitests @@ -136,7 +244,10 @@ function setupEnvironment() { ['media.navigator.permission.disabled', true], ['media.navigator.streams.fake', FAKE_ENABLED], ['media.getusermedia.screensharing.enabled', true], - ['media.getusermedia.screensharing.allowed_domains', "mochi.test"] + ['media.getusermedia.screensharing.allowed_domains', "mochi.test"], + ['media.getusermedia.audiocapture.enabled', true], + ['media.useAudioChannelService', true], + ['media.recorder.audio_node.enabled', true] ] }, setTestOptions); diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini index 9d458b0e59b8..115d83b11f0f 100644 --- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -30,6 +30,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be to [test_dataChannel_noOffer.html] [test_enumerateDevices.html] skip-if = buildapp == 'mulet' +[test_getUserMedia_audioCapture.html] [test_getUserMedia_basicAudio.html] skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure [test_getUserMedia_basicVideo.html] diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 51aa7d17ceae..645f29d153e9 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -642,39 +642,6 @@ DataChannelWrapper.prototype = { }; -/** - * This class provides helpers around analysing the audio content in a stream - * using WebAudio AnalyserNodes. - * - * @constructor - * @param {object} stream - * A MediaStream object whose audio track we shall analyse. - */ -function AudioStreamAnalyser(stream) { - if (stream.getAudioTracks().length === 0) { - throw new Error("No audio track in stream"); - } - this.stream = stream; - this.audioContext = new AudioContext(); - this.sourceNode = this.audioContext.createMediaStreamSource(this.stream); - this.analyser = this.audioContext.createAnalyser(); - this.sourceNode.connect(this.analyser); - this.data = new Uint8Array(this.analyser.frequencyBinCount); -} - -AudioStreamAnalyser.prototype = { - /** - * Get an array of frequency domain data for our stream's audio track. - * - * @returns {array} A Uint8Array containing the frequency domain data. - */ - getByteFrequencyData: function() { - this.analyser.getByteFrequencyData(this.data); - return this.data; - } -}; - - /** * This class acts as a wrapper around a PeerConnection instance. * @@ -1559,20 +1526,20 @@ PeerConnectionWrapper.prototype = { * @returns {Promise} * A promise that resolves when we're receiving the tone from |from|. */ - checkReceivingToneFrom : function(from) { + checkReceivingToneFrom : function(audiocontext, from) { var inputElem = from.localMediaElements[0]; // As input we use the stream of |from|'s first available audio sender. var inputSenderTracks = from._pc.getSenders().map(sn => sn.track); var inputAudioStream = from._pc.getLocalStreams() .find(s => s.getAudioTracks().some(t => inputSenderTracks.some(t2 => t == t2))); - var inputAnalyser = new AudioStreamAnalyser(inputAudioStream); + var inputAnalyser = new AudioStreamAnalyser(audiocontext, inputAudioStream); // It would have been nice to have a working getReceivers() here, but until // we do, let's use what remote streams we have. var outputAudioStream = this._pc.getRemoteStreams() .find(s => s.getAudioTracks().length > 0); - var outputAnalyser = new AudioStreamAnalyser(outputAudioStream); + var outputAnalyser = new AudioStreamAnalyser(audiocontext, outputAudioStream); var maxWithIndex = (a, b, i) => (b >= a.value) ? { value: b, index: i } : a; var initial = { value: -1, index: -1 }; diff --git a/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html b/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html new file mode 100644 index 000000000000..057d754ee292 --- /dev/null +++ b/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html @@ -0,0 +1,110 @@ + + + + Test AudioCapture + + + +
+
+
+ + diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html index 6d6e7be029f2..7f3a4d4bd8d0 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html @@ -136,7 +136,7 @@ ]); test.chain.append([ function PC_LOCAL_CHECK_WEBAUDIO_FLOW_PRESENT(test) { - return test.pcRemote.checkReceivingToneFrom(test.pcLocal); + return test.pcRemote.checkReceivingToneFrom(test.audioCtx, test.pcLocal); } ]); test.chain.append([ diff --git a/dom/media/tests/mochitest/test_peerConnection_webAudio.html b/dom/media/tests/mochitest/test_peerConnection_webAudio.html index f5448cc65ae8..2a8cd31f546a 100644 --- a/dom/media/tests/mochitest/test_peerConnection_webAudio.html +++ b/dom/media/tests/mochitest/test_peerConnection_webAudio.html @@ -32,7 +32,7 @@ runNetworkTest(function() { ]); test.chain.append([ function CHECK_AUDIO_FLOW(test) { - return test.pcRemote.checkReceivingToneFrom(test.pcLocal); + return test.pcRemote.checkReceivingToneFrom(test.audioContext, test.pcLocal); } ]); test.run(); From 7872410708040d5214bd6d46206f14a30926975e Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 80/90] Bug 1156472 - Part 11 - Unbitrot MediaManager.cpp over jib's changes. r=jib --- dom/media/MediaManager.cpp | 40 +++++++++++++++++---- dom/media/MediaManager.h | 8 +++-- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 2 +- modules/libpref/init/all.js | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index d989563b8057..a3fefcfd2fab 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1257,7 +1257,9 @@ static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices; */ already_AddRefed -MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType, +MediaManager::EnumerateRawDevices(uint64_t aWindowId, + MediaSourceEnum aVideoType, + MediaSourceEnum aAudioType, bool aFake, bool aFakeTracks) { MOZ_ASSERT(NS_IsMainThread()); @@ -1287,7 +1289,8 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aWindowId, audioLoopDev, videoLoopDev, aVideoType, - aFake, aFakeTracks]() mutable { + aAudioType, aFake, + aFakeTracks]() mutable { nsRefPtr backend; if (aFake) { backend = new MediaEngineDefault(aFakeTracks); @@ -1306,7 +1309,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType } nsTArray> audios; - GetSources(backend, dom::MediaSourceEnum::Microphone, + GetSources(backend, aAudioType, &MediaEngine::EnumerateAudioDevices, audios, audioLoopDev); for (auto& source : audios) { result->AppendElement(source); @@ -1628,6 +1631,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, } MediaSourceEnum videoType = dom::MediaSourceEnum::Camera; + MediaSourceEnum audioType = dom::MediaSourceEnum::Microphone; if (c.mVideo.IsMediaTrackConstraints()) { auto& vc = c.mVideo.GetAsMediaTrackConstraints(); @@ -1716,6 +1720,23 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, privileged = false; } } + + if (c.mAudio.IsMediaTrackConstraints()) { + auto& ac = c.mAudio.GetAsMediaTrackConstraints(); + audioType = StringToEnum(dom::MediaSourceEnumValues::strings, + ac.mMediaSource, + audioType); + // Only enable AudioCapture if the pref is enabled. If it's not, we can deny + // right away. + if (audioType == dom::MediaSourceEnum::AudioCapture && + !Preferences::GetBool("media.getusermedia.audiocapture.enabled")) { + nsRefPtr error = + new MediaStreamError(aWindow, + NS_LITERAL_STRING("PermissionDeniedError")); + onFailure->OnError(error); + return NS_OK; + } + } StreamListeners* listeners = AddWindowID(windowID); // Create a disabled listener to act as a placeholder @@ -1778,7 +1799,8 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, (!fake || Preferences::GetBool("media.navigator.permission.fake")); nsRefPtr p = EnumerateDevicesImpl(windowID, videoType, - fake, fakeTracks); + audioType, fake, + fakeTracks); p->Then([this, onSuccess, onFailure, windowID, c, listener, askPermission, prefs, isHTTPS, callID, origin](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // grab result @@ -1934,7 +1956,9 @@ MediaManager::ToJSArray(SourceSet& aDevices) } already_AddRefed -MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, MediaSourceEnum aVideoType, +MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, + MediaSourceEnum aVideoType, + MediaSourceEnum aAudioType, bool aFake, bool aFakeTracks) { MOZ_ASSERT(NS_IsMainThread()); @@ -1963,12 +1987,13 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, MediaSourceEnum aVideoTyp nsRefPtr> p = media::GetOriginKey(origin, privateBrowsing, persist); - p->Then([id, aWindowId, aVideoType, + p->Then([id, aWindowId, aVideoType, aAudioType, aFake, aFakeTracks](const nsCString& aOriginKey) mutable { MOZ_ASSERT(NS_IsMainThread()); nsRefPtr mgr = MediaManager_GetInstance(); - nsRefPtr p = mgr->EnumerateRawDevices(aWindowId, aVideoType, + nsRefPtr p = mgr->EnumerateRawDevices(aWindowId, + aVideoType, aAudioType, aFake, aFakeTracks); p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // secondary result @@ -2007,6 +2032,7 @@ MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow, nsRefPtr p = EnumerateDevicesImpl(windowId, dom::MediaSourceEnum::Camera, + dom::MediaSourceEnum::Microphone, fake); p->Then([onSuccess](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // grab result diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 68ab74269201..d35f4bf40ece 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -597,10 +597,14 @@ public: // TODO: make private once we upgrade to GCC 4.8+ on linux. static already_AddRefed ToJSArray(SourceSet& aDevices); private: already_AddRefed - EnumerateRawDevices(uint64_t aWindowId, dom::MediaSourceEnum aSrcType, + EnumerateRawDevices(uint64_t aWindowId, + dom::MediaSourceEnum aVideoType, + dom::MediaSourceEnum aAudioType, bool aFake, bool aFakeTracks); already_AddRefed - EnumerateDevicesImpl(uint64_t aWindowId, dom::MediaSourceEnum aSrcType, + EnumerateDevicesImpl(uint64_t aWindowId, + dom::MediaSourceEnum aVideoSrcType, + dom::MediaSourceEnum aAudioSrcType, bool aFake = false, bool aFakeTracks = false); StreamListeners* AddWindowID(uint64_t aWindowId); diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 223a5acde76e..c45beae4ce24 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -268,7 +268,7 @@ MediaEngineWebRTCMicrophoneSource::Config(bool aEchoOn, uint32_t aEcho, // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets. // A finite result may be used to calculate this device's ranking as a choice. -uint32_t MediaEngineWebRTCAudioSource::GetBestFitnessDistance( +uint32_t MediaEngineWebRTCMicrophoneSource::GetBestFitnessDistance( const nsTArray& aConstraintSets, const nsString& aDeviceId) { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index fbbab15fb332..576b7680a6a9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -445,6 +445,8 @@ pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webe // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); +pref("media.getusermedia.audiocapture.enabled", false); + // TextTrack support pref("media.webvtt.enabled", true); pref("media.webvtt.regions.enabled", false); From 67ca74db0b4c9867d98c3b3f7cbaafbf2d9d9d39 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 81/90] Bug 1156472 - Part 12 - Allow to pipe the AudioCaptureStream into an AudioContext. r=mt,roc --- dom/media/MediaManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index a3fefcfd2fab..5b9d252f6a6a 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -797,6 +797,9 @@ public: if (mAudioSource && mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { domStream = DOMLocalMediaStream::CreateAudioCaptureStream(window); + // It should be possible to pipe the capture stream to anything. CORS is + // not a problem here, we got explicit user content. + domStream->SetPrincipal(window->GetExtantDoc()->NodePrincipal()); msg->RegisterCaptureStreamForWindow( mWindowID, domStream->GetStream()->AsProcessedStream()); window->SetAudioCapture(true); From 90a222f71a3ffb4291c2cba6ea4dc6f9fd1d7f22 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 82/90] Bug 1156472 - Part 13 - Make necessary adjustments for integer audio. r=jesup --- dom/media/AudioCaptureStream.cpp | 133 +++++++++++++++++++++++++++++++ dom/media/AudioChannelFormat.cpp | 108 ------------------------- dom/media/AudioChannelFormat.h | 129 +++++++++++++++++++++++++++--- dom/media/AudioSegment.cpp | 6 +- 4 files changed, 253 insertions(+), 123 deletions(-) create mode 100644 dom/media/AudioCaptureStream.cpp diff --git a/dom/media/AudioCaptureStream.cpp b/dom/media/AudioCaptureStream.cpp new file mode 100644 index 000000000000..f22050328958 --- /dev/null +++ b/dom/media/AudioCaptureStream.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaStreamGraphImpl.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/unused.h" + +#include "AudioSegment.h" +#include "mozilla/Logging.h" +#include "mozilla/Attributes.h" +#include "AudioCaptureStream.h" +#include "ImageContainer.h" +#include "AudioNodeEngine.h" +#include "AudioNodeStream.h" +#include "AudioNodeExternalInputStream.h" +#include "webaudio/MediaStreamAudioDestinationNode.h" +#include +#include "DOMMediaStream.h" + +using namespace mozilla::layers; +using namespace mozilla::dom; +using namespace mozilla::gfx; + +namespace mozilla +{ + +// We are mixing to mono until PeerConnection can accept stereo +static const uint32_t MONO = 1; + +AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper) + : ProcessedMediaStream(aWrapper), mTrackCreated(false) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_COUNT_CTOR(AudioCaptureStream); + mMixer.AddCallback(this); +} + +AudioCaptureStream::~AudioCaptureStream() +{ + MOZ_COUNT_DTOR(AudioCaptureStream); + mMixer.RemoveCallback(this); +} + +void +AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, + uint32_t aFlags) +{ + uint32_t inputCount = mInputs.Length(); + StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); + // Notify the DOM everything is in order. + if (!mTrackCreated) { + for (uint32_t i = 0; i < mListeners.Length(); i++) { + MediaStreamListener* l = mListeners[i]; + AudioSegment tmp; + l->NotifyQueuedTrackChanges( + Graph(), AUDIO_TRACK, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp); + l->NotifyFinishedTrackCreation(Graph()); + } + mTrackCreated = true; + } + + // If the captured stream is connected back to a object on the page (be it an + // HTMLMediaElement with a stream as source, or an AudioContext), a cycle + // situation occur. This can work if it's an AudioContext with at least one + // DelayNode, but the MSG will mute the whole cycle otherwise. + bool blocked = mFinished || mBlocked.GetAt(aFrom); + if (blocked || InMutedCycle() || inputCount == 0) { + track->Get()->AppendNullData(aTo - aFrom); + } else { + // We mix down all the tracks of all inputs, to a stereo track. Everything + // is {up,down}-mixed to stereo. + mMixer.StartMixing(); + AudioSegment output; + for (uint32_t i = 0; i < inputCount; i++) { + MediaStream* s = mInputs[i]->GetSource(); + StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO); + while (!tracks.IsEnded()) { + AudioSegment* inputSegment = tracks->Get(); + StreamTime inputStart = s->GraphTimeToStreamTime(aFrom); + StreamTime inputEnd = s->GraphTimeToStreamTime(aTo); + AudioSegment toMix; + toMix.AppendSlice(*inputSegment, inputStart, inputEnd); + // Care for streams blocked in the [aTo, aFrom] range. + if (inputEnd - inputStart < aTo - aFrom) { + toMix.AppendNullData((aTo - aFrom) - (inputEnd - inputStart)); + } + toMix.Mix(mMixer, MONO, Graph()->GraphRate()); + tracks.Next(); + } + } + // This calls MixerCallback below + mMixer.FinishMixing(); + } + + // Regardless of the status of the input tracks, we go foward. + mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime((aTo))); +} + +void +AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer, + AudioSampleFormat aFormat, uint32_t aChannels, + uint32_t aFrames, uint32_t aSampleRate) +{ + nsAutoTArray, MONO> output; + nsAutoTArray bufferPtrs; + output.SetLength(MONO); + bufferPtrs.SetLength(MONO); + + uint32_t written = 0; + // We need to copy here, because the mixer will reuse the storage, we should + // not hold onto it. Buffers are in planar format. + for (uint32_t channel = 0; channel < aChannels; channel++) { + AudioDataValue* out = output[channel].AppendElements(aFrames); + PodCopy(out, aMixedBuffer + written, aFrames); + bufferPtrs[channel] = out; + written += aFrames; + } + AudioChunk chunk; + chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(&output); + chunk.mDuration = aFrames; + chunk.mBufferFormat = aFormat; + chunk.mVolume = 1.0f; + chunk.mChannelData.SetLength(MONO); + for (uint32_t channel = 0; channel < aChannels; channel++) { + chunk.mChannelData[channel] = bufferPtrs[channel]; + } + + // Now we have mixed data, simply append it to out track. + EnsureTrack(AUDIO_TRACK)->Get()->AppendAndConsumeChunk(&chunk); +} +} diff --git a/dom/media/AudioChannelFormat.cpp b/dom/media/AudioChannelFormat.cpp index 2534851bed17..1a1ce9d61ac7 100644 --- a/dom/media/AudioChannelFormat.cpp +++ b/dom/media/AudioChannelFormat.cpp @@ -4,26 +4,11 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AudioChannelFormat.h" -#include "nsTArray.h" #include namespace mozilla { -enum { - SURROUND_L, - SURROUND_R, - SURROUND_C, - SURROUND_LFE, - SURROUND_SL, - SURROUND_SR -}; - -static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6; - -static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS; -static const float IGNORE_F = 0.0f; - uint32_t GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2) { @@ -63,9 +48,6 @@ gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = { { 0, 1, 2, 3, 4, IGNORE } } }; -static const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] = - { 0, 5, 9, 12, 14 }; - void AudioChannelsUpMix(nsTArray* aChannelArray, uint32_t aOutputChannelCount, @@ -108,94 +90,4 @@ AudioChannelsUpMix(nsTArray* aChannelArray, } } -/** - * DownMixMatrix represents a conversion matrix efficiently by exploiting the - * fact that each input channel contributes to at most one output channel, - * except possibly for the C input channel in layouts that have one. Also, - * every input channel is multiplied by the same coefficient for every output - * channel it contributes to. - */ -struct DownMixMatrix { - // Every input channel c is copied to output channel mInputDestination[c] - // after multiplying by mInputCoefficient[c]. - uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; - // If not IGNORE, then the C channel is copied to this output channel after - // multiplying by its coefficient. - uint8_t mCExtraDestination; - float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS]; -}; - -static const DownMixMatrix -gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = -{ - // Downmixes to mono - { { 0, 0 }, IGNORE, { 0.5f, 0.5f } }, - { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } }, - { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } }, - { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } }, - { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } }, - // Downmixes to stereo - { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } }, - { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, - { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } }, - // Downmixes to 3-channel - { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } }, - { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, - // Downmixes to quad - { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } }, - // Downmixes to 5-channel - { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } } -}; - -void -AudioChannelsDownMix(const nsTArray& aChannelArray, - float** aOutputChannels, - uint32_t aOutputChannelCount, - uint32_t aDuration) -{ - uint32_t inputChannelCount = aChannelArray.Length(); - const void* const* inputChannels = aChannelArray.Elements(); - NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do"); - - if (inputChannelCount > 6) { - // Just drop the unknown channels. - for (uint32_t o = 0; o < aOutputChannelCount; ++o) { - memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float)); - } - return; - } - - // Ignore unknown channels, they're just dropped. - inputChannelCount = std::min(6, inputChannelCount); - - const DownMixMatrix& m = gDownMixMatrices[ - gMixingMatrixIndexByChannels[aOutputChannelCount - 1] + - inputChannelCount - aOutputChannelCount - 1]; - - // This is slow, but general. We can define custom code for special - // cases later. - for (uint32_t s = 0; s < aDuration; ++s) { - // Reserve an extra junk channel at the end for the cases where we - // want an input channel to contribute to nothing - float outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1]; - memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS)); - for (uint32_t c = 0; c < inputChannelCount; ++c) { - outputChannels[m.mInputDestination[c]] += - m.mInputCoefficient[c]*(static_cast(inputChannels[c]))[s]; - } - // Utilize the fact that in every layout, C is the third channel. - if (m.mCExtraDestination != IGNORE) { - outputChannels[m.mCExtraDestination] += - m.mInputCoefficient[SURROUND_C]*(static_cast(inputChannels[SURROUND_C]))[s]; - } - - for (uint32_t c = 0; c < aOutputChannelCount; ++c) { - aOutputChannels[c][s] = outputChannels[c]; - } - } -} - } // namespace mozilla diff --git a/dom/media/AudioChannelFormat.h b/dom/media/AudioChannelFormat.h index 99a201456aa5..d5aef21c5668 100644 --- a/dom/media/AudioChannelFormat.h +++ b/dom/media/AudioChannelFormat.h @@ -9,6 +9,8 @@ #include #include "nsTArrayForwardDeclare.h" +#include "AudioSampleFormat.h" +#include "nsTArray.h" namespace mozilla { @@ -29,6 +31,26 @@ namespace mozilla { * Only 1, 2, 4 and 6 are currently defined in Web Audio. */ +enum { + SURROUND_L, + SURROUND_R, + SURROUND_C, + SURROUND_LFE, + SURROUND_SL, + SURROUND_SR +}; + +const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6; + +// This is defined by some Windows SDK header. +#undef IGNORE + +const int IGNORE = CUSTOM_CHANNEL_LAYOUTS; +const float IGNORE_F = 0.0f; + +const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] = + { 0, 5, 9, 12, 14 }; + /** * Return a channel count whose channel layout includes all the channels from * aChannels1 and aChannels2. @@ -53,19 +75,102 @@ AudioChannelsUpMix(nsTArray* aChannelArray, uint32_t aOutputChannelCount, const void* aZeroChannel); -/** - * Given an array of input channels (which must be float format!), - * downmix to aOutputChannelCount, and copy the results to the - * channel buffers in aOutputChannels. - * Don't call this with input count <= output count. - */ -void -AudioChannelsDownMix(const nsTArray& aChannelArray, - float** aOutputChannels, - uint32_t aOutputChannelCount, - uint32_t aDuration); -// A version of AudioChannelsDownMix that downmixes int16_ts may be required. +/** + * DownMixMatrix represents a conversion matrix efficiently by exploiting the + * fact that each input channel contributes to at most one output channel, + * except possibly for the C input channel in layouts that have one. Also, + * every input channel is multiplied by the same coefficient for every output + * channel it contributes to. + */ +struct DownMixMatrix { + // Every input channel c is copied to output channel mInputDestination[c] + // after multiplying by mInputCoefficient[c]. + uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; + // If not IGNORE, then the C channel is copied to this output channel after + // multiplying by its coefficient. + uint8_t mCExtraDestination; + float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS]; +}; + +static const DownMixMatrix +gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = +{ + // Downmixes to mono + { { 0, 0 }, IGNORE, { 0.5f, 0.5f } }, + { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } }, + { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } }, + { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } }, + { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } }, + // Downmixes to stereo + { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } }, + { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, + { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } }, + // Downmixes to 3-channel + { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } }, + { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, + // Downmixes to quad + { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } }, + // Downmixes to 5-channel + { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } } +}; + +/** + * Given an array of input channels, downmix to aOutputChannelCount, and copy + * the results to the channel buffers in aOutputChannels. Don't call this with + * input count <= output count. + */ +template +void AudioChannelsDownMix(const nsTArray& aChannelArray, + T** aOutputChannels, + uint32_t aOutputChannelCount, + uint32_t aDuration) +{ + uint32_t inputChannelCount = aChannelArray.Length(); + const void* const* inputChannels = aChannelArray.Elements(); + NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do"); + + if (inputChannelCount > 6) { + // Just drop the unknown channels. + for (uint32_t o = 0; o < aOutputChannelCount; ++o) { + memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(T)); + } + return; + } + + // Ignore unknown channels, they're just dropped. + inputChannelCount = std::min(6, inputChannelCount); + + const DownMixMatrix& m = gDownMixMatrices[ + gMixingMatrixIndexByChannels[aOutputChannelCount - 1] + + inputChannelCount - aOutputChannelCount - 1]; + + // This is slow, but general. We can define custom code for special + // cases later. + for (uint32_t s = 0; s < aDuration; ++s) { + // Reserve an extra junk channel at the end for the cases where we + // want an input channel to contribute to nothing + T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1]; + memset(outputChannels, 0, sizeof(T)*(CUSTOM_CHANNEL_LAYOUTS)); + for (uint32_t c = 0; c < inputChannelCount; ++c) { + outputChannels[m.mInputDestination[c]] += + m.mInputCoefficient[c]*(static_cast(inputChannels[c]))[s]; + } + // Utilize the fact that in every layout, C is the third channel. + if (m.mCExtraDestination != IGNORE) { + outputChannels[m.mCExtraDestination] += + m.mInputCoefficient[SURROUND_C]*(static_cast(inputChannels[SURROUND_C]))[s]; + } + + for (uint32_t c = 0; c < aOutputChannelCount; ++c) { + aOutputChannels[c][s] = outputChannels[c]; + } + } +} + } // namespace mozilla diff --git a/dom/media/AudioSegment.cpp b/dom/media/AudioSegment.cpp index 15ac13e5537b..c4162842d360 100644 --- a/dom/media/AudioSegment.cpp +++ b/dom/media/AudioSegment.cpp @@ -206,13 +206,13 @@ AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels, AudioDataValue* ptr = PointerForOffsetInChannel(buf.Elements(), outBufferLength, aOutputChannels, channel, offsetSamples); - PodCopy(ptr, reinterpret_cast(channelData[channel]), + PodCopy(ptr, reinterpret_cast(channelData[channel]), frames); } MOZ_ASSERT(channelData.Length() == aOutputChannels); } else if (channelData.Length() > aOutputChannels) { // Down mix. - nsAutoTArray outChannelPtrs; + nsAutoTArray outChannelPtrs; outChannelPtrs.SetLength(aOutputChannels); uint32_t offsetSamples = 0; for (uint32_t channel = 0; channel < aOutputChannels; channel++) { @@ -228,7 +228,7 @@ AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels, AudioDataValue* ptr = PointerForOffsetInChannel(buf.Elements(), outBufferLength, aOutputChannels, channel, offsetSamples); - PodCopy(ptr, reinterpret_cast(channelData[channel]), + PodCopy(ptr, reinterpret_cast(channelData[channel]), frames); } } From 69bf340380012ad12ddeb1316e9dfd5cccbded79 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH 83/90] Bug 1156472 - Part 14 - Null check the window, because it can be different during the window's shutdown. r=baku In which case everything is cleaned up properly by the HTMLMediaElement themselves. --- dom/audiochannel/AudioChannelService.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index b71b491c5078..93a916b07b43 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -562,6 +562,15 @@ AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow, AudioChannelWindow* winData = GetWindowData(pTopWindow->WindowID()); + // This can happen, but only during shutdown, because the the outer window + // changes ScriptableTop, so that its ID is different. + // In this case either we are capturing, and it's too late because the window + // has been closed anyways, or we are un-capturing, and everything has already + // been cleaned up by the HTMLMediaElements or the AudioContexts. + if (!winData) { + return; + } + nsTObserverArray::ForwardIterator iter(winData->mAgents); while (iter.HasMore()) { From 87d9a57571a8fa91d105714ba6dcc302a6ab6481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Fri, 24 Jul 2015 16:21:57 +0200 Subject: [PATCH 84/90] Bug 1186981 - Remove dead #app-extension-point-end rules. r=mconley --- .../shared/customizableui/panelUIOverlay.inc.css | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/browser/themes/shared/customizableui/panelUIOverlay.inc.css b/browser/themes/shared/customizableui/panelUIOverlay.inc.css index 0b0ff14df84f..1128cb9289d2 100644 --- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css +++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css @@ -174,16 +174,6 @@ panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .pan flex-direction: column; } -#app-extension-point-end > #PanelUI-menu-button { - padding: 2px 5px; -} -#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-text { - display: none; -} -#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-icon { - margin: 0; -} - #PanelUI-popup > arrowscrollbox > autorepeatbutton { display: none; } From 715217c5e6f4c55662aef7d6d6e850a75b9b11e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Fri, 24 Jul 2015 16:22:16 +0200 Subject: [PATCH 85/90] Bug 1187236 - Identity block border should span the entire height on hover. r=paolo --- browser/themes/shared/identity-block/identity-block.inc.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css index 28137d147bcb..c7f1a71e8a4f 100644 --- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -18,7 +18,7 @@ %endif %endif - border-inline-end: 1px solid; + border-inline-end: 1px solid var(--identity-box-border-color); border-image: linear-gradient(transparent 15%, var(--identity-box-border-color) 15%, var(--identity-box-border-color) 85%, @@ -33,6 +33,7 @@ #identity-box:hover, #identity-box[open=true] { background-color: var(--identity-box-selected-background-color); + border-image-source: none; } #urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity { From d2ae11223ef8ab01f6abf24b708d3a36498a1b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Fri, 24 Jul 2015 16:22:46 +0200 Subject: [PATCH 86/90] Bug 1186984 - Fix --verified-identity-box-background-color vs. --verified-identity-box-backgroundcolor CSS variable name mismatch. r=paolo --- browser/themes/linux/browser.css | 4 ++-- browser/themes/shared/devedition.inc.css | 2 +- browser/themes/windows/browser.css | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index 24ee34a977da..856610f65477 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -34,7 +34,7 @@ --toolbarbutton-combined-boxshadow: 0 0 0 1px hsla(0,0%,100%,.2); --toolbarbutton-combined-backgroundimage: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px); - --verified-identity-box-backgroundcolor: #fff; + --identity-box-verified-background-color: #fff; } #menubar-items { @@ -986,7 +986,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba } #identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) { - background-color: var(--verified-identity-box-backgroundcolor); + background-color: var(--identity-box-verified-background-color); } #identity-box:-moz-focusring { diff --git a/browser/themes/shared/devedition.inc.css b/browser/themes/shared/devedition.inc.css index c8e9193a764c..71880fb3a0d9 100644 --- a/browser/themes/shared/devedition.inc.css +++ b/browser/themes/shared/devedition.inc.css @@ -63,7 +63,7 @@ :root[devtoolstheme="dark"] #identity-box { --identity-box-border-color: #5F6670; --identity-box-chrome-color: #46afe3; - --verified-identity-box-background-color: transparent; + --identity-box-verified-background-color: transparent; --identity-box-selected-background-color: rgba(231,230,230,.2); } diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index 1487e380a16e..a251d08a75b1 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -38,7 +38,7 @@ --toolbarbutton-combined-boxshadow: none; --toolbarbutton-combined-backgroundimage: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 16px); - --verified-identity-box-backgroundcolor: #FFF; + --identity-box-verified-background-color: #fff; --urlbar-dropmarker-url: url("chrome://browser/skin/urlbar-history-dropmarker.png"); --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px); @@ -1437,7 +1437,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder, } #identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) { - background-color: var(--verified-identity-box-backgroundcolor); + background-color: var(--identity-box-verified-background-color); } #identity-box:-moz-focusring { From 3f1982d3de19ac2fceda001cf439ba9d13a0c9f2 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Fri, 24 Jul 2015 10:37:52 -0400 Subject: [PATCH 87/90] Bug 1176358 - Pass the symbols url instead of an urllib2 opener. DONTBUILD. r=bhearsum --- testing/mozharness/scripts/firefox_ui_updates.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/mozharness/scripts/firefox_ui_updates.py b/testing/mozharness/scripts/firefox_ui_updates.py index 53681f8db80a..3bf866d430a7 100644 --- a/testing/mozharness/scripts/firefox_ui_updates.py +++ b/testing/mozharness/scripts/firefox_ui_updates.py @@ -267,7 +267,8 @@ class FirefoxUIUpdates(FirefoxUITests): try: # Let's see if the symbols are available - return urllib2.urlopen(symbols_url) + urllib2.urlopen(symbols_path) + return symbols_path except urllib2.HTTPError, e: self.warning("%s - %s" % (str(e), symbols_url)) From b24bd973bdbc7ddcee1ea7af3503566e594a2683 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Fri, 24 Jul 2015 10:41:54 -0400 Subject: [PATCH 88/90] Bug 1182798 - Set status summary for Firefox UI tests + change exit code. DONTBUILD. r=jlund --- .../mozharness/scripts/firefox_ui_updates.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/testing/mozharness/scripts/firefox_ui_updates.py b/testing/mozharness/scripts/firefox_ui_updates.py index 3bf866d430a7..f4f605a6a43c 100644 --- a/testing/mozharness/scripts/firefox_ui_updates.py +++ b/testing/mozharness/scripts/firefox_ui_updates.py @@ -20,6 +20,7 @@ sys.path.insert(1, os.path.dirname(sys.path[0])) from mozharness.base.script import PreScriptAction from mozharness.mozilla.testing.firefox_ui_tests import FirefoxUITests +from mozharness.mozilla.buildbot import TBPL_SUCCESS, TBPL_WARNING, EXIT_STATUS_DICT INSTALLER_SUFFIXES = ('.tar.bz2', '.zip', '.dmg', '.exe', '.apk', '.tar.gz') @@ -420,14 +421,25 @@ class FirefoxUIUpdates(FirefoxUITests): results[build_id][locale] = retcode - self.info("Firefox UI update tests failed locales:") + # Determine which locales have failed and set scripts exit code + exit_status = TBPL_SUCCESS for build_id in sorted(results.keys()): - self.info(build_id) failed_locales = [] for locale in sorted(results[build_id].keys()): if results[build_id][locale] != 0: failed_locales.append(locale) - self.info(" %s" % (', '.join(failed_locales))) + + if failed_locales: + if exit_status == TBPL_SUCCESS: + self.info("") + self.info("SUMMARY - Firefox UI update tests failed locales:") + self.info("=================================================") + exit_status = TBPL_WARNING + + self.info(build_id) + self.info(" %s" % (', '.join(failed_locales))) + + self.return_code = EXIT_STATUS_DICT[exit_status] if __name__ == '__main__': From 15d0a4b27a0ebc29c9c518bed5b10130f8d23ce6 Mon Sep 17 00:00:00 2001 From: Armen Zambrano Gasparnian Date: Fri, 24 Jul 2015 11:03:03 -0400 Subject: [PATCH 89/90] Bug 1186987 - If file_path is None do not check if it is an executable. DONTBUILD. r=jlund --- testing/mozharness/mozharness/mozilla/vcstools.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/vcstools.py b/testing/mozharness/mozharness/mozilla/vcstools.py index 1259cabdd831..c7349291539b 100644 --- a/testing/mozharness/mozharness/mozilla/vcstools.py +++ b/testing/mozharness/mozharness/mozilla/vcstools.py @@ -49,10 +49,9 @@ class VCSToolsScript(VCSScript): if type(self.query_exe(vcs_tool)) is list: continue - if not self.is_exe(file_path): - self.critical("%s is not executable." % file_path) - if file_path is None: self.fatal("This machine is missing %s, if this is your " "local machine you can use --cfg " "developer_config.py" % vcs_tool) + elif not self.is_exe(file_path): + self.critical("%s is not executable." % file_path) From 2b73aa4f6337c58d376148a961b895ee0f0b544b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 24 Jul 2015 17:08:37 +0200 Subject: [PATCH 90/90] Backed out 14 changesets (bug 1156472) for bustage on a CLOSED TREE Backed out changeset 2ddbf85a42c0 (bug 1156472) Backed out changeset 306d02e17081 (bug 1156472) Backed out changeset 03598139f39a (bug 1156472) Backed out changeset 4b1e6069b598 (bug 1156472) Backed out changeset 6c588a5eaaec (bug 1156472) Backed out changeset 8c98d7beaea7 (bug 1156472) Backed out changeset fbf59fbb5875 (bug 1156472) Backed out changeset 66479dd9eed9 (bug 1156472) Backed out changeset c8502deeed33 (bug 1156472) Backed out changeset 1a60ff1149a1 (bug 1156472) Backed out changeset af1638279785 (bug 1156472) Backed out changeset 8210276a98ca (bug 1156472) Backed out changeset 13730e7c5997 (bug 1156472) Backed out changeset 05acb71cf981 (bug 1156472) --- .../locales/en-US/chrome/browser/browser.dtd | 1 - .../en-US/chrome/browser/browser.properties | 23 +-- browser/modules/ContentWebRTC.jsm | 14 +- browser/modules/webrtcUI.jsm | 50 +++--- dom/audiochannel/AudioChannelAgent.cpp | 20 --- dom/audiochannel/AudioChannelAgent.h | 2 - dom/audiochannel/AudioChannelService.cpp | 32 ---- dom/audiochannel/AudioChannelService.h | 8 - dom/audiochannel/nsIAudioChannelAgent.idl | 7 +- dom/base/nsGlobalWindow.cpp | 22 +-- dom/base/nsPIDOMWindow.h | 5 - dom/fmradio/FMRadio.cpp | 6 - dom/html/HTMLMediaElement.cpp | 62 +------ dom/html/HTMLMediaElement.h | 6 - dom/media/AudioCaptureStream.cpp | 133 --------------- dom/media/AudioCaptureStream.cpp.rej | 133 --------------- dom/media/AudioCaptureStream.h.rej | 43 ----- dom/media/AudioChannelFormat.cpp | 112 +++++++++++- dom/media/AudioChannelFormat.h | 123 +------------- dom/media/AudioMixer.h | 6 +- dom/media/AudioSegment.cpp | 97 ----------- dom/media/AudioSegment.h | 9 +- dom/media/DOMMediaStream.cpp | 30 ---- dom/media/DOMMediaStream.h | 15 -- dom/media/DecodedStream.cpp | 8 - dom/media/DecodedStream.h | 1 - dom/media/MediaDecoder.cpp | 7 - dom/media/MediaDecoder.h | 2 - dom/media/MediaDecoderStateMachine.cpp | 29 ---- dom/media/MediaDecoderStateMachine.h | 3 - dom/media/MediaManager.cpp | 160 ++++++------------ dom/media/MediaManager.h | 10 +- dom/media/MediaStreamGraph.cpp | 73 -------- dom/media/MediaStreamGraph.h | 10 -- dom/media/MediaStreamGraphImpl.h | 17 -- dom/media/moz.build | 1 - dom/media/tests/mochitest/head.js | 113 +------------ dom/media/tests/mochitest/mochitest.ini | 1 - dom/media/tests/mochitest/pc.js | 39 ++++- .../test_getUserMedia_audioCapture.html | 110 ------------ .../test_peerConnection_replaceTrack.html | 2 +- .../test_peerConnection_webAudio.html | 2 +- dom/media/webaudio/AudioDestinationNode.cpp | 40 +---- dom/media/webaudio/AudioDestinationNode.h | 2 - dom/media/webrtc/MediaEngineWebRTC.cpp | 19 +-- dom/media/webrtc/MediaEngineWebRTC.h | 78 +-------- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 102 +++-------- dom/webidl/Constraints.webidl | 1 - modules/libpref/init/all.js | 2 - 49 files changed, 293 insertions(+), 1498 deletions(-) delete mode 100644 dom/media/AudioCaptureStream.cpp delete mode 100644 dom/media/AudioCaptureStream.cpp.rej delete mode 100644 dom/media/AudioCaptureStream.h.rej delete mode 100644 dom/media/tests/mochitest/test_getUserMedia_audioCapture.html diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd index fe7439e0a445..89981e6936c4 100644 --- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -758,7 +758,6 @@ you can use these alternative items. Otherwise, their values should be empty. - - diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index 1a71d59b1b09..766446fac755 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -553,17 +553,13 @@ identity.loggedIn.signOut.accessKey = O # LOCALIZATION NOTE (getUserMedia.shareCamera.message, getUserMedia.shareMicrophone.message, # getUserMedia.shareScreen.message, getUserMedia.shareCameraAndMicrophone.message, -# getUserMedia.shareScreenAndMicrophone.message, getUserMedia.shareCameraAndAudioCapture.message, -# getUserMedia.shareAudioCapture.message, getUserMedia.shareScreenAndAudioCapture.message): +# getUserMedia.shareScreenAndMicrophone.message): # %S is the website origin (e.g. www.mozilla.org) getUserMedia.shareCamera.message = Would you like to share your camera with %S? getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S? getUserMedia.shareScreen.message = Would you like to share your screen with %S? getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S? -getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab's audio with %S? getUserMedia.shareScreenAndMicrophone.message = Would you like to share your microphone and screen with %S? -getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab's audio and your screen with %S? -getUserMedia.shareAudioCapture.message = Would you like to share this tab's audio with %S? getUserMedia.selectWindow.label=Window to share: getUserMedia.selectWindow.accesskey=W getUserMedia.selectScreen.label=Screen to share: @@ -605,7 +601,6 @@ getUserMedia.sharingApplication.message = You are currently sharing an applicati getUserMedia.sharingScreen.message = You are currently sharing your screen with this page. getUserMedia.sharingWindow.message = You are currently sharing a window with this page. getUserMedia.sharingBrowser.message = You are currently sharing a tab with this page. -getUserMedia.sharingAudioCapture.message = You are currently sharing a tab's audio with this page. getUserMedia.continueSharing.label = Continue Sharing getUserMedia.continueSharing.accesskey = C getUserMedia.stopSharing.label = Stop Sharing @@ -615,7 +610,6 @@ getUserMedia.sharingMenu.label = Tabs sharing devices getUserMedia.sharingMenu.accesskey = d # LOCALIZATION NOTE (getUserMedia.sharingMenuCamera # getUserMedia.sharingMenuMicrophone, -# getUserMedia.sharingMenuAudioCapture, # getUserMedia.sharingMenuApplication, # getUserMedia.sharingMenuScreen, # getUserMedia.sharingMenuWindow, @@ -625,11 +619,6 @@ getUserMedia.sharingMenu.accesskey = d # getUserMedia.sharingMenuCameraMicrophoneScreen, # getUserMedia.sharingMenuCameraMicrophoneWindow, # getUserMedia.sharingMenuCameraMicrophoneBrowser, -# getUserMedia.sharingMenuCameraAudioCapture, -# getUserMedia.sharingMenuCameraAudioCaptureApplication, -# getUserMedia.sharingMenuCameraAudioCaptureScreen, -# getUserMedia.sharingMenuCameraAudioCaptureWindow, -# getUserMedia.sharingMenuCameraAudioCaptureBrowser, # getUserMedia.sharingMenuCameraApplication, # getUserMedia.sharingMenuCameraScreen, # getUserMedia.sharingMenuCameraWindow, @@ -641,7 +630,6 @@ getUserMedia.sharingMenu.accesskey = d # %S is the website origin (e.g. www.mozilla.org) getUserMedia.sharingMenuCamera = %S (camera) getUserMedia.sharingMenuMicrophone = %S (microphone) -getUserMedia.sharingMenuAudioCapture = %S (tab audio) getUserMedia.sharingMenuApplication = %S (application) getUserMedia.sharingMenuScreen = %S (screen) getUserMedia.sharingMenuWindow = %S (window) @@ -651,11 +639,6 @@ getUserMedia.sharingMenuCameraMicrophoneApplication = %S (camera, microphone and getUserMedia.sharingMenuCameraMicrophoneScreen = %S (camera, microphone and screen) getUserMedia.sharingMenuCameraMicrophoneWindow = %S (camera, microphone and window) getUserMedia.sharingMenuCameraMicrophoneBrowser = %S (camera, microphone and tab) -getUserMedia.sharingMenuCameraAudioCapture = %S (camera and tab audio) -getUserMedia.sharingMenuCameraAudioCaptureApplication = %S (camera, tab audio and application) -getUserMedia.sharingMenuCameraAudioCaptureScreen = %S (camera, tab audio and screen) -getUserMedia.sharingMenuCameraAudioCaptureWindow = %S (camera, tab audio and window) -getUserMedia.sharingMenuCameraAudioCaptureBrowser = %S (camera, tab audio and tab) getUserMedia.sharingMenuCameraApplication = %S (camera and application) getUserMedia.sharingMenuCameraScreen = %S (camera and screen) getUserMedia.sharingMenuCameraWindow = %S (camera and window) @@ -664,10 +647,6 @@ getUserMedia.sharingMenuMicrophoneApplication = %S (microphone and application) getUserMedia.sharingMenuMicrophoneScreen = %S (microphone and screen) getUserMedia.sharingMenuMicrophoneWindow = %S (microphone and window) getUserMedia.sharingMenuMicrophoneBrowser = %S (microphone and tab) -getUserMedia.sharingMenuMicrophoneApplication = %S (tab audio and application) -getUserMedia.sharingMenuMicrophoneScreen = %S (tab audio and screen) -getUserMedia.sharingMenuMicrophoneWindow = %S (tab audio and window) -getUserMedia.sharingMenuMicrophoneBrowser = %S (tab audio and tab) # LOCALIZATION NOTE(getUserMedia.sharingMenuUnknownHost): this is used for the website # origin for the sharing menu if no readable origin could be deduced from the URL. getUserMedia.sharingMenuUnknownHost = Unknown origin diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm index e059c60d3d2f..5f0514170d6b 100644 --- a/browser/modules/ContentWebRTC.jsm +++ b/browser/modules/ContentWebRTC.jsm @@ -86,21 +86,14 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec // MediaStreamConstraints defines video as 'boolean or MediaTrackConstraints'. let video = aConstraints.video || aConstraints.picture; - let audio = aConstraints.audio; let sharingScreen = video && typeof(video) != "boolean" && video.mediaSource != "camera"; - let sharingAudio = audio && typeof(audio) != "boolean" && - audio.mediaSource != "microphone"; for (let device of aDevices) { device = device.QueryInterface(Ci.nsIMediaDevice); switch (device.type) { case "audio": - // Check that if we got a microphone, we have not requested an audio - // capture, and if we have requested an audio capture, we are not - // getting a microphone instead. - if (audio && (device.mediaSource == "microphone") != sharingAudio) { - audioDevices.push({name: device.name, deviceIndex: devices.length, - mediaSource: device.mediaSource}); + if (aConstraints.audio) { + audioDevices.push({name: device.name, deviceIndex: devices.length}); devices.push(device); } break; @@ -120,7 +113,7 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec if (videoDevices.length) requestTypes.push(sharingScreen ? "Screen" : "Camera"); if (audioDevices.length) - requestTypes.push(sharingAudio ? "AudioCapture" : "Microphone"); + requestTypes.push("Microphone"); if (!requestTypes.length) { denyRequest({callID: aCallID}, "NotFoundError"); @@ -140,7 +133,6 @@ function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSec secure: aSecure, requestTypes: requestTypes, sharingScreen: sharingScreen, - sharingAudio: sharingAudio, audioDevices: audioDevices, videoDevices: videoDevices }; diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index 792c58bf1dcd..be52cb8350f8 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -188,8 +188,7 @@ function getHost(uri, href) { function prompt(aBrowser, aRequest) { let {audioDevices: audioDevices, videoDevices: videoDevices, - sharingScreen: sharingScreen, sharingAudio: sharingAudio, - requestTypes: requestTypes} = aRequest; + sharingScreen: sharingScreen, requestTypes: requestTypes} = aRequest; let uri = Services.io.newURI(aRequest.documentURI, null, null); let host = getHost(uri); let chromeDoc = aBrowser.ownerDocument; @@ -199,9 +198,10 @@ function prompt(aBrowser, aRequest) { let message = stringBundle.getFormattedString(stringId, [host]); let mainLabel; - if (sharingScreen || sharingAudio) { + if (sharingScreen) { mainLabel = stringBundle.getString("getUserMedia.shareSelectedItems.label"); - } else { + } + else { let string = stringBundle.getString("getUserMedia.shareSelectedDevices.label"); mainLabel = PluralForm.get(requestTypes.length, string); } @@ -225,8 +225,8 @@ function prompt(aBrowser, aRequest) { } } ]; - // Bug 1037438: implement 'never' for screen sharing. - if (!sharingScreen && !sharingAudio) { + + if (!sharingScreen) { // Bug 1037438: implement 'never' for screen sharing. secondaryActions.push({ label: stringBundle.getString("getUserMedia.never.label"), accessKey: stringBundle.getString("getUserMedia.never.accesskey"), @@ -243,10 +243,10 @@ function prompt(aBrowser, aRequest) { }); } - if (aRequest.secure && !sharingScreen && !sharingAudio) { + if (aRequest.secure && !sharingScreen) { // Don't show the 'Always' action if the connection isn't secure, or for - // screen/audio sharing (because we can't guess which window the user wants - // to share without prompting). + // screen sharing (because we can't guess which window the user wants to + // share without prompting). secondaryActions.unshift({ label: stringBundle.getString("getUserMedia.always.label"), accessKey: stringBundle.getString("getUserMedia.always.accesskey"), @@ -266,8 +266,7 @@ function prompt(aBrowser, aRequest) { if (aTopic == "shown") { let PopupNotifications = chromeDoc.defaultView.PopupNotifications; let popupId = "Devices"; - if (requestTypes.length == 1 && (requestTypes[0] == "Microphone" || - requestTypes[0] == "AudioCapture")) + if (requestTypes.length == 1 && requestTypes[0] == "Microphone") popupId = "Microphone"; if (requestTypes.indexOf("Screen") != -1) popupId = "Screen"; @@ -385,7 +384,7 @@ function prompt(aBrowser, aRequest) { chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length || sharingScreen; chromeDoc.getElementById("webRTC-selectWindowOrScreen").hidden = !sharingScreen || !videoDevices.length; - chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length || sharingAudio; + chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length; let camMenupopup = chromeDoc.getElementById("webRTC-selectCamera-menupopup"); let windowMenupopup = chromeDoc.getElementById("webRTC-selectWindow-menupopup"); @@ -394,16 +393,12 @@ function prompt(aBrowser, aRequest) { listScreenShareDevices(windowMenupopup, videoDevices); else listDevices(camMenupopup, videoDevices); - - if (!sharingAudio) - listDevices(micMenupopup, audioDevices); - + listDevices(micMenupopup, audioDevices); if (requestTypes.length == 2) { let stringBundle = chromeDoc.defaultView.gNavigatorBundle; if (!sharingScreen) addDeviceToList(camMenupopup, stringBundle.getString("getUserMedia.noVideo.label"), "-1"); - if (!sharingAudio) - addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); + addDeviceToList(micMenupopup, stringBundle.getString("getUserMedia.noAudio.label"), "-1"); } this.mainAction.callback = function(aRemember) { @@ -421,18 +416,13 @@ function prompt(aBrowser, aRequest) { } } if (audioDevices.length) { - if (!sharingAudio) { - let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; - let allowMic = audioDeviceIndex != "-1"; - if (allowMic) - allowedDevices.push(audioDeviceIndex); - if (aRemember) { - perms.add(uri, "microphone", - allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION); - } - } else { - // Only one device possible for audio capture. - allowedDevices.push(0); + let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value; + let allowMic = audioDeviceIndex != "-1"; + if (allowMic) + allowedDevices.push(audioDeviceIndex); + if (aRemember) { + perms.add(uri, "microphone", + allowMic ? perms.ALLOW_ACTION : perms.DENY_ACTION); } } diff --git a/dom/audiochannel/AudioChannelAgent.cpp b/dom/audiochannel/AudioChannelAgent.cpp index 3a68bdd371ac..c02602db25de 100644 --- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -35,7 +35,6 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent) AudioChannelAgent::AudioChannelAgent() : mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR) - , mInnerWindowID(0) , mIsRegToService(false) { } @@ -105,10 +104,6 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType, } if (aWindow) { - nsCOMPtr pInnerWindow = do_QueryInterface(aWindow); - MOZ_ASSERT(pInnerWindow->IsInnerWindow()); - mInnerWindowID = pInnerWindow->WindowID(); - nsCOMPtr topWindow; aWindow->GetScriptableTop(getter_AddRefs(topWindow)); mWindow = do_QueryInterface(topWindow); @@ -196,18 +191,3 @@ AudioChannelAgent::WindowID() const { return mWindow ? mWindow->WindowID() : 0; } - -void -AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID) -{ - if (aInnerWindowID != mInnerWindowID) { - return; - } - - nsCOMPtr callback = GetCallback(); - if (!callback) { - return; - } - - callback->WindowAudioCaptureChanged(); -} diff --git a/dom/audiochannel/AudioChannelAgent.h b/dom/audiochannel/AudioChannelAgent.h index 809d34f2a1e7..75b2fd335edc 100644 --- a/dom/audiochannel/AudioChannelAgent.h +++ b/dom/audiochannel/AudioChannelAgent.h @@ -34,7 +34,6 @@ public: AudioChannelAgent(); void WindowVolumeChanged(); - void WindowAudioCaptureChanged(uint64_t aInnerWindowID); nsPIDOMWindow* Window() const { @@ -62,7 +61,6 @@ private: nsWeakPtr mWeakCallback; int32_t mAudioChannelType; - uint64_t mInnerWindowID; bool mIsRegToService; }; diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index 93a916b07b43..c3b858ab7761 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -546,38 +546,6 @@ AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow) } } -void -AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow, - uint64_t aInnerWindowID) -{ - MOZ_ASSERT(aWindow); - MOZ_ASSERT(aWindow->IsOuterWindow()); - - nsCOMPtr topWindow; - aWindow->GetScriptableTop(getter_AddRefs(topWindow)); - nsCOMPtr pTopWindow = do_QueryInterface(topWindow); - if (!pTopWindow) { - return; - } - - AudioChannelWindow* winData = GetWindowData(pTopWindow->WindowID()); - - // This can happen, but only during shutdown, because the the outer window - // changes ScriptableTop, so that its ID is different. - // In this case either we are capturing, and it's too late because the window - // has been closed anyways, or we are un-capturing, and everything has already - // been cleaned up by the HTMLMediaElements or the AudioContexts. - if (!winData) { - return; - } - - nsTObserverArray::ForwardIterator - iter(winData->mAgents); - while (iter.HasMore()) { - iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID); - } -} - /* static */ const nsAttrValue::EnumTable* AudioChannelService::GetAudioChannelTable() { diff --git a/dom/audiochannel/AudioChannelService.h b/dom/audiochannel/AudioChannelService.h index 4dc0bedb7475..a0a65d8c737a 100644 --- a/dom/audiochannel/AudioChannelService.h +++ b/dom/audiochannel/AudioChannelService.h @@ -102,14 +102,6 @@ public: void RefreshAgentsVolume(nsPIDOMWindow* aWindow); - // This method needs to know the inner window that wants to capture audio. We - // group agents per top outer window, but we can have multiple innerWindow per - // top outerWindow (subiframes, etc.) and we have to identify all the agents - // just for a particular innerWindow. - void RefreshAgentsCapture(nsPIDOMWindow* aWindow, - uint64_t aInnerWindowID); - - #ifdef MOZ_WIDGET_GONK void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager) { diff --git a/dom/audiochannel/nsIAudioChannelAgent.idl b/dom/audiochannel/nsIAudioChannelAgent.idl index 87934d4bacc0..a35f54c09530 100644 --- a/dom/audiochannel/nsIAudioChannelAgent.idl +++ b/dom/audiochannel/nsIAudioChannelAgent.idl @@ -6,18 +6,13 @@ interface nsIDOMWindow; -[uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)] +[uuid(4f537c88-3722-4946-9a09-ce559fa0591d)] interface nsIAudioChannelAgentCallback : nsISupports { /** * Notified when the window volume/mute is changed */ void windowVolumeChanged(in float aVolume, in bool aMuted); - - /** - * Notified when the capture state is changed. - */ - void windowAudioCaptureChanged(); }; /** diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 59483a458bd1..3827f6b57a01 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -564,7 +564,7 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow) mMayHavePointerEnterLeaveEventListener(false), mIsModalContentWindow(false), mIsActive(false), mIsBackground(false), - mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false), + mAudioMuted(false), mAudioVolume(1.0), mDesktopModeViewport(false), mInnerWindow(nullptr), mOuterWindow(aOuterWindow), // Make sure no actual window ends up with mWindowID == 0 @@ -3745,26 +3745,6 @@ nsPIDOMWindow::RefreshMediaElements() service->RefreshAgentsVolume(GetOuterWindow()); } -bool -nsPIDOMWindow::GetAudioCaptured() const -{ - MOZ_ASSERT(IsInnerWindow()); - return mAudioCaptured; -} - -nsresult -nsPIDOMWindow::SetAudioCapture(bool aCapture) -{ - MOZ_ASSERT(IsInnerWindow()); - - mAudioCaptured = aCapture; - - nsRefPtr service = AudioChannelService::GetOrCreate(); - service->RefreshAgentsCapture(GetOuterWindow(), mWindowID); - - return NS_OK; -} - // nsISpeechSynthesisGetter #ifdef MOZ_WEBSPEECH diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 3e6404e9950c..b9f17bb801a4 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -185,9 +185,6 @@ public: float GetAudioVolume() const; nsresult SetAudioVolume(float aVolume); - bool GetAudioCaptured() const; - nsresult SetAudioCapture(bool aCapture); - virtual void SetServiceWorkersTestingEnabled(bool aEnabled) { MOZ_ASSERT(IsOuterWindow()); @@ -825,8 +822,6 @@ protected: bool mAudioMuted; float mAudioVolume; - bool mAudioCaptured; - // current desktop mode flag. bool mDesktopModeViewport; diff --git a/dom/fmradio/FMRadio.cpp b/dom/fmradio/FMRadio.cpp index 150ee703a1f7..1f5d8de3f0e1 100644 --- a/dom/fmradio/FMRadio.cpp +++ b/dom/fmradio/FMRadio.cpp @@ -471,12 +471,6 @@ FMRadio::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } -NS_IMETHODIMP -FMRadio::WindowAudioCaptureChanged() -{ - return NS_OK; -} - NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index f511ef93f51c..493bbd26678a 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2030,7 +2030,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo mAllowCasting(false), mIsCasting(false), mAudioCaptured(false), - mAudioCapturedByWindow(false), mPlayingBeforeSeek(false), mPlayingThroughTheAudioChannelBeforeSeek(false), mPausedForInactiveDocumentOrChannel(false), @@ -2098,11 +2097,6 @@ HTMLMediaElement::~HTMLMediaElement() EndSrcMediaStreamPlayback(); } - if (mCaptureStreamPort) { - mCaptureStreamPort->Destroy(); - mCaptureStreamPort = nullptr; - } - NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0, "Destroyed media element should no longer be in element table"); @@ -4481,7 +4475,8 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() (!mPaused && (HasAttr(kNameSpaceID_None, nsGkAtoms::loop) || (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && - !IsPlaybackEnded()) || + !IsPlaybackEnded() && + (!mSrcStream || HasAudio())) || mPlayingThroughTheAudioChannelBeforeSeek)); if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) { mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel; @@ -4497,7 +4492,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() if (!mAudioChannelAgent) { return; } - mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(), + mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(), static_cast(mAudioChannel), this); } @@ -4509,10 +4504,6 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() void HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) { - // Immediately check if this should go to the MSG instead of the normal - // media playback route. - WindowAudioCaptureChanged(); - // This is needed to pass nsContentUtils::IsCallerChrome(). // AudioChannel API should not called from content but it can happen that // this method has some content JS in its stack. @@ -4683,53 +4674,6 @@ HTMLMediaElement::GetTopLevelPrincipal() } #endif // MOZ_EME -NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged() -{ - MOZ_ASSERT(mAudioChannelAgent); - - if (!OwnerDoc()->GetInnerWindow()) { - return NS_OK; - } - bool captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured(); - - if (captured != mAudioCapturedByWindow) { - if (captured) { - mAudioCapturedByWindow = true; - nsCOMPtr window = - do_QueryInterface(OwnerDoc()->GetParentObject()); - uint64_t id = window->WindowID(); - MediaStreamGraph* msg = MediaStreamGraph::GetInstance(); - - if (!mPlaybackStream) { - nsRefPtr stream = CaptureStreamInternal(false, msg); - mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetStream()); - } else { - mCaptureStreamPort = msg->ConnectToCaptureStream(id, mPlaybackStream->GetStream()); - } - } else { - mAudioCapturedByWindow = false; - if (mDecoder) { - ProcessedMediaStream* ps = - mCaptureStreamPort->GetSource()->AsProcessedStream(); - MOZ_ASSERT(ps); - - for (uint32_t i = 0; i < mOutputStreams.Length(); i++) { - if (mOutputStreams[i].mStream->GetStream() == ps) { - mOutputStreams.RemoveElementAt(i); - break; - } - } - - mDecoder->RemoveOutputStream(ps); - } - mCaptureStreamPort->Destroy(); - mCaptureStreamPort = nullptr; - } - } - - return NS_OK; -} - AudioTrackList* HTMLMediaElement::AudioTracks() { diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index 406478fc507c..84f4ed0d9cd8 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -1074,9 +1074,6 @@ protected: // Holds a reference to a MediaInputPort connecting mSrcStream to mPlaybackStream. nsRefPtr mPlaybackStreamInputPort; - // Holds a reference to the stream connecting this stream to the capture sink. - nsRefPtr mCaptureStreamPort; - // Holds a reference to a stream with mSrcStream as input but intended for // playback. Used so we don't block playback of other video elements // playing the same mSrcStream. @@ -1286,9 +1283,6 @@ protected: // True if the sound is being captured. bool mAudioCaptured; - // True if the sound is being captured by the window. - bool mAudioCapturedByWindow; - // If TRUE then the media element was actively playing before the currently // in progress seeking. If FALSE then the media element is either not seeking // or was not actively playing before the current seek. Used to decide whether diff --git a/dom/media/AudioCaptureStream.cpp b/dom/media/AudioCaptureStream.cpp deleted file mode 100644 index f22050328958..000000000000 --- a/dom/media/AudioCaptureStream.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MediaStreamGraphImpl.h" -#include "mozilla/MathAlgorithms.h" -#include "mozilla/unused.h" - -#include "AudioSegment.h" -#include "mozilla/Logging.h" -#include "mozilla/Attributes.h" -#include "AudioCaptureStream.h" -#include "ImageContainer.h" -#include "AudioNodeEngine.h" -#include "AudioNodeStream.h" -#include "AudioNodeExternalInputStream.h" -#include "webaudio/MediaStreamAudioDestinationNode.h" -#include -#include "DOMMediaStream.h" - -using namespace mozilla::layers; -using namespace mozilla::dom; -using namespace mozilla::gfx; - -namespace mozilla -{ - -// We are mixing to mono until PeerConnection can accept stereo -static const uint32_t MONO = 1; - -AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper) - : ProcessedMediaStream(aWrapper), mTrackCreated(false) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_COUNT_CTOR(AudioCaptureStream); - mMixer.AddCallback(this); -} - -AudioCaptureStream::~AudioCaptureStream() -{ - MOZ_COUNT_DTOR(AudioCaptureStream); - mMixer.RemoveCallback(this); -} - -void -AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, - uint32_t aFlags) -{ - uint32_t inputCount = mInputs.Length(); - StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); - // Notify the DOM everything is in order. - if (!mTrackCreated) { - for (uint32_t i = 0; i < mListeners.Length(); i++) { - MediaStreamListener* l = mListeners[i]; - AudioSegment tmp; - l->NotifyQueuedTrackChanges( - Graph(), AUDIO_TRACK, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp); - l->NotifyFinishedTrackCreation(Graph()); - } - mTrackCreated = true; - } - - // If the captured stream is connected back to a object on the page (be it an - // HTMLMediaElement with a stream as source, or an AudioContext), a cycle - // situation occur. This can work if it's an AudioContext with at least one - // DelayNode, but the MSG will mute the whole cycle otherwise. - bool blocked = mFinished || mBlocked.GetAt(aFrom); - if (blocked || InMutedCycle() || inputCount == 0) { - track->Get()->AppendNullData(aTo - aFrom); - } else { - // We mix down all the tracks of all inputs, to a stereo track. Everything - // is {up,down}-mixed to stereo. - mMixer.StartMixing(); - AudioSegment output; - for (uint32_t i = 0; i < inputCount; i++) { - MediaStream* s = mInputs[i]->GetSource(); - StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO); - while (!tracks.IsEnded()) { - AudioSegment* inputSegment = tracks->Get(); - StreamTime inputStart = s->GraphTimeToStreamTime(aFrom); - StreamTime inputEnd = s->GraphTimeToStreamTime(aTo); - AudioSegment toMix; - toMix.AppendSlice(*inputSegment, inputStart, inputEnd); - // Care for streams blocked in the [aTo, aFrom] range. - if (inputEnd - inputStart < aTo - aFrom) { - toMix.AppendNullData((aTo - aFrom) - (inputEnd - inputStart)); - } - toMix.Mix(mMixer, MONO, Graph()->GraphRate()); - tracks.Next(); - } - } - // This calls MixerCallback below - mMixer.FinishMixing(); - } - - // Regardless of the status of the input tracks, we go foward. - mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime((aTo))); -} - -void -AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer, - AudioSampleFormat aFormat, uint32_t aChannels, - uint32_t aFrames, uint32_t aSampleRate) -{ - nsAutoTArray, MONO> output; - nsAutoTArray bufferPtrs; - output.SetLength(MONO); - bufferPtrs.SetLength(MONO); - - uint32_t written = 0; - // We need to copy here, because the mixer will reuse the storage, we should - // not hold onto it. Buffers are in planar format. - for (uint32_t channel = 0; channel < aChannels; channel++) { - AudioDataValue* out = output[channel].AppendElements(aFrames); - PodCopy(out, aMixedBuffer + written, aFrames); - bufferPtrs[channel] = out; - written += aFrames; - } - AudioChunk chunk; - chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(&output); - chunk.mDuration = aFrames; - chunk.mBufferFormat = aFormat; - chunk.mVolume = 1.0f; - chunk.mChannelData.SetLength(MONO); - for (uint32_t channel = 0; channel < aChannels; channel++) { - chunk.mChannelData[channel] = bufferPtrs[channel]; - } - - // Now we have mixed data, simply append it to out track. - EnsureTrack(AUDIO_TRACK)->Get()->AppendAndConsumeChunk(&chunk); -} -} diff --git a/dom/media/AudioCaptureStream.cpp.rej b/dom/media/AudioCaptureStream.cpp.rej deleted file mode 100644 index 5a0dcd271be8..000000000000 --- a/dom/media/AudioCaptureStream.cpp.rej +++ /dev/null @@ -1,133 +0,0 @@ -+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -+/* This Source Code Form is subject to the terms of the Mozilla Public -+ * License, v. 2.0. If a copy of the MPL was not distributed with this file, -+ * You can obtain one at http://mozilla.org/MPL/2.0/. */ -+ -+#include "MediaStreamGraphImpl.h" -+#include "mozilla/MathAlgorithms.h" -+#include "mozilla/unused.h" -+ -+#include "AudioSegment.h" -+#include "mozilla/Logging.h" -+#include "mozilla/Attributes.h" -+#include "AudioCaptureStream.h" -+#include "ImageContainer.h" -+#include "AudioNodeEngine.h" -+#include "AudioNodeStream.h" -+#include "AudioNodeExternalInputStream.h" -+#include "webaudio/MediaStreamAudioDestinationNode.h" -+#include -+#include "DOMMediaStream.h" -+ -+using namespace mozilla::layers; -+using namespace mozilla::dom; -+using namespace mozilla::gfx; -+ -+namespace mozilla -+{ -+ -+// We are mixing to mono until PeerConnection can accept stereo -+static const uint32_t MONO = 1; -+ -+AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper) -+ : ProcessedMediaStream(aWrapper), mTrackCreated(false) -+{ -+ MOZ_ASSERT(NS_IsMainThread()); -+ MOZ_COUNT_CTOR(AudioCaptureStream); -+ mMixer.AddCallback(this); -+} -+ -+AudioCaptureStream::~AudioCaptureStream() -+{ -+ MOZ_COUNT_DTOR(AudioCaptureStream); -+ mMixer.RemoveCallback(this); -+} -+ -+void -+AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, -+ uint32_t aFlags) -+{ -+ uint32_t inputCount = mInputs.Length(); -+ StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); -+ // Notify the DOM everything is in order. -+ if (!mTrackCreated) { -+ for (uint32_t i = 0; i < mListeners.Length(); i++) { -+ MediaStreamListener* l = mListeners[i]; -+ AudioSegment tmp; -+ l->NotifyQueuedTrackChanges( -+ Graph(), AUDIO_TRACK, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp); -+ l->NotifyFinishedTrackCreation(Graph()); -+ } -+ mTrackCreated = true; -+ } -+ -+ // If the captured stream is connected back to a object on the page (be it an -+ // HTMLMediaElement with a stream as source, or an AudioContext), a cycle -+ // situation occur. This can work if it's an AudioContext with at least one -+ // DelayNode, but the MSG will mute the whole cycle otherwise. -+ bool blocked = mFinished || mBlocked.GetAt(aFrom); -+ if (blocked || InMutedCycle() || inputCount == 0) { -+ track->Get()->AppendNullData(aTo - aFrom); -+ } else { -+ // We mix down all the tracks of all inputs, to a stereo track. Everything -+ // is {up,down}-mixed to stereo. -+ mMixer.StartMixing(); -+ AudioSegment output; -+ for (uint32_t i = 0; i < inputCount; i++) { -+ MediaStream* s = mInputs[i]->GetSource(); -+ StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO); -+ while (!tracks.IsEnded()) { -+ AudioSegment* inputSegment = tracks->Get(); -+ StreamTime inputStart = s->GraphTimeToStreamTime(aFrom); -+ StreamTime inputEnd = s->GraphTimeToStreamTime(aTo); -+ AudioSegment toMix; -+ toMix.AppendSlice(*inputSegment, inputStart, inputEnd); -+ // Care for streams blocked in the [aTo, aFrom] range. -+ if (inputEnd - inputStart < aTo - aFrom) { -+ toMix.AppendNullData((aTo - aFrom) - (inputEnd - inputStart)); -+ } -+ toMix.Mix(mMixer, MONO, Graph()->GraphRate()); -+ tracks.Next(); -+ } -+ } -+ // This calls MixerCallback below -+ mMixer.FinishMixing(); -+ } -+ -+ // Regardless of the status of the input tracks, we go foward. -+ mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime((aTo))); -+} -+ -+void -+AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer, -+ AudioSampleFormat aFormat, uint32_t aChannels, -+ uint32_t aFrames, uint32_t aSampleRate) -+{ -+ nsAutoTArray, MONO> output; -+ nsAutoTArray bufferPtrs; -+ output.SetLength(MONO); -+ bufferPtrs.SetLength(MONO); -+ -+ uint32_t written = 0; -+ // We need to copy here, because the mixer will reuse the storage, we should -+ // not hold onto it. Buffers are in planar format. -+ for (uint32_t channel = 0; channel < aChannels; channel++) { -+ float* out = output[channel].AppendElements(aFrames); -+ PodCopy(out, aMixedBuffer + written, aFrames); -+ bufferPtrs[channel] = out; -+ written += aFrames; -+ } -+ AudioChunk chunk; -+ chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(&output); -+ chunk.mDuration = aFrames; -+ chunk.mBufferFormat = AUDIO_FORMAT_FLOAT32; -+ chunk.mVolume = 1.0f; -+ chunk.mChannelData.SetLength(MONO); -+ for (uint32_t channel = 0; channel < aChannels; channel++) { -+ chunk.mChannelData[channel] = bufferPtrs[channel]; -+ } -+ -+ // Now we have mixed data, simply append it to out track. -+ EnsureTrack(AUDIO_TRACK)->Get()->AppendAndConsumeChunk(&chunk); -+} -+} diff --git a/dom/media/AudioCaptureStream.h.rej b/dom/media/AudioCaptureStream.h.rej deleted file mode 100644 index 3c05c50e8525..000000000000 --- a/dom/media/AudioCaptureStream.h.rej +++ /dev/null @@ -1,43 +0,0 @@ ---- AudioCaptureStream.h -+++ AudioCaptureStream.h -@@ -0,0 +1,40 @@ -+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ -+/* This Source Code Form is subject to the terms of the Mozilla Public -+ * License, v. 2.0. If a copy of the MPL was not distributed with this file, -+ * You can obtain one at http://mozilla.org/MPL/2.0/. */ -+ -+#ifndef MOZILLA_AUDIOCAPTURESTREAM_H_ -+#define MOZILLA_AUDIOCAPTURESTREAM_H_ -+ -+#include "MediaStreamGraph.h" -+#include "AudioMixer.h" -+#include -+ -+namespace mozilla -+{ -+ -+class DOMMediaStream; -+ -+/** -+ * See MediaStreamGraph::CreateAudioCaptureStream. -+ */ -+class AudioCaptureStream : public ProcessedMediaStream, -+ public MixerCallbackReceiver -+{ -+public: -+ explicit AudioCaptureStream(DOMMediaStream* aWrapper); -+ virtual ~AudioCaptureStream(); -+ -+ void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override; -+ -+protected: -+ enum { AUDIO_TRACK = 1 }; -+ void MixerCallback(AudioDataValue* aMixedBuffer, AudioSampleFormat aFormat, -+ uint32_t aChannels, uint32_t aFrames, -+ uint32_t aSampleRate) override; -+ AudioMixer mMixer; -+ bool mTrackCreated; -+}; -+} -+ -+#endif /* MOZILLA_AUDIOCAPTURESTREAM_H_ */ diff --git a/dom/media/AudioChannelFormat.cpp b/dom/media/AudioChannelFormat.cpp index 1a1ce9d61ac7..a447b1dd5d73 100644 --- a/dom/media/AudioChannelFormat.cpp +++ b/dom/media/AudioChannelFormat.cpp @@ -4,11 +4,26 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AudioChannelFormat.h" +#include "nsTArray.h" #include namespace mozilla { +enum { + SURROUND_L, + SURROUND_R, + SURROUND_C, + SURROUND_LFE, + SURROUND_SL, + SURROUND_SR +}; + +static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6; + +static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS; +static const float IGNORE_F = 0.0f; + uint32_t GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2) { @@ -48,6 +63,9 @@ gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = { { 0, 1, 2, 3, 4, IGNORE } } }; +static const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] = + { 0, 5, 9, 12, 14 }; + void AudioChannelsUpMix(nsTArray* aChannelArray, uint32_t aOutputChannelCount, @@ -58,8 +76,8 @@ AudioChannelsUpMix(nsTArray* aChannelArray, GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount); NS_ASSERTION(outputChannelCount > inputChannelCount, "No up-mix needed"); - MOZ_ASSERT(inputChannelCount > 0, "Bad number of channels"); - MOZ_ASSERT(outputChannelCount > 0, "Bad number of channels"); + NS_ASSERTION(inputChannelCount > 0, "Bad number of channels"); + NS_ASSERTION(outputChannelCount > 0, "Bad number of channels"); aChannelArray->SetLength(outputChannelCount); @@ -90,4 +108,94 @@ AudioChannelsUpMix(nsTArray* aChannelArray, } } +/** + * DownMixMatrix represents a conversion matrix efficiently by exploiting the + * fact that each input channel contributes to at most one output channel, + * except possibly for the C input channel in layouts that have one. Also, + * every input channel is multiplied by the same coefficient for every output + * channel it contributes to. + */ +struct DownMixMatrix { + // Every input channel c is copied to output channel mInputDestination[c] + // after multiplying by mInputCoefficient[c]. + uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; + // If not IGNORE, then the C channel is copied to this output channel after + // multiplying by its coefficient. + uint8_t mCExtraDestination; + float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS]; +}; + +static const DownMixMatrix +gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = +{ + // Downmixes to mono + { { 0, 0 }, IGNORE, { 0.5f, 0.5f } }, + { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } }, + { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } }, + { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } }, + { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } }, + // Downmixes to stereo + { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } }, + { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, + { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } }, + // Downmixes to 3-channel + { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } }, + { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, + // Downmixes to quad + { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }, + { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } }, + // Downmixes to 5-channel + { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } } +}; + +void +AudioChannelsDownMix(const nsTArray& aChannelArray, + float** aOutputChannels, + uint32_t aOutputChannelCount, + uint32_t aDuration) +{ + uint32_t inputChannelCount = aChannelArray.Length(); + const void* const* inputChannels = aChannelArray.Elements(); + NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do"); + + if (inputChannelCount > 6) { + // Just drop the unknown channels. + for (uint32_t o = 0; o < aOutputChannelCount; ++o) { + memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float)); + } + return; + } + + // Ignore unknown channels, they're just dropped. + inputChannelCount = std::min(6, inputChannelCount); + + const DownMixMatrix& m = gDownMixMatrices[ + gMixingMatrixIndexByChannels[aOutputChannelCount - 1] + + inputChannelCount - aOutputChannelCount - 1]; + + // This is slow, but general. We can define custom code for special + // cases later. + for (uint32_t s = 0; s < aDuration; ++s) { + // Reserve an extra junk channel at the end for the cases where we + // want an input channel to contribute to nothing + float outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1]; + memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS)); + for (uint32_t c = 0; c < inputChannelCount; ++c) { + outputChannels[m.mInputDestination[c]] += + m.mInputCoefficient[c]*(static_cast(inputChannels[c]))[s]; + } + // Utilize the fact that in every layout, C is the third channel. + if (m.mCExtraDestination != IGNORE) { + outputChannels[m.mCExtraDestination] += + m.mInputCoefficient[SURROUND_C]*(static_cast(inputChannels[SURROUND_C]))[s]; + } + + for (uint32_t c = 0; c < aOutputChannelCount; ++c) { + aOutputChannels[c][s] = outputChannels[c]; + } + } +} + } // namespace mozilla diff --git a/dom/media/AudioChannelFormat.h b/dom/media/AudioChannelFormat.h index d5aef21c5668..99a201456aa5 100644 --- a/dom/media/AudioChannelFormat.h +++ b/dom/media/AudioChannelFormat.h @@ -9,8 +9,6 @@ #include #include "nsTArrayForwardDeclare.h" -#include "AudioSampleFormat.h" -#include "nsTArray.h" namespace mozilla { @@ -31,26 +29,6 @@ namespace mozilla { * Only 1, 2, 4 and 6 are currently defined in Web Audio. */ -enum { - SURROUND_L, - SURROUND_R, - SURROUND_C, - SURROUND_LFE, - SURROUND_SL, - SURROUND_SR -}; - -const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6; - -// This is defined by some Windows SDK header. -#undef IGNORE - -const int IGNORE = CUSTOM_CHANNEL_LAYOUTS; -const float IGNORE_F = 0.0f; - -const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] = - { 0, 5, 9, 12, 14 }; - /** * Return a channel count whose channel layout includes all the channels from * aChannels1 and aChannels2. @@ -75,102 +53,19 @@ AudioChannelsUpMix(nsTArray* aChannelArray, uint32_t aOutputChannelCount, const void* aZeroChannel); - /** - * DownMixMatrix represents a conversion matrix efficiently by exploiting the - * fact that each input channel contributes to at most one output channel, - * except possibly for the C input channel in layouts that have one. Also, - * every input channel is multiplied by the same coefficient for every output - * channel it contributes to. + * Given an array of input channels (which must be float format!), + * downmix to aOutputChannelCount, and copy the results to the + * channel buffers in aOutputChannels. + * Don't call this with input count <= output count. */ -struct DownMixMatrix { - // Every input channel c is copied to output channel mInputDestination[c] - // after multiplying by mInputCoefficient[c]. - uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; - // If not IGNORE, then the C channel is copied to this output channel after - // multiplying by its coefficient. - uint8_t mCExtraDestination; - float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS]; -}; - -static const DownMixMatrix -gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = -{ - // Downmixes to mono - { { 0, 0 }, IGNORE, { 0.5f, 0.5f } }, - { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } }, - { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } }, - { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } }, - { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } }, - // Downmixes to stereo - { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } }, - { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, - { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } }, - // Downmixes to 3-channel - { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } }, - { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, - // Downmixes to quad - { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }, - { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } }, - // Downmixes to 5-channel - { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } } -}; - -/** - * Given an array of input channels, downmix to aOutputChannelCount, and copy - * the results to the channel buffers in aOutputChannels. Don't call this with - * input count <= output count. - */ -template -void AudioChannelsDownMix(const nsTArray& aChannelArray, - T** aOutputChannels, +void +AudioChannelsDownMix(const nsTArray& aChannelArray, + float** aOutputChannels, uint32_t aOutputChannelCount, - uint32_t aDuration) -{ - uint32_t inputChannelCount = aChannelArray.Length(); - const void* const* inputChannels = aChannelArray.Elements(); - NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do"); - - if (inputChannelCount > 6) { - // Just drop the unknown channels. - for (uint32_t o = 0; o < aOutputChannelCount; ++o) { - memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(T)); - } - return; - } - - // Ignore unknown channels, they're just dropped. - inputChannelCount = std::min(6, inputChannelCount); - - const DownMixMatrix& m = gDownMixMatrices[ - gMixingMatrixIndexByChannels[aOutputChannelCount - 1] + - inputChannelCount - aOutputChannelCount - 1]; - - // This is slow, but general. We can define custom code for special - // cases later. - for (uint32_t s = 0; s < aDuration; ++s) { - // Reserve an extra junk channel at the end for the cases where we - // want an input channel to contribute to nothing - T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1]; - memset(outputChannels, 0, sizeof(T)*(CUSTOM_CHANNEL_LAYOUTS)); - for (uint32_t c = 0; c < inputChannelCount; ++c) { - outputChannels[m.mInputDestination[c]] += - m.mInputCoefficient[c]*(static_cast(inputChannels[c]))[s]; - } - // Utilize the fact that in every layout, C is the third channel. - if (m.mCExtraDestination != IGNORE) { - outputChannels[m.mCExtraDestination] += - m.mInputCoefficient[SURROUND_C]*(static_cast(inputChannels[SURROUND_C]))[s]; - } - - for (uint32_t c = 0; c < aOutputChannelCount; ++c) { - aOutputChannels[c][s] = outputChannels[c]; - } - } -} + uint32_t aDuration); +// A version of AudioChannelsDownMix that downmixes int16_ts may be required. } // namespace mozilla diff --git a/dom/media/AudioMixer.h b/dom/media/AudioMixer.h index c86aa33455b3..c992942e25f9 100644 --- a/dom/media/AudioMixer.h +++ b/dom/media/AudioMixer.h @@ -26,9 +26,7 @@ struct MixerCallbackReceiver { * stream. * * AudioMixer::Mix is to be called repeatedly with buffers that have the same - * length, sample rate, sample format and channel count. This class works with - * interleaved and plannar buffers, but the buffer mixed must be of the same - * type during a mixing cycle. + * length, sample rate, sample format and channel count. * * When all the tracks have been mixed, calling FinishMixing will call back with * a buffer containing the mixed audio data. @@ -73,7 +71,7 @@ public: mSampleRate = mChannels = mFrames = 0; } - /* Add a buffer to the mix. */ + /* Add a buffer to the mix. aSamples is interleaved. */ void Mix(AudioDataValue* aSamples, uint32_t aChannels, uint32_t aFrames, diff --git a/dom/media/AudioSegment.cpp b/dom/media/AudioSegment.cpp index c4162842d360..ddd16bbe16a5 100644 --- a/dom/media/AudioSegment.cpp +++ b/dom/media/AudioSegment.cpp @@ -146,103 +146,6 @@ void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler, uint32_t aInR } } -// This helps to to safely get a pointer to the position we want to start -// writing a planar audio buffer, depending on the channel and the offset in the -// buffer. -static AudioDataValue* -PointerForOffsetInChannel(AudioDataValue* aData, size_t aLengthSamples, - uint32_t aChannelCount, uint32_t aChannel, - uint32_t aOffsetSamples) -{ - size_t samplesPerChannel = aLengthSamples / aChannelCount; - size_t beginningOfChannel = samplesPerChannel * aChannel; - MOZ_ASSERT(aChannel * samplesPerChannel + aOffsetSamples < aLengthSamples, - "Offset request out of bounds."); - return aData + beginningOfChannel + aOffsetSamples; -} - -void -AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels, - uint32_t aSampleRate) -{ - nsAutoTArray - buf; - nsAutoTArray channelData; - uint32_t offsetSamples = 0; - uint32_t duration = GetDuration(); - - if (duration <= 0) { - MOZ_ASSERT(duration == 0); - return; - } - - uint32_t outBufferLength = duration * aOutputChannels; - buf.SetLength(outBufferLength); - - for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) { - AudioChunk& c = *ci; - uint32_t frames = c.mDuration; - - // If the chunk is silent, simply write the right number of silence in the - // buffers. - if (c.mBufferFormat == AUDIO_FORMAT_SILENCE) { - for (uint32_t channel = 0; channel < aOutputChannels; channel++) { - AudioDataValue* ptr = - PointerForOffsetInChannel(buf.Elements(), outBufferLength, - aOutputChannels, channel, offsetSamples); - PodZero(ptr, frames); - } - } else { - // Othewise, we need to upmix or downmix appropriately, depending on the - // desired input and output channels. - channelData.SetLength(c.mChannelData.Length()); - for (uint32_t i = 0; i < channelData.Length(); ++i) { - channelData[i] = c.mChannelData[i]; - } - if (channelData.Length() < aOutputChannels) { - // Up-mix. - AudioChannelsUpMix(&channelData, aOutputChannels, gZeroChannel); - for (uint32_t channel = 0; channel < aOutputChannels; channel++) { - AudioDataValue* ptr = - PointerForOffsetInChannel(buf.Elements(), outBufferLength, - aOutputChannels, channel, offsetSamples); - PodCopy(ptr, reinterpret_cast(channelData[channel]), - frames); - } - MOZ_ASSERT(channelData.Length() == aOutputChannels); - } else if (channelData.Length() > aOutputChannels) { - // Down mix. - nsAutoTArray outChannelPtrs; - outChannelPtrs.SetLength(aOutputChannels); - uint32_t offsetSamples = 0; - for (uint32_t channel = 0; channel < aOutputChannels; channel++) { - outChannelPtrs[channel] = - PointerForOffsetInChannel(buf.Elements(), outBufferLength, - aOutputChannels, channel, offsetSamples); - } - AudioChannelsDownMix(channelData, outChannelPtrs.Elements(), - aOutputChannels, frames); - } else { - // The channel count is already what we want, just copy it over. - for (uint32_t channel = 0; channel < aOutputChannels; channel++) { - AudioDataValue* ptr = - PointerForOffsetInChannel(buf.Elements(), outBufferLength, - aOutputChannels, channel, offsetSamples); - PodCopy(ptr, reinterpret_cast(channelData[channel]), - frames); - } - } - } - offsetSamples += frames; - } - - if (offsetSamples) { - MOZ_ASSERT(offsetSamples == outBufferLength / aOutputChannels, - "We forgot to write some samples?"); - aMixer.Mix(buf.Elements(), aOutputChannels, offsetSamples, aSampleRate); - } -} - void AudioSegment::WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aOutputChannels, uint32_t aSampleRate) { diff --git a/dom/media/AudioSegment.h b/dom/media/AudioSegment.h index 25c0057f1b7f..22bad4e7790a 100644 --- a/dom/media/AudioSegment.h +++ b/dom/media/AudioSegment.h @@ -299,14 +299,7 @@ public: return chunk; } void ApplyVolume(float aVolume); - // Mix the segment into a mixer, interleaved. This is useful to output a - // segment to a system audio callback. It up or down mixes to aChannelCount - // channels. - void WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aChannelCount, - uint32_t aSampleRate); - // Mix the segment into a mixer, keeping it planar, up or down mixing to - // aChannelCount channels. - void Mix(AudioMixer& aMixer, uint32_t aChannelCount, uint32_t aSampleRate); + void WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aChannelCount, uint32_t aSampleRate); int ChannelCount() { NS_WARN_IF_FALSE(!mChunks.IsEmpty(), diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index e75d5fbfad02..40bdee8bd364 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -301,18 +301,6 @@ DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, InitStreamCommon(aGraph->CreateTrackUnionStream(this)); } -void -DOMMediaStream::InitAudioCaptureStream(nsIDOMWindow* aWindow, - MediaStreamGraph* aGraph) -{ - mWindow = aWindow; - - if (!aGraph) { - aGraph = MediaStreamGraph::GetInstance(); - } - InitStreamCommon(aGraph->CreateAudioCaptureStream(this)); -} - void DOMMediaStream::InitStreamCommon(MediaStream* aStream) { @@ -341,15 +329,6 @@ DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, return stream.forget(); } -already_AddRefed -DOMMediaStream::CreateAudioCaptureStream(nsIDOMWindow* aWindow, - MediaStreamGraph* aGraph) -{ - nsRefPtr stream = new DOMMediaStream(); - stream->InitAudioCaptureStream(aWindow, aGraph); - return stream.forget(); -} - void DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled) { @@ -674,15 +653,6 @@ DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, return stream.forget(); } -already_AddRefed -DOMLocalMediaStream::CreateAudioCaptureStream(nsIDOMWindow* aWindow, - MediaStreamGraph* aGraph) -{ - nsRefPtr stream = new DOMLocalMediaStream(); - stream->InitAudioCaptureStream(aWindow, aGraph); - return stream.forget(); -} - DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(AudioNode* aNode) : mStreamNode(aNode) { diff --git a/dom/media/DOMMediaStream.h b/dom/media/DOMMediaStream.h index fb7bac8733b4..ebad4e70afbc 100644 --- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -198,13 +198,6 @@ public: static already_AddRefed CreateTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); - /** - * Create an nsDOMMediaStream whose underlying stream is an - * AudioCaptureStream - */ - static already_AddRefed CreateAudioCaptureStream( - nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); - void SetLogicalStreamStartTime(StreamTime aTime) { mLogicalStreamStartTime = aTime; @@ -268,8 +261,6 @@ protected: MediaStreamGraph* aGraph = nullptr); void InitTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); - void InitAudioCaptureStream(nsIDOMWindow* aWindow, - MediaStreamGraph* aGraph = nullptr); void InitStreamCommon(MediaStream* aStream); already_AddRefed CreateAudioTrack(AudioStreamTrack* aStreamTrack); already_AddRefed CreateVideoTrack(VideoStreamTrack* aStreamTrack); @@ -360,12 +351,6 @@ public: CreateTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); - /** - * Create an nsDOMLocalMediaStream whose underlying stream is an - * AudioCaptureStream. */ - static already_AddRefed CreateAudioCaptureStream( - nsIDOMWindow* aWindow, MediaStreamGraph* aGraph = nullptr); - protected: virtual ~DOMLocalMediaStream(); }; diff --git a/dom/media/DecodedStream.cpp b/dom/media/DecodedStream.cpp index 913f68203e21..dcc950228f72 100644 --- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -289,14 +289,6 @@ DecodedStream::OutputStreams() return mOutputStreams; } -bool -DecodedStream::HasConsumers() const -{ - MOZ_ASSERT(NS_IsMainThread()); - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - return mOutputStreams.IsEmpty(); -} - ReentrantMonitor& DecodedStream::GetReentrantMonitor() const { diff --git a/dom/media/DecodedStream.h b/dom/media/DecodedStream.h index ebad8330c865..8b25b95c9f7d 100644 --- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -114,7 +114,6 @@ public: int64_t AudioEndTime() const; int64_t GetPosition() const; bool IsFinished() const; - bool HasConsumers() const; // Return true if stream is finished. bool SendData(double aVolume, bool aIsSameOrigin); diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 3f0cdadc6a19..59f7e5fcc59b 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -326,13 +326,6 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream, mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded); } -void MediaDecoder::RemoveOutputStream(MediaStream* aStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load()."); - mDecoderStateMachine->RemoveOutputStream(aStream); -} - double MediaDecoder::GetDuration() { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index d216bf9c7666..c2a01bb07465 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -399,8 +399,6 @@ public: // The stream is initially blocked. The decoder is responsible for unblocking // it while it is playing back. virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); - // Remove an output stream added with AddOutputStream. - virtual void RemoveOutputStream(MediaStream* aStream); // Return the duration of the video in seconds. virtual double GetDuration(); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 9b7ab7e0e092..2ca215ca06f9 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -3177,25 +3177,6 @@ void MediaDecoderStateMachine::DispatchAudioCaptured() OwnerThread()->Dispatch(r.forget()); } -void MediaDecoderStateMachine::DispatchAudioUncaptured() -{ - nsRefPtr self = this; - nsCOMPtr r = NS_NewRunnableFunction([self] () -> void - { - MOZ_ASSERT(self->OnTaskQueue()); - ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor()); - if (self->mAudioCaptured) { - // Start again the audio sink - self->mAudioCaptured = false; - if (self->IsPlaying()) { - self->StartAudioThread(); - } - self->ScheduleStateMachine(); - } - }); - OwnerThread()->Dispatch(r.forget()); -} - void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded) { @@ -3205,16 +3186,6 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, DispatchAudioCaptured(); } -void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - DECODER_LOG("RemoveOutputStream=%p!", aStream); - mDecodedStream->Remove(aStream); - if (!mDecodedStream->HasConsumers()) { - DispatchAudioUncaptured(); - } -} - } // namespace mozilla // avoid redefined macro in unified build diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 8670d0569baa..ea485d4e9d08 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -149,8 +149,6 @@ public: }; void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); - // Remove an output stream added with AddOutputStream. - void RemoveOutputStream(MediaStream* aStream); // Set/Unset dormant state. void SetDormant(bool aDormant); @@ -162,7 +160,6 @@ private: void InitializationTask(); void DispatchAudioCaptured(); - void DispatchAudioUncaptured(); void Shutdown(); public: diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 5b9d252f6a6a..7af74e55c71a 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -300,8 +300,7 @@ protected: NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice) MediaDevice::MediaDevice(MediaEngineSource* aSource, bool aIsVideo) - : mMediaSource(aSource->GetMediaSource()) - , mSource(aSource) + : mSource(aSource) , mIsVideo(aIsVideo) { mSource->GetName(mName); @@ -312,7 +311,9 @@ MediaDevice::MediaDevice(MediaEngineSource* aSource, bool aIsVideo) VideoDevice::VideoDevice(MediaEngineVideoSource* aSource) : MediaDevice(aSource, true) -{} +{ + mMediaSource = aSource->GetMediaSource(); +} /** * Helper functions that implement the constraints algorithm from @@ -438,8 +439,6 @@ MediaDevice::GetMediaSource(nsAString& aMediaSource) { if (mMediaSource == dom::MediaSourceEnum::Microphone) { aMediaSource.Assign(NS_LITERAL_STRING("microphone")); - } else if (mMediaSource == dom::MediaSourceEnum::AudioCapture) { - aMediaSource.Assign(NS_LITERAL_STRING("audioCapture")); } else if (mMediaSource == dom::MediaSourceEnum::Window) { // this will go away aMediaSource.Assign(NS_LITERAL_STRING("window")); } else { // all the rest are shared @@ -785,55 +784,11 @@ public: } } #endif - - MediaStreamGraph* msg = MediaStreamGraph::GetInstance(); - nsRefPtr stream = msg->CreateSourceStream(nullptr); - - nsRefPtr domStream; - // AudioCapture is a special case, here, in the sense that we're not really - // using the audio source and the SourceMediaStream, which acts as - // placeholders. We re-route a number of stream internaly in the MSG and mix - // them down instead. - if (mAudioSource && - mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { - domStream = DOMLocalMediaStream::CreateAudioCaptureStream(window); - // It should be possible to pipe the capture stream to anything. CORS is - // not a problem here, we got explicit user content. - domStream->SetPrincipal(window->GetExtantDoc()->NodePrincipal()); - msg->RegisterCaptureStreamForWindow( - mWindowID, domStream->GetStream()->AsProcessedStream()); - window->SetAudioCapture(true); - } else { - // Normal case, connect the source stream to the track union stream to - // avoid us blocking - nsRefPtr trackunion = - nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, - mAudioSource, mVideoSource); - trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true); - nsRefPtr port = trackunion->GetStream()->AsProcessedStream()-> - AllocateInputPort(stream, MediaInputPort::FLAG_BLOCK_OUTPUT); - trackunion->mSourceStream = stream; - trackunion->mPort = port.forget(); - // Log the relationship between SourceMediaStream and TrackUnion stream - // Make sure logger starts before capture - AsyncLatencyLogger::Get(true); - LogLatency(AsyncLatencyLogger::MediaStreamCreate, - reinterpret_cast(stream.get()), - reinterpret_cast(trackunion->GetStream())); - - nsCOMPtr principal; - if (mPeerIdentity) { - principal = nsNullPrincipal::Create(); - trackunion->SetPeerIdentity(mPeerIdentity.forget()); - } else { - principal = window->GetExtantDoc()->NodePrincipal(); - } - trackunion->CombineWithPrincipal(principal); - - domStream = trackunion.forget(); - } - - if (!domStream || sInShutdown) { + // Create a media stream. + nsRefPtr trackunion = + nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, + mAudioSource, mVideoSource); + if (!trackunion || sInShutdown) { nsCOMPtr onFailure = mOnFailure.forget(); LOG(("Returning error for getUserMedia() - no stream")); @@ -847,6 +802,36 @@ public: } return NS_OK; } + trackunion->AudioConfig(aec_on, (uint32_t) aec, + agc_on, (uint32_t) agc, + noise_on, (uint32_t) noise, + playout_delay); + + + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + nsRefPtr stream = gm->CreateSourceStream(nullptr); + + // connect the source stream to the track union stream to avoid us blocking + trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true); + nsRefPtr port = trackunion->GetStream()->AsProcessedStream()-> + AllocateInputPort(stream, MediaInputPort::FLAG_BLOCK_OUTPUT); + trackunion->mSourceStream = stream; + trackunion->mPort = port.forget(); + // Log the relationship between SourceMediaStream and TrackUnion stream + // Make sure logger starts before capture + AsyncLatencyLogger::Get(true); + LogLatency(AsyncLatencyLogger::MediaStreamCreate, + reinterpret_cast(stream.get()), + reinterpret_cast(trackunion->GetStream())); + + nsCOMPtr principal; + if (mPeerIdentity) { + principal = nsNullPrincipal::Create(); + trackunion->SetPeerIdentity(mPeerIdentity.forget()); + } else { + principal = window->GetExtantDoc()->NodePrincipal(); + } + trackunion->CombineWithPrincipal(principal); // The listener was added at the beginning in an inactive state. // Activate our listener. We'll call Start() on the source when get a callback @@ -856,7 +841,7 @@ public: // Note: includes JS callbacks; must be released on MainThread TracksAvailableCallback* tracksAvailableCallback = - new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, domStream); + new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, trackunion); mListener->AudioConfig(aec_on, (uint32_t) aec, agc_on, (uint32_t) agc, @@ -867,11 +852,11 @@ public: // because that can take a while. // Pass ownership of trackunion to the MediaOperationTask // to ensure it's kept alive until the MediaOperationTask runs (at least). - MediaManager::PostTask( - FROM_HERE, new MediaOperationTask(MEDIA_START, mListener, domStream, - tracksAvailableCallback, mAudioSource, - mVideoSource, false, mWindowID, - mOnFailure.forget())); + MediaManager::PostTask(FROM_HERE, + new MediaOperationTask(MEDIA_START, mListener, trackunion, + tracksAvailableCallback, + mAudioSource, mVideoSource, false, mWindowID, + mOnFailure.forget())); // We won't need mOnFailure now. mOnFailure = nullptr; @@ -1260,9 +1245,7 @@ static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices; */ already_AddRefed -MediaManager::EnumerateRawDevices(uint64_t aWindowId, - MediaSourceEnum aVideoType, - MediaSourceEnum aAudioType, +MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType, bool aFake, bool aFakeTracks) { MOZ_ASSERT(NS_IsMainThread()); @@ -1292,8 +1275,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aWindowId, audioLoopDev, videoLoopDev, aVideoType, - aAudioType, aFake, - aFakeTracks]() mutable { + aFake, aFakeTracks]() mutable { nsRefPtr backend; if (aFake) { backend = new MediaEngineDefault(aFakeTracks); @@ -1312,7 +1294,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, } nsTArray> audios; - GetSources(backend, aAudioType, + GetSources(backend, dom::MediaSourceEnum::Microphone, &MediaEngine::EnumerateAudioDevices, audios, audioLoopDev); for (auto& source : audios) { result->AppendElement(source); @@ -1634,7 +1616,6 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, } MediaSourceEnum videoType = dom::MediaSourceEnum::Camera; - MediaSourceEnum audioType = dom::MediaSourceEnum::Microphone; if (c.mVideo.IsMediaTrackConstraints()) { auto& vc = c.mVideo.GetAsMediaTrackConstraints(); @@ -1723,23 +1704,6 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, privileged = false; } } - - if (c.mAudio.IsMediaTrackConstraints()) { - auto& ac = c.mAudio.GetAsMediaTrackConstraints(); - audioType = StringToEnum(dom::MediaSourceEnumValues::strings, - ac.mMediaSource, - audioType); - // Only enable AudioCapture if the pref is enabled. If it's not, we can deny - // right away. - if (audioType == dom::MediaSourceEnum::AudioCapture && - !Preferences::GetBool("media.getusermedia.audiocapture.enabled")) { - nsRefPtr error = - new MediaStreamError(aWindow, - NS_LITERAL_STRING("PermissionDeniedError")); - onFailure->OnError(error); - return NS_OK; - } - } StreamListeners* listeners = AddWindowID(windowID); // Create a disabled listener to act as a placeholder @@ -1802,8 +1766,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, (!fake || Preferences::GetBool("media.navigator.permission.fake")); nsRefPtr p = EnumerateDevicesImpl(windowID, videoType, - audioType, fake, - fakeTracks); + fake, fakeTracks); p->Then([this, onSuccess, onFailure, windowID, c, listener, askPermission, prefs, isHTTPS, callID, origin](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // grab result @@ -1959,9 +1922,7 @@ MediaManager::ToJSArray(SourceSet& aDevices) } already_AddRefed -MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, - MediaSourceEnum aVideoType, - MediaSourceEnum aAudioType, +MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, MediaSourceEnum aVideoType, bool aFake, bool aFakeTracks) { MOZ_ASSERT(NS_IsMainThread()); @@ -1990,13 +1951,12 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, nsRefPtr> p = media::GetOriginKey(origin, privateBrowsing, persist); - p->Then([id, aWindowId, aVideoType, aAudioType, + p->Then([id, aWindowId, aVideoType, aFake, aFakeTracks](const nsCString& aOriginKey) mutable { MOZ_ASSERT(NS_IsMainThread()); nsRefPtr mgr = MediaManager_GetInstance(); - nsRefPtr p = mgr->EnumerateRawDevices(aWindowId, - aVideoType, aAudioType, + nsRefPtr p = mgr->EnumerateRawDevices(aWindowId, aVideoType, aFake, aFakeTracks); p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // secondary result @@ -2035,7 +1995,6 @@ MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow, nsRefPtr p = EnumerateDevicesImpl(windowId, dom::MediaSourceEnum::Camera, - dom::MediaSourceEnum::Microphone, fake); p->Then([onSuccess](SourceSet*& aDevices) mutable { ScopedDeletePtr devices(aDevices); // grab result @@ -2116,7 +2075,7 @@ StopSharingCallback(MediaManager *aThis, listener->Invalidate(); } listener->Remove(); - listener->StopSharing(); + listener->StopScreenWindowSharing(); } aListeners->Clear(); aThis->RemoveWindowID(aWindowID); @@ -2439,7 +2398,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, uint64_t windowID = PromiseFlatString(Substring(data, strlen("screen:"))).ToInteger64(&rv); MOZ_ASSERT(NS_SUCCEEDED(rv)); if (NS_SUCCEEDED(rv)) { - LOG(("Revoking Screen/windowCapture access for window %llu", windowID)); + LOG(("Revoking Screeen/windowCapture access for window %llu", windowID)); StopScreensharing(windowID); } } else { @@ -2620,7 +2579,7 @@ StopScreensharingCallback(MediaManager *aThis, if (aListeners) { auto length = aListeners->Length(); for (size_t i = 0; i < length; ++i) { - aListeners->ElementAt(i)->StopSharing(); + aListeners->ElementAt(i)->StopScreenWindowSharing(); } } } @@ -2782,7 +2741,7 @@ GetUserMediaCallbackMediaStreamListener::Invalidate() // Doesn't kill audio // XXX refactor to combine with Invalidate()? void -GetUserMediaCallbackMediaStreamListener::StopSharing() +GetUserMediaCallbackMediaStreamListener::StopScreenWindowSharing() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); if (mVideoSource && !mStopped && @@ -2795,13 +2754,6 @@ GetUserMediaCallbackMediaStreamListener::StopSharing() this, nullptr, nullptr, nullptr, mVideoSource, mFinished, mWindowID, nullptr)); - } else if (mAudioSource && - mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { - nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); - MOZ_ASSERT(window); - window->SetAudioCapture(false); - MediaStreamGraph::GetInstance()->UnregisterCaptureStreamForWindow(mWindowID); - mStream->Destroy(); } } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index d35f4bf40ece..d7af9c5a7b99 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -103,7 +103,7 @@ public: return mStream->AsSourceStream(); } - void StopSharing(); + void StopScreenWindowSharing(); void StopTrack(TrackID aID, bool aIsAudio); @@ -597,14 +597,10 @@ public: // TODO: make private once we upgrade to GCC 4.8+ on linux. static already_AddRefed ToJSArray(SourceSet& aDevices); private: already_AddRefed - EnumerateRawDevices(uint64_t aWindowId, - dom::MediaSourceEnum aVideoType, - dom::MediaSourceEnum aAudioType, + EnumerateRawDevices(uint64_t aWindowId, dom::MediaSourceEnum aSrcType, bool aFake, bool aFakeTracks); already_AddRefed - EnumerateDevicesImpl(uint64_t aWindowId, - dom::MediaSourceEnum aVideoSrcType, - dom::MediaSourceEnum aAudioSrcType, + EnumerateDevicesImpl(uint64_t aWindowId, dom::MediaSourceEnum aSrcType, bool aFake = false, bool aFakeTracks = false); StreamListeners* AddWindowID(uint64_t aWindowId); diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index a23fba28f998..53144c054893 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -18,7 +18,6 @@ #include "mozilla/Attributes.h" #include "TrackUnionStream.h" #include "ImageContainer.h" -#include "AudioCaptureStream.h" #include "AudioChannelService.h" #include "AudioNodeEngine.h" #include "AudioNodeStream.h" @@ -3193,17 +3192,6 @@ MediaStreamGraph::CreateTrackUnionStream(DOMMediaStream* aWrapper) return stream; } -ProcessedMediaStream* -MediaStreamGraph::CreateAudioCaptureStream(DOMMediaStream* aWrapper) -{ - AudioCaptureStream* stream = new AudioCaptureStream(aWrapper); - NS_ADDREF(stream); - MediaStreamGraphImpl* graph = static_cast(this); - stream->SetGraphImpl(graph); - graph->AppendMessage(new CreateMessage(stream)); - return stream; -} - AudioNodeExternalInputStream* MediaStreamGraph::CreateAudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate) { @@ -3568,65 +3556,4 @@ ProcessedMediaStream::AddInput(MediaInputPort* aPort) GraphImpl()->SetStreamOrderDirty(); } -void -MediaStreamGraph::RegisterCaptureStreamForWindow( - uint64_t aWindowId, ProcessedMediaStream* aCaptureStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - MediaStreamGraphImpl* graphImpl = static_cast(this); - graphImpl->RegisterCaptureStreamForWindow(aWindowId, aCaptureStream); -} - -void -MediaStreamGraphImpl::RegisterCaptureStreamForWindow( - uint64_t aWindowId, ProcessedMediaStream* aCaptureStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - WindowAndStream winAndStream; - winAndStream.mWindowId = aWindowId; - winAndStream.mCaptureStreamSink = aCaptureStream; - mWindowCaptureStreams.AppendElement(winAndStream); -} - -void -MediaStreamGraph::UnregisterCaptureStreamForWindow(uint64_t aWindowId) -{ - MOZ_ASSERT(NS_IsMainThread()); - MediaStreamGraphImpl* graphImpl = static_cast(this); - graphImpl->UnregisterCaptureStreamForWindow(aWindowId); -} - -void -MediaStreamGraphImpl::UnregisterCaptureStreamForWindow(uint64_t aWindowId) -{ - MOZ_ASSERT(NS_IsMainThread()); - for (uint32_t i = 0; i < mWindowCaptureStreams.Length(); i++) { - if (mWindowCaptureStreams[i].mWindowId == aWindowId) { - mWindowCaptureStreams.RemoveElementAt(i); - } - } -} - -already_AddRefed -MediaStreamGraph::ConnectToCaptureStream(uint64_t aWindowId, - MediaStream* aMediaStream) -{ - return aMediaStream->GraphImpl()->ConnectToCaptureStream(aWindowId, - aMediaStream); -} - -already_AddRefed -MediaStreamGraphImpl::ConnectToCaptureStream(uint64_t aWindowId, - MediaStream* aMediaStream) -{ - MOZ_ASSERT(NS_IsMainThread()); - for (uint32_t i = 0; i < mWindowCaptureStreams.Length(); i++) { - if (mWindowCaptureStreams[i].mWindowId == aWindowId) { - ProcessedMediaStream* sink = mWindowCaptureStreams[i].mCaptureStreamSink; - return sink->AllocateInputPort(aMediaStream, 0); - } - } - return nullptr; -} - } // namespace mozilla diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index ac770fe1396a..312aad706052 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -1262,10 +1262,6 @@ public: * particular tracks of each input stream. */ ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper); - /** - * Create a stream that will mix all its audio input. - */ - ProcessedMediaStream* CreateAudioCaptureStream(DOMMediaStream* aWrapper); // Internal AudioNodeStreams can only pass their output to another // AudioNode, whereas external AudioNodeStreams can pass their output // to an nsAudioStream for playback. @@ -1322,12 +1318,6 @@ public: */ TrackRate GraphRate() const { return mSampleRate; } - void RegisterCaptureStreamForWindow(uint64_t aWindowId, - ProcessedMediaStream* aCaptureStream); - void UnregisterCaptureStreamForWindow(uint64_t aWindowId); - already_AddRefed ConnectToCaptureStream( - uint64_t aWindowId, MediaStream* aMediaStream); - protected: explicit MediaStreamGraph(TrackRate aSampleRate) : mNextGraphUpdateIndex(1) diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 15ded10c470c..262cae526c2e 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -532,13 +532,6 @@ public: } } - // Capture Stream API. This allows to get a mixed-down output for a window. - void RegisterCaptureStreamForWindow(uint64_t aWindowId, - ProcessedMediaStream* aCaptureStream); - void UnregisterCaptureStreamForWindow(uint64_t aWindowId); - already_AddRefed - ConnectToCaptureStream(uint64_t aWindowId, MediaStream* aMediaStream); - // Data members // /** @@ -762,16 +755,6 @@ private: * Used to pass memory report information across threads. */ nsTArray mAudioStreamSizes; - - struct WindowAndStream - { - uint64_t mWindowId; - nsRefPtr mCaptureStreamSink; - }; - /** - * Stream for window audio capture. - */ - nsTArray mWindowCaptureStreams; /** * Indicates that the MSG thread should gather data for a memory report. */ diff --git a/dom/media/moz.build b/dom/media/moz.build index 25d2dbb728d1..63c6fa3366bd 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -196,7 +196,6 @@ EXPORTS.mozilla.dom += [ UNIFIED_SOURCES += [ 'AbstractThread.cpp', - 'AudioCaptureStream.cpp', 'AudioChannelFormat.cpp', 'AudioCompactor.cpp', 'AudioSegment.cpp', diff --git a/dom/media/tests/mochitest/head.js b/dom/media/tests/mochitest/head.js index dfe4a2874806..68158f28ee59 100644 --- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -20,114 +20,6 @@ try { FAKE_ENABLED = true; } -/** - * This class provides helpers around analysing the audio content in a stream - * using WebAudio AnalyserNodes. - * - * @constructor - * @param {object} stream - * A MediaStream object whose audio track we shall analyse. - */ -function AudioStreamAnalyser(ac, stream) { - if (stream.getAudioTracks().length === 0) { - throw new Error("No audio track in stream"); - } - this.audioContext = ac; - this.stream = stream; - this.sourceNode = this.audioContext.createMediaStreamSource(this.stream); - this.analyser = this.audioContext.createAnalyser(); - this.sourceNode.connect(this.analyser); - this.data = new Uint8Array(this.analyser.frequencyBinCount); -} - -AudioStreamAnalyser.prototype = { - /** - * Get an array of frequency domain data for our stream's audio track. - * - * @returns {array} A Uint8Array containing the frequency domain data. - */ - getByteFrequencyData: function() { - this.analyser.getByteFrequencyData(this.data); - return this.data; - }, - - /** - * Append a canvas to the DOM where the frequency data are drawn. - * Useful to debug tests. - */ - enableDebugCanvas: function() { - var cvs = document.createElement("canvas"); - document.getElementById("content").appendChild(cvs); - - // Easy: 1px per bin - cvs.width = this.analyser.frequencyBinCount; - cvs.height = 256; - cvs.style.border = "1px solid red"; - - var c = cvs.getContext('2d'); - - var self = this; - function render() { - c.clearRect(0, 0, cvs.width, cvs.height); - var array = self.getByteFrequencyData(); - for (var i = 0; i < array.length; i++) { - c.fillRect(i, (256 - (array[i])), 1, 256); - } - requestAnimationFrame(render); - } - requestAnimationFrame(render); - }, - - /** - * Return a Promise, that will be resolved when the function passed as - * argument, when called, returns true (meaning the analysis was a - * success). - * - * @param {function} analysisFunction - * A fonction that performs an analysis, and returns true if the - * analysis was a success (i.e. it found what it was looking for) - */ - waitForAnalysisSuccess: function(analysisFunction) { - var self = this; - return new Promise((resolve, reject) => { - function analysisLoop() { - var success = analysisFunction(self.getByteFrequencyData()); - if (success) { - resolve(); - return; - } - // else, we need more time - requestAnimationFrame(analysisLoop); - } - analysisLoop(); - }); - }, - - /** - * Return the FFT bin index for a given frequency. - * - * @param {double} frequency - * The frequency for whicht to return the bin number. - * @returns {integer} the index of the bin in the FFT array. - */ - binIndexForFrequency: function(frequency) { - return 1 + Math.round(frequency * - this.analyser.fftSize / - this.audioContext.sampleRate); - }, - - /** - * Reverse operation, get the frequency for a bin index. - * - * @param {integer} index an index in an FFT array - * @returns {double} the frequency for this bin - */ - frequencyForBinIndex: function(index) { - return (index - 1) * - this.audioContext.sampleRate / - this.analyser.fftSize; - } -}; /** * Create the necessary HTML elements for head and body as used by Mochitests @@ -244,10 +136,7 @@ function setupEnvironment() { ['media.navigator.permission.disabled', true], ['media.navigator.streams.fake', FAKE_ENABLED], ['media.getusermedia.screensharing.enabled', true], - ['media.getusermedia.screensharing.allowed_domains', "mochi.test"], - ['media.getusermedia.audiocapture.enabled', true], - ['media.useAudioChannelService', true], - ['media.recorder.audio_node.enabled', true] + ['media.getusermedia.screensharing.allowed_domains', "mochi.test"] ] }, setTestOptions); diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini index 115d83b11f0f..9d458b0e59b8 100644 --- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -30,7 +30,6 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be to [test_dataChannel_noOffer.html] [test_enumerateDevices.html] skip-if = buildapp == 'mulet' -[test_getUserMedia_audioCapture.html] [test_getUserMedia_basicAudio.html] skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure [test_getUserMedia_basicVideo.html] diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 645f29d153e9..51aa7d17ceae 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -642,6 +642,39 @@ DataChannelWrapper.prototype = { }; +/** + * This class provides helpers around analysing the audio content in a stream + * using WebAudio AnalyserNodes. + * + * @constructor + * @param {object} stream + * A MediaStream object whose audio track we shall analyse. + */ +function AudioStreamAnalyser(stream) { + if (stream.getAudioTracks().length === 0) { + throw new Error("No audio track in stream"); + } + this.stream = stream; + this.audioContext = new AudioContext(); + this.sourceNode = this.audioContext.createMediaStreamSource(this.stream); + this.analyser = this.audioContext.createAnalyser(); + this.sourceNode.connect(this.analyser); + this.data = new Uint8Array(this.analyser.frequencyBinCount); +} + +AudioStreamAnalyser.prototype = { + /** + * Get an array of frequency domain data for our stream's audio track. + * + * @returns {array} A Uint8Array containing the frequency domain data. + */ + getByteFrequencyData: function() { + this.analyser.getByteFrequencyData(this.data); + return this.data; + } +}; + + /** * This class acts as a wrapper around a PeerConnection instance. * @@ -1526,20 +1559,20 @@ PeerConnectionWrapper.prototype = { * @returns {Promise} * A promise that resolves when we're receiving the tone from |from|. */ - checkReceivingToneFrom : function(audiocontext, from) { + checkReceivingToneFrom : function(from) { var inputElem = from.localMediaElements[0]; // As input we use the stream of |from|'s first available audio sender. var inputSenderTracks = from._pc.getSenders().map(sn => sn.track); var inputAudioStream = from._pc.getLocalStreams() .find(s => s.getAudioTracks().some(t => inputSenderTracks.some(t2 => t == t2))); - var inputAnalyser = new AudioStreamAnalyser(audiocontext, inputAudioStream); + var inputAnalyser = new AudioStreamAnalyser(inputAudioStream); // It would have been nice to have a working getReceivers() here, but until // we do, let's use what remote streams we have. var outputAudioStream = this._pc.getRemoteStreams() .find(s => s.getAudioTracks().length > 0); - var outputAnalyser = new AudioStreamAnalyser(audiocontext, outputAudioStream); + var outputAnalyser = new AudioStreamAnalyser(outputAudioStream); var maxWithIndex = (a, b, i) => (b >= a.value) ? { value: b, index: i } : a; var initial = { value: -1, index: -1 }; diff --git a/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html b/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html deleted file mode 100644 index 057d754ee292..000000000000 --- a/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - Test AudioCapture - - - -
-
-
- - diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html index 7f3a4d4bd8d0..6d6e7be029f2 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html @@ -136,7 +136,7 @@ ]); test.chain.append([ function PC_LOCAL_CHECK_WEBAUDIO_FLOW_PRESENT(test) { - return test.pcRemote.checkReceivingToneFrom(test.audioCtx, test.pcLocal); + return test.pcRemote.checkReceivingToneFrom(test.pcLocal); } ]); test.chain.append([ diff --git a/dom/media/tests/mochitest/test_peerConnection_webAudio.html b/dom/media/tests/mochitest/test_peerConnection_webAudio.html index 2a8cd31f546a..f5448cc65ae8 100644 --- a/dom/media/tests/mochitest/test_peerConnection_webAudio.html +++ b/dom/media/tests/mochitest/test_peerConnection_webAudio.html @@ -32,7 +32,7 @@ runNetworkTest(function() { ]); test.chain.append([ function CHECK_AUDIO_FLOW(test) { - return test.pcRemote.checkReceivingToneFrom(test.audioContext, test.pcLocal); + return test.pcRemote.checkReceivingToneFrom(test.pcLocal); } ]); test.run(); diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index d37145ef547a..95ab1b413459 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -313,9 +313,12 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, bool aIsOffline, AudioChannel aChannel, uint32_t aNumberOfChannels, - uint32_t aLength, float aSampleRate) - : AudioNode(aContext, aIsOffline ? aNumberOfChannels : 2, - ChannelCountMode::Explicit, ChannelInterpretation::Speakers) + uint32_t aLength, + float aSampleRate) + : AudioNode(aContext, + aIsOffline ? aNumberOfChannels : 2, + ChannelCountMode::Explicit, + ChannelInterpretation::Speakers) , mFramesToProduce(aLength) , mAudioChannel(AudioChannel::Normal) , mIsOffline(aIsOffline) @@ -323,7 +326,6 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, , mExtraCurrentTime(0) , mExtraCurrentTimeSinceLastStartedBlocking(0) , mExtraCurrentTimeUpdatedSinceLastStableState(false) - , mCaptured(false) { bool startWithAudioDriver = true; MediaStreamGraph* graph = aIsOffline ? @@ -503,33 +505,6 @@ AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } -NS_IMETHODIMP -AudioDestinationNode::WindowAudioCaptureChanged() -{ - MOZ_ASSERT(mAudioChannelAgent); - - if (!mStream || Context()->IsOffline()) { - return NS_OK; - } - - bool captured = GetOwner()->GetAudioCaptured(); - - if (captured != mCaptured) { - if (captured) { - nsCOMPtr window = Context()->GetParentObject(); - uint64_t id = window->WindowID(); - mCaptureStreamPort = - mStream->Graph()->ConnectToCaptureStream(id, mStream); - } else { - mCaptureStreamPort->Disconnect(); - mCaptureStreamPort->Destroy(); - } - mCaptured = captured; - } - - return NS_OK; -} - AudioChannel AudioDestinationNode::MozAudioChannelType() const { @@ -616,8 +591,6 @@ AudioDestinationNode::CreateAudioChannelAgent() // The AudioChannelAgent must start playing immediately in order to avoid // race conditions with mozinterruptbegin/end events. InputMuted(false); - - WindowAudioCaptureChanged(); } void @@ -709,7 +682,6 @@ AudioDestinationNode::InputMuted(bool aMuted) return; } - WindowAudioCaptureChanged(); WindowVolumeChanged(volume, muted); } diff --git a/dom/media/webaudio/AudioDestinationNode.h b/dom/media/webaudio/AudioDestinationNode.h index 724e44d61d3c..db5418a9cb51 100644 --- a/dom/media/webaudio/AudioDestinationNode.h +++ b/dom/media/webaudio/AudioDestinationNode.h @@ -99,7 +99,6 @@ private: uint32_t mFramesToProduce; nsCOMPtr mAudioChannelAgent; - nsRefPtr mCaptureStreamPort; nsRefPtr mOfflineRenderingPromise; @@ -112,7 +111,6 @@ private: double mExtraCurrentTime; double mExtraCurrentTimeSinceLastStartedBlocking; bool mExtraCurrentTimeUpdatedSinceLastStableState; - bool mCaptured; }; } // namespace dom diff --git a/dom/media/webrtc/MediaEngineWebRTC.cpp b/dom/media/webrtc/MediaEngineWebRTC.cpp index 207e97acb33e..8771ef79af7c 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.cpp +++ b/dom/media/webrtc/MediaEngineWebRTC.cpp @@ -291,13 +291,6 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource, // We spawn threads to handle gUM runnables, so we must protect the member vars MutexAutoLock lock(mMutex); - if (aMediaSource == dom::MediaSourceEnum::AudioCapture) { - nsRefPtr audioCaptureSource = - new MediaEngineWebRTCAudioCaptureSource(nullptr); - aASources->AppendElement(audioCaptureSource); - return; - } - #ifdef MOZ_WIDGET_ANDROID jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef(); @@ -365,14 +358,15 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource, strcpy(uniqueId,deviceName); // safe given assert and initialization/error-check } - nsRefPtr aSource; + nsRefPtr aSource; NS_ConvertUTF8toUTF16 uuid(uniqueId); if (mAudioSources.Get(uuid, getter_AddRefs(aSource))) { // We've already seen this device, just append. aASources->AppendElement(aSource.get()); } else { - aSource = new MediaEngineWebRTCMicrophoneSource(mThread, mVoiceEngine, i, - deviceName, uniqueId); + aSource = new MediaEngineWebRTCAudioSource( + mThread, mVoiceEngine, i, deviceName, uniqueId + ); mAudioSources.Put(uuid, aSource); // Hashtable takes ownership. aASources->AppendElement(aSource); } @@ -391,8 +385,9 @@ ClearVideoSource (const nsAString&, // unused } static PLDHashOperator -ClearAudioSource(const nsAString &, // unused - MediaEngineAudioSource *aData, void *userArg) +ClearAudioSource (const nsAString&, // unused + MediaEngineWebRTCAudioSource* aData, + void *userArg) { if (aData) { aData->Shutdown(); diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 112c5134d607..105cca560048 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -133,77 +133,13 @@ private: void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut) override; }; -class MediaEngineWebRTCAudioCaptureSource : public MediaEngineAudioSource +class MediaEngineWebRTCAudioSource : public MediaEngineAudioSource, + public webrtc::VoEMediaProcess, + private MediaConstraintsHelper { public: - NS_DECL_THREADSAFE_ISUPPORTS - - explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid) - : MediaEngineAudioSource(kReleased) - { - } - void GetName(nsAString& aName) override; - void GetUUID(nsACString& aUUID) override; - nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, - const MediaEnginePrefs& aPrefs, - const nsString& aDeviceId) override - { - // Nothing to do here, everything is managed in MediaManager.cpp - return NS_OK; - } - nsresult Deallocate() override - { - // Nothing to do here, everything is managed in MediaManager.cpp - return NS_OK; - } - void Shutdown() override - { - // Nothing to do here, everything is managed in MediaManager.cpp - } - nsresult Start(SourceMediaStream* aMediaStream, TrackID aId) override; - nsresult Stop(SourceMediaStream* aMediaStream, TrackID aId) override; - void SetDirectListeners(bool aDirect) override - {} - nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, - uint32_t aAGC, bool aNoiseOn, uint32_t aNoise, - int32_t aPlayoutDelay) override - { - return NS_OK; - } - void NotifyPull(MediaStreamGraph* aGraph, SourceMediaStream* aSource, - TrackID aID, StreamTime aDesiredTime) override - {} - const dom::MediaSourceEnum GetMediaSource() override - { - return dom::MediaSourceEnum::AudioCapture; - } - bool IsFake() override - { - return false; - } - nsresult TakePhoto(PhotoCallback* aCallback) override - { - return NS_ERROR_NOT_IMPLEMENTED; - } - uint32_t GetBestFitnessDistance( - const nsTArray& aConstraintSets, - const nsString& aDeviceId) override; - -protected: - virtual ~MediaEngineWebRTCAudioCaptureSource() { Shutdown(); } - nsCString mUUID; -}; - -class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource, - public webrtc::VoEMediaProcess, - private MediaConstraintsHelper -{ -public: - MediaEngineWebRTCMicrophoneSource(nsIThread* aThread, - webrtc::VoiceEngine* aVoiceEnginePtr, - int aIndex, - const char* name, - const char* uuid) + MediaEngineWebRTCAudioSource(nsIThread* aThread, webrtc::VoiceEngine* aVoiceEnginePtr, + int aIndex, const char* name, const char* uuid) : MediaEngineAudioSource(kReleased) , mVoiceEngine(aVoiceEnginePtr) , mMonitor("WebRTCMic.Monitor") @@ -271,7 +207,7 @@ public: virtual void Shutdown() override; protected: - ~MediaEngineWebRTCMicrophoneSource() { Shutdown(); } + ~MediaEngineWebRTCAudioSource() { Shutdown(); } private: void Init(); @@ -358,7 +294,7 @@ private: // Store devices we've already seen in a hashtable for quick return. // Maps UUID to MediaEngineSource (one set for audio, one for video). nsRefPtrHashtable mVideoSources; - nsRefPtrHashtable mAudioSources; + nsRefPtrHashtable mAudioSources; }; } diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index c45beae4ce24..c85c5710c193 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -41,10 +41,9 @@ extern PRLogModuleInfo* GetMediaManagerLog(); #define LOG_FRAMES(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Verbose, msg) /** - * Webrtc microphone source source. + * Webrtc audio source. */ -NS_IMPL_ISUPPORTS0(MediaEngineWebRTCMicrophoneSource) -NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioCaptureSource) +NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioSource) // XXX temp until MSG supports registration StaticRefPtr gFarendObserver; @@ -178,7 +177,7 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame } void -MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) +MediaEngineWebRTCAudioSource::GetName(nsAString& aName) { if (mInitDone) { aName.Assign(mDeviceName); @@ -188,7 +187,7 @@ MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) } void -MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID) +MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID) { if (mInitDone) { aUUID.Assign(mDeviceUUID); @@ -198,10 +197,10 @@ MediaEngineWebRTCMicrophoneSource::GetUUID(nsACString& aUUID) } nsresult -MediaEngineWebRTCMicrophoneSource::Config(bool aEchoOn, uint32_t aEcho, - bool aAgcOn, uint32_t aAGC, - bool aNoiseOn, uint32_t aNoise, - int32_t aPlayoutDelay) +MediaEngineWebRTCAudioSource::Config(bool aEchoOn, uint32_t aEcho, + bool aAgcOn, uint32_t aAGC, + bool aNoiseOn, uint32_t aNoise, + int32_t aPlayoutDelay) { LOG(("Audio config: aec: %d, agc: %d, noise: %d", aEchoOn ? aEcho : -1, @@ -268,7 +267,7 @@ MediaEngineWebRTCMicrophoneSource::Config(bool aEchoOn, uint32_t aEcho, // Infinity = UINT32_MAX e.g. device cannot satisfy accumulated ConstraintSets. // A finite result may be used to calculate this device's ranking as a choice. -uint32_t MediaEngineWebRTCMicrophoneSource::GetBestFitnessDistance( +uint32_t MediaEngineWebRTCAudioSource::GetBestFitnessDistance( const nsTArray& aConstraintSets, const nsString& aDeviceId) { @@ -282,9 +281,9 @@ uint32_t MediaEngineWebRTCMicrophoneSource::GetBestFitnessDistance( } nsresult -MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs, - const nsString& aDeviceId) +MediaEngineWebRTCAudioSource::Allocate(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) { if (mState == kReleased) { if (mInitDone) { @@ -310,7 +309,7 @@ MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aC } nsresult -MediaEngineWebRTCMicrophoneSource::Deallocate() +MediaEngineWebRTCAudioSource::Deallocate() { bool empty; { @@ -332,8 +331,7 @@ MediaEngineWebRTCMicrophoneSource::Deallocate() } nsresult -MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream, - TrackID aID) +MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID) { if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; @@ -386,7 +384,7 @@ MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream, } nsresult -MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID) +MediaEngineWebRTCAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) { { MonitorAutoLock lock(mMonitor); @@ -423,17 +421,17 @@ MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID) } void -MediaEngineWebRTCMicrophoneSource::NotifyPull(MediaStreamGraph *aGraph, - SourceMediaStream *aSource, - TrackID aID, - StreamTime aDesiredTime) +MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aID, + StreamTime aDesiredTime) { // Ignore - we push audio data LOG_FRAMES(("NotifyPull, desired = %ld", (int64_t) aDesiredTime)); } void -MediaEngineWebRTCMicrophoneSource::Init() +MediaEngineWebRTCAudioSource::Init() { mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine); @@ -498,7 +496,7 @@ MediaEngineWebRTCMicrophoneSource::Init() } void -MediaEngineWebRTCMicrophoneSource::Shutdown() +MediaEngineWebRTCAudioSource::Shutdown() { if (!mInitDone) { // duplicate these here in case we failed during Init() @@ -553,10 +551,9 @@ MediaEngineWebRTCMicrophoneSource::Shutdown() typedef int16_t sample; void -MediaEngineWebRTCMicrophoneSource::Process(int channel, - webrtc::ProcessingTypes type, - sample *audio10ms, int length, - int samplingFreq, bool isStereo) +MediaEngineWebRTCAudioSource::Process(int channel, + webrtc::ProcessingTypes type, sample* audio10ms, + int length, int samplingFreq, bool isStereo) { // On initial capture, throw away all far-end data except the most recent sample // since it's already irrelevant and we want to keep avoid confusing the AEC far-end @@ -621,55 +618,4 @@ MediaEngineWebRTCMicrophoneSource::Process(int channel, return; } -void -MediaEngineWebRTCAudioCaptureSource::GetName(nsAString &aName) -{ - aName.AssignLiteral("AudioCapture"); -} -void -MediaEngineWebRTCAudioCaptureSource::GetUUID(nsACString &aUUID) -{ - nsID uuid; - char uuidBuffer[NSID_LENGTH]; - nsCString asciiString; - ErrorResult rv; - - rv = nsContentUtils::GenerateUUIDInPlace(uuid); - if (rv.Failed()) { - aUUID.AssignLiteral(""); - return; - } - - - uuid.ToProvidedString(uuidBuffer); - asciiString.AssignASCII(uuidBuffer); - - // Remove {} and the null terminator - aUUID.Assign(Substring(asciiString, 1, NSID_LENGTH - 3)); -} - -nsresult -MediaEngineWebRTCAudioCaptureSource::Start(SourceMediaStream *aMediaStream, - TrackID aId) -{ - aMediaStream->AddTrack(aId, 0, new AudioSegment()); - return NS_OK; -} - -nsresult -MediaEngineWebRTCAudioCaptureSource::Stop(SourceMediaStream *aMediaStream, - TrackID aId) -{ - aMediaStream->EndAllTrackAndFinish(); - return NS_OK; -} - -uint32_t -MediaEngineWebRTCAudioCaptureSource::GetBestFitnessDistance( - const nsTArray& aConstraintSets, - const nsString& aDeviceId) -{ - // There is only one way of capturing audio for now, and it's always adequate. - return 0; -} } diff --git a/dom/webidl/Constraints.webidl b/dom/webidl/Constraints.webidl index f7f0c706a9d7..fc6275b59b4e 100644 --- a/dom/webidl/Constraints.webidl +++ b/dom/webidl/Constraints.webidl @@ -25,7 +25,6 @@ enum MediaSourceEnum { "window", "browser", "microphone", - "audioCapture", "other" }; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 576b7680a6a9..fbbab15fb332 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -445,8 +445,6 @@ pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webe // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); -pref("media.getusermedia.audiocapture.enabled", false); - // TextTrack support pref("media.webvtt.enabled", true); pref("media.webvtt.regions.enabled", false);