From 21c98793d3c19092ca56065458bfb6388f0d02c0 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 10 Sep 2024 22:30:49 +0800 Subject: [PATCH] =?UTF-8?q?import=20changes=20from=20`dev'=20branch=20of?= =?UTF-8?q?=20rmottola/Arctic-Fox:=20-=20Bug=201244883=20-=20Add=20Nightly?= =?UTF-8?q?-/Aurora-only=20crash=20for=20AsyncTransactionWaiter=20timeouts?= =?UTF-8?q?=20-=20r=3Dnical=20(132b2ceff9)=20-=20Bug=201148978=20-=20Trigg?= =?UTF-8?q?er=20paints=20when=20moving=20plugin=20windows=20around=20on=20?= =?UTF-8?q?the=20browser=20main=20thread.=20r=3Dmattwoodrow=20(c75ce5ec09)?= =?UTF-8?q?=20-=20Dedent=20some=20functions.=20(bug=201254899=20part=201,?= =?UTF-8?q?=20r=3Djrmuizel)=20(c84fb419c7)=20-=20Refactor=20acceleration?= =?UTF-8?q?=20pref=20initialization.=20(bug=201254899=20part=202,=20r=3Djr?= =?UTF-8?q?muizel)=20(29a164c70e)=20-=20Remove=20NS=5FNATIVE=5FGRAPHIC=20o?= =?UTF-8?q?n=20Windows.=20(bug=201266536,=20r=3Djimm)=20(84011349d1)=20-?= =?UTF-8?q?=20Bug=201267253=20-=20Delete=20gfxWindowsPlatform::RenderMode?= =?UTF-8?q?=20and=20replace=20it=20with=20a=20check=20against=20the=20defa?= =?UTF-8?q?ult=20backend.=20r=3Dbas=20(93cb6e503e)=20-=20Introduce=20gfxCo?= =?UTF-8?q?nfig,=20a=20manager=20for=20graphics=20feature=20settings.=20(b?= =?UTF-8?q?ug=201254899=20part=203,=20r=3Dmilan)=20(97498ca46a)=20-=20Bug?= =?UTF-8?q?=201262187:=20Allow=20D3D9=20if=20D3D11=20failed,=20behind=20th?= =?UTF-8?q?e=20pref,=20but=20on=20by=20default.=20r=3Dbas=20(8163e28b26)?= =?UTF-8?q?=20-=20Bug=201178376=20-=20Optionally=20fade=20in=20new=20progr?= =?UTF-8?q?essively=20painted=20tiles=20r=3Dnical=20(777bf1799d)=20-=20Bug?= =?UTF-8?q?=201178376=20-=20Allow=20progressive=20painting=20when=20low-pr?= =?UTF-8?q?ecision=20tiles=20are=20disabled=20r=3DBenWa=20(3b8d84e19c)=20-?= =?UTF-8?q?=20Bug=201178376=20-=20Put=20progressive=20paint=20status=20in?= =?UTF-8?q?=20tile=20updates=20r=3Dnical=20(935d3b46ed)=20-=20Bug=20125177?= =?UTF-8?q?8:=20Attempt=20to=20avoid=20presenting=20when=20the=20window=20?= =?UTF-8?q?is=20still=20resizing.=20r=3Djrmuizel=20(32b194a6f7)=20-=20Hois?= =?UTF-8?q?t=20mWidget=20into=20the=20Compositor=20base=20class.=20(bug=20?= =?UTF-8?q?1264545=20part=201,=20r=3Dnical)=20(aca26ec343)=20-=20Lift=20co?= =?UTF-8?q?mpositor-accessed=20methods=20from=20nsIWidget=20into=20Composi?= =?UTF-8?q?torWidgetProxy.=20(bug=201264545=20part=202,=20r=3Djimm)=20(609?= =?UTF-8?q?a23157a)=20-=20Rename=20FeatureStatus::Crashed=20to=20CrashedIn?= =?UTF-8?q?Handler.=20(bug=201254899=20part=204,=20r=3Dmilan)=20(0eae23a3f?= =?UTF-8?q?d)=20-=20Move=20DeviceInitData=20from=20gfxWindowsPlatform=20to?= =?UTF-8?q?=20gfxPlatforn.=20(bug=201254899=20part=205,=20r=3Dmilan)=20(e3?= =?UTF-8?q?1540ba18)=20-=20Merge=20gfxWindowsPlatform::mAcceleration=20int?= =?UTF-8?q?o=20gfxConfig.=20(bug=201254899=20part=206,=20r=3Dmilan)=20(9d4?= =?UTF-8?q?5cc8b87)=20-=20Add=20another=20feature=20state=20for=20blacklis?= =?UTF-8?q?ting=20and=20environment=20decisions.=20(bug=201254899=20part?= =?UTF-8?q?=207,=20r=3Dmilan)=20(e7eee53cfb)=20-=20Give=20FeatureState=20a?= =?UTF-8?q?=20public=20interface.=20(bug=201254899=20part=208,=20r=3Dmilan?= =?UTF-8?q?)=20(52d8e7f355)=20-=20Replace=20gfxWindowsPlatform::mD3D11Stat?= =?UTF-8?q?us=20with=20gfxConfig.=20(bug=201254899=20part=209,=20r=3Djrmui?= =?UTF-8?q?zel)=20(90dc658b53)=20-=20Replace=20gfxWindowsPlatform::mD2D1St?= =?UTF-8?q?atus=20with=20gfxConfig.=20(bug=201254899=20part=2010,=20r=3Dmi?= =?UTF-8?q?lan)=20(eb9474f309)=20-=20Fix=20assertion=20failure=20in=20gfxC?= =?UTF-8?q?onfig.=20(bug=201269565,=20r=3Dmilan)=20(0eb738ce66)=20-=20Add?= =?UTF-8?q?=20gfxConfig=20to=20nsIGfxInfo,=20for=20about:support=20access.?= =?UTF-8?q?=20(bug=201254899=20part=2011,=20r=3Djrmuizel)=20(e770240152)?= =?UTF-8?q?=20-=20Change=20Compositor::GetWidget=20to=20return=20a=20Compo?= =?UTF-8?q?sitorWidgetProxy.=20(bug=201264545=20part=203,=20r=3Djimm)=20(f?= =?UTF-8?q?df1d96255)=20-=20Bug=201251778=20-=20Followup:=20Remove=20unref?= =?UTF-8?q?erenced=20local=20variable.=20r=3Dbustage=20(27579f5542)=20-=20?= =?UTF-8?q?Use=20CompositorWidgetProxy=20in=20place=20of=20nsIWidget=20in?= =?UTF-8?q?=20the=20compositor.=20(bug=201264545=20part=204,=20r=3Djimm)?= =?UTF-8?q?=20(80def1c2eb)=20-=20Use=20CompositorWidgetProxy=20in=20place?= =?UTF-8?q?=20of=20nsIWidget=20in=20CompositorBridgeParent.=20(bug=2012645?= =?UTF-8?q?45=20part=205,=20r=3Djimm,kats)=20(67d0e1ef7d)=20-=20Move=20Com?= =?UTF-8?q?positorWidgetProxy=20inheritance=20out=20of=20nsIWidget.=20(bug?= =?UTF-8?q?=201264545=20part=206,=20r=3Djimm)=20(61075722c5)=20-=20Bug=201?= =?UTF-8?q?251894=20-=20In=20CompositorD3D11::CreateTexture,=20copy=20as?= =?UTF-8?q?=20much=20as=20the=20render=20target=20allows.=20r=3Dbas=20(bf5?= =?UTF-8?q?fc6baa2)=20-=20Bug=201266444:=20It=20is=20OK=20for=20us=20not?= =?UTF-8?q?=20to=20have=20texture=20sharing.=20r=3Djrmuizel=20(0b1885f89d)?= =?UTF-8?q?=20-=20Bug=201266396=20-=20Make=20TextureClient=20more=20robust?= =?UTF-8?q?=20against=20racy=20shutdown=20situations.=20r=3DBas=20(b1d7f54?= =?UTF-8?q?643)=20-=20Fix=20test=20bustage=20due=20to=20platform=20line-en?= =?UTF-8?q?dings.=20Bug=201222624=20(10b8cf3592)=20-=20More=20test=20busta?= =?UTF-8?q?ge=20from=20bug=201222624=20(763c4c0bb9)=20-=20Backed=20out=204?= =?UTF-8?q?=20changesets=20(bug=201222624)=20to=20fix=20bug=201249572=20(7?= =?UTF-8?q?ba3d433d0)=20-=20Bug=201268230=20-=20RunTime.cpp=20and=20Script?= =?UTF-8?q?Loader=20do=20not=20have=20to=20use=20MainThreadStopSyncLoopRun?= =?UTF-8?q?nable,=20r=3Dkhuey=20(88499a3982)=20-=20Bug=201037725=20-=20Add?= =?UTF-8?q?=20warning=20message=20in=20the=20console=20when=20worker=20spa?= =?UTF-8?q?wn=20over=20limit.=20r=3Dkhuey=20(8af94dbc1d)=20-=20Bug=2010476?= =?UTF-8?q?63=20-=20Disabling=20the=20cache=20in=20a=20tab=20should=20also?= =?UTF-8?q?=20disable=20it=20for=20all=20workers=20in=20that=20tab;r=3Dkhu?= =?UTF-8?q?ey=20(5411d81682)=20-=20Bug=201253793=20Update=20ScriptLoader?= =?UTF-8?q?=20assertion=20to=20handle=20cancelation=20case.=20r=3Dkhuey=20?= =?UTF-8?q?(18c78d5651)=20-=20Bug=201245768=20-=20Implement=20a=20test=20f?= =?UTF-8?q?or=20the=20correct=20error=20management=20when=20worker=20impor?= =?UTF-8?q?ts=203rd=20party=20scripts,=20r=3Dbz=20(c1d3f290a9)=20-=20Bug?= =?UTF-8?q?=201249673.=20Muted=20errors=20should=20be=20turned=20into=20Ne?= =?UTF-8?q?tworkError=20DOMExceptions=20when=20returning=20from=20importSc?= =?UTF-8?q?ripts=20on=20workers,=20instead=20of=20becoming=20NS=5FERROR=5F?= =?UTF-8?q?FAILURE.=20r=3Dbaku=20(0358282cbe)=20-=20Bug=201265405=20-=20Ad?= =?UTF-8?q?d=20a=20dictionary=20to=20specify=20how=20PeriodicWave=20should?= =?UTF-8?q?=20be=20normalized=20(or=20not);=20r=3Dsmaug=20=E2=80=A6normali?= =?UTF-8?q?zed=20(or=20not);=20r=3Dsmaugu=20(201213146c)=20-=20Bug=2012510?= =?UTF-8?q?82.=20Restore=20comments=20in=20PageTransitionEvent.webidl=20th?= =?UTF-8?q?at=20got=20lost=20when=20nsIDOMPageTransitionEvent.idl=20was=20?= =?UTF-8?q?migrated=20to=20webidl.=20r=3Dbz=20The=20mentioned=20migration?= =?UTF-8?q?=20happened=20in=20http://hg.mozilla.org/mozilla-central/rev/e6?= =?UTF-8?q?377ca32f3d=20from=20bug=201031051.=20(2dfa309056)=20-=20Bug=201?= =?UTF-8?q?266178=20Make=20ServiceWorkerClient=20not=20assert=20if=20the?= =?UTF-8?q?=20document=20doesn't=20have=20an=20outer=20window.=20r=3Dehsan?= =?UTF-8?q?=20(eafb169c91)=20-=20Bug=201259164=20-=20Set=20ServiceWorkerMe?= =?UTF-8?q?ssageEvent.origin=20correctly=20when=20calling=20ServiceWorkerC?= =?UTF-8?q?lient.postMessage();=20r=3Dbkelly=20(caeb65d10e)=20-=20Bug=2012?= =?UTF-8?q?46319=20P1=20Dedupe=20service=20worker=20registrar=20entries.?= =?UTF-8?q?=20r=3Dbaku=20(b76deef941)=20-=20Bug=201246319=20P2=20Verify=20?= =?UTF-8?q?entries=20are=20deduped=20from=20the=20ServiceWorkerRegistrar.?= =?UTF-8?q?=20r=3Dbaku=20(8a4e348d6e)=20-=20Bug=201246319=20P3=20Fix=20ser?= =?UTF-8?q?vice=20worker=20registry=20value=20update.=20r=3Dbz=20(14abf6b6?= =?UTF-8?q?ce)=20-=20Bug=201247970=20-=20Remove=20principal=20spec=20from?= =?UTF-8?q?=20service=20worker=20registrar=20file.=20r=3Dbaku=20(3c3013070?= =?UTF-8?q?0)=20-=20Bug=201249438=20P1=20Move=20guts=20of=20RegisterServic?= =?UTF-8?q?eWorker()=20into=20a=20protected=20method=20that=20can=20be=20t?= =?UTF-8?q?ested=20in=20gtest.=20r=3Dbaku=20(488243196d)=20-=20Bug=2012494?= =?UTF-8?q?38=20P2=20Modify=20existing=20gtest=20to=20use=20RegisterServic?= =?UTF-8?q?eWorkerInternal.=20r=3Dbaku=20(e86c66891d)=20-=20Bug=201249438?= =?UTF-8?q?=20P3=20Add=20a=20gtest=20that=20registers=20duplicate=20servic?= =?UTF-8?q?e=20worker=20registrations.=20r=3Dbaku=20(35e269f9af)=20-=20Bug?= =?UTF-8?q?=201226443=20P6=20Ignore=20update()=20called=20during=20top=20l?= =?UTF-8?q?evel=20service=20worker=20script=20evaluation.=20r=3Dehsan=20(d?= =?UTF-8?q?cb9d02553)=20-=20Bug=201241725=20-=20about:serviceworkers=20"Ac?= =?UTF-8?q?tive=20Cache=20Name"=20UUID=20should=20not=20contain=20null=20b?= =?UTF-8?q?ytes,=20r=3Dbkelly=20(4cddea6a67)=20-=20Bug=201221852=20-=20Sha?= =?UTF-8?q?redWorker.port=20should=20be=20always=20not=20null,=20r=3Dsmaug?= =?UTF-8?q?=20(a9800274dc)=20-=20Bug=201261428:=20Clean=20up=20a=20bit=20m?= =?UTF-8?q?ore.=20r=3Dbz=20(4977e3d7a5)=20-=20Bug=20890284.=20Stop=20split?= =?UTF-8?q?ting=20textnodes=20in=20the=20XML=20content=20sink.=20r=3Dpeter?= =?UTF-8?q?v=20(a46dfca1cf)=20-=20Bug=201211708=20Allow=20themes=20to=20sp?= =?UTF-8?q?ecify=20XBL=20bindings=20even=20in=20unprivileged=20documents?= =?UTF-8?q?=20r=3Dsicking=20(82cf1a4023)=20-=20Bug=20915962=20-=20Part=201?= =?UTF-8?q?:=20Allow=20pressing=20space=20to=20scroll=20the=20document=20i?= =?UTF-8?q?f=20an=20editable=20element=20or=20form=20control=20is=20not=20?= =?UTF-8?q?focused;=20r=3Droc=20(cdb934af03)=20-=20Bug=20915962=20-=20Part?= =?UTF-8?q?=202:=20Add=20a=20test=20case=20for=20pressing=20space=20when?= =?UTF-8?q?=20a=20tabindex=3D-1=20and=20a=20button=20element=20is=20focuse?= =?UTF-8?q?d;=20r=3Droc=20(17dcf5cfd0)=20-=20Bug=20915962=20-=20Part=203:?= =?UTF-8?q?=20Do=20not=20crash=20when=20pressing=20the=20space=20bar=20wit?= =?UTF-8?q?hout=20having=20an=20element=20focused;=20r=3Droc=20(2161e62bc3?= =?UTF-8?q?)=20-=20Bug=201180761,=20cancel=20the=20event=20earlier=20so=20?= =?UTF-8?q?that=20space=20doesn't=20trigger=20checkbox=20change=20and=20sc?= =?UTF-8?q?roll,=20r=3Dneil=20(2425cb76ad)=20-=20Bug=201259182=20-=20Shrin?= =?UTF-8?q?k=20keyCodeData.=20r=3Dbz.=20(737204af84)=20-=20Bug=201193567?= =?UTF-8?q?=20-=20Check=20result=20of=20ReadID=20in=20nsXBLPrototypeBindin?= =?UTF-8?q?g::Read().=20r=3Dwchen=20(c9b1c35bf3)=20-=20Bug=201173344=20-?= =?UTF-8?q?=20Remove=20an=20intermediary=20root=20from=20nsXBLProtoImplFie?= =?UTF-8?q?ld's=20FieldGetterImpl;=20r=3Djandem=20(5f42dd2e48)=20-=20Bug?= =?UTF-8?q?=201207494=20-=20Part=2014:=20Remove=20use=20of=20expression=20?= =?UTF-8?q?closure=20from=20dom/xbl/.=20r=3Dbz=20(21c7d3825f)=20-=20align?= =?UTF-8?q?=20tests=20(fe34b613d3)=20-=20Bug=201223702=20-=20Fix=20some=20?= =?UTF-8?q?errors=20about=20wifi=20direct.=20r=3Dhchang=20(568d86054a)=20-?= =?UTF-8?q?=20Bug=201166274=20-=20Part=201:=20Handle=20the=20callback=20an?= =?UTF-8?q?d=20IPC=20message=20of=20setStaticIpMode=20correctly.=20r=3Dvch?= =?UTF-8?q?ang=20(8fb8d7f3b7)=20-=20Bug=201133665=20-=20[Flame][Wifi]=20Th?= =?UTF-8?q?e=20SSID=20that=20has=20set=20to=20be=20binded=20with=20MAC=20a?= =?UTF-8?q?ddress=20is=20not=20hightlighted=20when=20user=20taps=20it.=20r?= =?UTF-8?q?=3Dhchang=20(3165471d13)=20-=20Bug=201207494=20-=20Part=2013:?= =?UTF-8?q?=20Remove=20use=20of=20expression=20closure=20from=20dom/wifi/.?= =?UTF-8?q?=20r=3Dhenry=20(dd9ad23a8a)=20-=20Bug=201251856=20-=20Disable?= =?UTF-8?q?=20U2F=20in=20all=20releases=20(fix=20for=201231681).=20r=3Dbak?= =?UTF-8?q?u=20(24ada10566)=20-=20align=20tests=20(dae9ecd0ee)=20-=20var-l?= =?UTF-8?q?et=20(11a3cb0878)=20-=20Bug=201184822=20-=20Use=20classId=20to?= =?UTF-8?q?=20get=20provider.=20r=3Dfabrice=20(1288eccd06)=20-=20Bug=20124?= =?UTF-8?q?7410=20-=20"test=20for=20=5Fnomap=20ids=20does=20not=20work=20c?= =?UTF-8?q?orrectly".=20r=3Ddougt=20(f736a04f08)=20-=20Bug=201035097=20-?= =?UTF-8?q?=20Changed=20the=20type=20from=20'radio'=20to=20'radioType'.=20?= =?UTF-8?q?r=3Djdm=20(f9a0079152)=20-=20Bug=201177871=20-=20Add=20a=20time?= =?UTF-8?q?out=20to=20XHR=20request=20of=20WifiGeoPositionProvider.=20r=3D?= =?UTF-8?q?jdm=20(2f6aa87c20)=20-=20align=20code=20to=20978593=20with=20PO?= =?UTF-8?q?ST=20and=20location=20structure=20(d8ba75a759)=20-=20Bug=201230?= =?UTF-8?q?685=20-=20Replace=20function=20declarations=20with=20add=5Ftask?= =?UTF-8?q?=20statements=20in=20test=5Fstorage=5Fvalue=5Farray.js=20and=20?= =?UTF-8?q?test=5Funicode.js.=20r=3Dmak=20(9822bf2215)=20-=20Bug=201230683?= =?UTF-8?q?=20-=20Replace=20try/catch=20with=20Assert.throws=20in=20test?= =?UTF-8?q?=5Fstorage=5Fconnection.js.=20r=3Dmak=20(1c993fc37e)=20-=20Bug?= =?UTF-8?q?=20655722=20-=20Rewrite=20=5FbuildGUIDMap=20in=20the=20sync=20b?= =?UTF-8?q?ookmark=20engine=20to=20use=20PlacesUtils.promiseBookmarksTree.?= =?UTF-8?q?=20r=3Dmak=20(3795d26af0)=20-=20Bug=201251057=20-=20enable=20de?= =?UTF-8?q?bug=20logging=20for=20rest.js=20requests=20and=20responses.=20r?= =?UTF-8?q?=3Dadw=20(1062bcd113)=20-=20Bug=20503515=20-=20Try=20and=20ensu?= =?UTF-8?q?re=20exported=20certificates=20include=20an=20extension=20by=20?= =?UTF-8?q?default.=20r=3Dkeeler=20(505967ab7f)=20-=20Bug=201017616=20-=20?= =?UTF-8?q?Filter=20out=20some=20more=20unnecessary=20characters=20when=20?= =?UTF-8?q?exporting=20certs.=20r=3Dkeeler=20(e95838e362)=20-=20Bug=201241?= =?UTF-8?q?614=20-=20don't=20overflow:auto=20the=20container,=20use=20em?= =?UTF-8?q?=20to=20size=20the=20dialog=20to=20avoid=20hidpi=20visibility?= =?UTF-8?q?=20issues,=20r=3Ddolske,ttaubert=20(8bd6c2b35b)=20-=20Bug=20126?= =?UTF-8?q?6851.=20Make=20=20and=20<listing>=20use=20HTMLPreElement?= =?UTF-8?q?=20as=20their=20primary=20interface,=20per=20<whatwg/html#1015>?= =?UTF-8?q?.=20=20r=3Dpeterv=20(6be7f9d6e9)=20-=20Bug=201262184=20-=20Bloc?= =?UTF-8?q?k=20embed=20content=20loading=20when=20child=20of=20media=20ele?= =?UTF-8?q?ment;=20r=3Dbz=20(a297eeb378)=20-=20Bug=201263696=20-=20Block?= =?UTF-8?q?=20embed=20content=20loading=20when=20ancestor=20of=20object=20?= =?UTF-8?q?element=20with=20content;=20r=3Dbz=20(89c143cbfe)=20-=20Bug=201?= =?UTF-8?q?266077.=20Fix=20<base>=20href=20getter=20to=20follow=20the=20sp?= =?UTF-8?q?ec;=20it=20should=20be=20using=20the=20fallback=20base=20URI=20?= =?UTF-8?q?to=20resolve=20against,=20not=20the=20document=20URI.=20r=3Dbke?= =?UTF-8?q?lly=20(e757b23a14)=20-=20Bug=201168079=20nsTextEditRules::Colla?= =?UTF-8?q?pseSelectionToTrailingBRIfNeeded()=20should=20ensure=20that=20t?= =?UTF-8?q?here=20is=20a=20selection=20before=20calling=20nsEditor::GetSta?= =?UTF-8?q?rtNodeAndOffset()=20r=3Dehsan=20(6c283bf3a7)=20-=20Bug=20898321?= =?UTF-8?q?=20-=20Return=20success=20from=20nsTableEditor::GetCellAt=20if?= =?UTF-8?q?=20frame=20not=20found;=20r=3Dehsan=20(0d09143b95)=20-=20Bug=20?= =?UTF-8?q?387687=20-=20wrap=20quotes=20in=20plain=20text=20replies=20to?= =?UTF-8?q?=20window.=20r=3Dmasayuki=20(ca51437018)=20-=20Bug=201247483=20?= =?UTF-8?q?-=20Only=20replace=20nodes=20in=20nsHTMLEditor::ReplaceOrphaned?= =?UTF-8?q?Structure=20if=20all=20nodes=20in=20node=20list=20are=20descend?= =?UTF-8?q?ants=20of=20replacement=20node.=20r=3Dehsan=20(8416037da2)=20-?= =?UTF-8?q?=20bug=201266496=20-=20fire=20some=20selection=20events=20for?= =?UTF-8?q?=20proxied=20accessibles=20r=3Ddavidb=20(8806de7dd9)=20-=20bug?= =?UTF-8?q?=201266518=20-=20add=20a=20new=20event=20message=20for=20AccSel?= =?UTF-8?q?ChangeEvents=20r=3Ddavidb=20(46af183cab)=20-=20Bug=20953265:=20?= =?UTF-8?q?Adjust=20Opus=20bitrate=20in=20WebRTC=20to=20pass=20>8KHz=20aud?= =?UTF-8?q?io,=20and=20comment=20r=3Dbwc=20(b0be6a326e)=20-=20Bug=20122147?= =?UTF-8?q?3:=20Do=20not=20treat=20answer=20as=20authoritative=20wrt=20pay?= =?UTF-8?q?load=20types.=20r=3Ddrno=20(d27409209e)=20-=20Bug=201241321=20-?= =?UTF-8?q?=20No=20RTCP=20stats=20for=20audio=20streams.=20r=3Drjesup=20(e?= =?UTF-8?q?c0222694e)=20-=20bug=201250492=20-=20use=20tl::Max=20instead=20?= =?UTF-8?q?of=20std::max=20to=20get=20rid=20of=20a=20static=20constructor?= =?UTF-8?q?=20r=3Djesup=20(3cebbc8969)=20-=20Bug=201254187:=20Fix=20maxBit?= =?UTF-8?q?rate=20to=20respect=20simulcast.=20r=3Djesup=20(e569e54b57)=20-?= =?UTF-8?q?=20Bug=201158931=20-=20Fix=20static=20assertion=20compilation?= =?UTF-8?q?=20error;=20r=3Dsnorp=20(eb27881746)=20-=20No=20bug,=20fix=20We?= =?UTF-8?q?brtcMediaCodecVP8VideoCodec.cpp=20warnings=20(a983544581)=20-?= =?UTF-8?q?=20Bug=201252737=20-=20use=20size=5Ft=20instead=20of=20uint32?= =?UTF-8?q?=5Ft=20for=20InitEncode().=20r=3Djesup=20(57c3abc9fa)=20-=20Bug?= =?UTF-8?q?=201208371=20-=20Never=20send=20more=20than=20one=20disabled=20?= =?UTF-8?q?frame=20in=20a=20row=20to=20the=20WebRTC=20encoder.=20r=3Djesup?= =?UTF-8?q?=20(ec0c28822b)=20-=20Bug=201208371=20-=20Do=20image=20format?= =?UTF-8?q?=20conversion=20async=20in=20MediaPipeline.=20r=3Djesup=20(032e?= =?UTF-8?q?fec783)=20-=20Bug=201266685=20-=20Don't=20pass=20too=20many=20f?= =?UTF-8?q?rames=20to=20the=20MediaPipelineTransmit=20VideoFrameConverter.?= =?UTF-8?q?=20r=3Djesup=20(21774a8d25)=20-=20Bug=201266644=20-=20Rename=20?= =?UTF-8?q?StreamBuffer=20to=20StreamTracks.=20r=3Djesup=20r=3Dpehrsons=20?= =?UTF-8?q?(21906fe1f7)=20-=20Bug=201208371=20-=20Don't=20treat=20audio=20?= =?UTF-8?q?chunks=20as=20mutable=20in=20MediaPipeline.=20r=3Dpadenot=20(38?= =?UTF-8?q?78ef4332)=20-=20Bug=201246310=20-=20Let=20MediaPipelineReceive?= =?UTF-8?q?=20tracks=20start=20at=200.=20r=3Djesup=20(b468ff8d48)=20-=20Bu?= =?UTF-8?q?g=201266644=20-=20Rename=20DOMMediaStream::=20CreateXXXStream?= =?UTF-8?q?=20to=20DOMMediaStream::=20CreateXXXStreamAsInput.=20r=3Djesup?= =?UTF-8?q?=20r=3Dpehrsons=20(fe4b6d70bc)=20-=20Bug=201234578:=20Add=20an?= =?UTF-8?q?=20assertion.=20r=3Ddrno,=20a=3Dabillings=20(f1a2c8d841)=20-=20?= =?UTF-8?q?bug=201250492=20-=20include=20sstream=20in=20SdpMediaSection.h?= =?UTF-8?q?=20instead=20of=20iostream=20r=3Djesup=20(110b5c2eca)=20-=20Bug?= =?UTF-8?q?=201264470=20-=20a=3Didentity=20is=20a=20long=20attribute,=20r?= =?UTF-8?q?=3Dbwc=20(5848194fe9)=20-=20Bug=201256750:=20Remove=20unnecessa?= =?UTF-8?q?ry=20sscanf=5Fs=20parameter=20on=20windows,=20and=20fix=20forma?= =?UTF-8?q?t=20string=20everywhere=20else.=20r=3Djesup=20(371c0db476)=20-?= =?UTF-8?q?=20Bug=201204082=20-=20try=20strtoull=20instead.=20r=3Dmt=20(a0?= =?UTF-8?q?313aa87c)=20-=20Bug=201113443=20-=20reject=20each=20media=20typ?= =?UTF-8?q?e=20with=20approriate=20default.=20r=3Dbwc=20(a72ff312d1)=20-?= =?UTF-8?q?=20Bug=201095793=20-=20use=20mid=20if=20provided=20to=20place?= =?UTF-8?q?=20candidate=20in=20msection.=20r=3Dbwc=20(2c29b21fac)=20-=20Bu?= =?UTF-8?q?g=201252699=20-=20Set=20WEBRTC=5FDETECT=5FARM=5FNEON=20when=20o?= =?UTF-8?q?ptional=20neon=20is=20requested.=20r=3Djesup=20(722e2043a5)=20-?= =?UTF-8?q?=20Bug=201229475=20-=20webrtc:=20Call=20opus=20tonality=5Fanaly?= =?UTF-8?q?sis=5Finit.=20r=3Djesup=20(1cf8cc2cd7)=20-=20Bug=201254876:=20a?= =?UTF-8?q?ssert=20windows=20recording=20is=20shut=20down=20r=3Dpkerr=20(1?= =?UTF-8?q?f2cb69073)=20-=20Bug=201227481=20-=20added=20a=20memset=20on=20?= =?UTF-8?q?aec.=20r=3Djesup=20(532026ce20)=20-=20Bug=201254507=20-=20Fix?= =?UTF-8?q?=20leak=20in=20WebRTC=20DesktopApplication=20class.=20r=3Djesup?= =?UTF-8?q?=20(54da72aeb4)=20-=20Bug=201196542=20-=20share=20only=20window?= =?UTF-8?q?s=20with=20non-zero=20area.=20r=3Dpkerr=20(94595ec463)=20-=20Bu?= =?UTF-8?q?g=201202087=20-=20Filter=20out=20non-shareable=20application=20?= =?UTF-8?q?for=20win8=20or=20greater.=20r=3Djesup=20(d989956802)=20-=20Bug?= =?UTF-8?q?=201216529=20-=20WebRTC:=20Request=20camera=20permission=20befo?= =?UTF-8?q?re=20accessing=20camera=20APIs.=20r=3Dgcp=20(24b6699226)=20-=20?= =?UTF-8?q?Bug=201237630=20-=20Part=201:=20Video=20freeze=20from=20WebRTC?= =?UTF-8?q?=20sender.=20r=3Drjesup=20(02daa8b5b7)=20-=20Bug=201237630=20-?= =?UTF-8?q?=20Part=202:=20remove=20LOG=20statement=20generating=20a=20now?= =?UTF-8?q?=20defunct=20error=20condition.=20r=3Drjesup=20(c6002ef12f)=20-?= =?UTF-8?q?=20Bug=201248335:=20avoid=20using=20SvcInternal=20structure=20e?= =?UTF-8?q?ntirely,=20as=20system-vpx=20may=20not=20have=20it=20r=3Dpkerr?= =?UTF-8?q?=20(ef9b21f20c)=20-=20Bug=201234571:=20unregister=20encoded-fra?= =?UTF-8?q?me=20callback=20when=20releasing=20codec=20databases=20r=3Dpker?= =?UTF-8?q?r=20(321bd5166b)=20-=20Bug=20820972=20-=20Comment=20out=20color?= =?UTF-8?q?Table[]=20because=20we=20don't=20need=20it.=20r=3Djesup.=20(60b?= =?UTF-8?q?10803d5)=20-=20cleanup=20and=20missing=20test=20stuff=20(e2be03?= =?UTF-8?q?31d9)=20-=20Merge=20remote-tracking=20branch=20'upstream/dev'?= =?UTF-8?q?=20into=20winbuild=20(3a3bb0b315)=20-=20layout/media:=20fix=20e?= =?UTF-8?q?xport=20symbol=20list,=20fix=20build=20bustage=20(f9f5bfe14c)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accessible/atk/AccessibleWrap.cpp | 11 + accessible/base/Platform.h | 2 + accessible/generic/Accessible.cpp | 9 + accessible/ipc/DocAccessibleParent.cpp | 25 + accessible/ipc/DocAccessibleParent.h | 4 + accessible/ipc/PDocAccessible.ipdl | 1 + accessible/mac/Platform.mm | 5 + accessible/other/Platform.cpp | 5 + accessible/windows/msaa/Platform.cpp | 7 + dom/base/nsObjectLoadingContent.cpp | 24 +- dom/base/test/file_bug1263696_frame_fail.html | 12 + dom/base/test/file_bug1263696_frame_pass.html | 13 + dom/base/test/mochitest.ini | 3 + dom/base/test/test_bug1263696.html | 53 ++ dom/html/HTMLMediaElement.cpp | 2 +- dom/html/HTMLObjectElement.h | 1 + dom/html/HTMLPreElement.cpp | 8 + dom/html/HTMLSharedElement.cpp | 4 +- dom/html/HTMLSharedObjectElement.cpp | 41 +- dom/html/HTMLSharedObjectElement.h | 27 +- dom/html/test/test_bug389797.html | 4 +- dom/inputport/InputPort.cpp | 2 +- dom/locales/en-US/chrome/dom/dom.properties | 4 +- dom/media/AudioCaptureStream.cpp | 6 +- dom/media/AudioCaptureStream.h | 2 +- dom/media/CanvasCaptureMediaStream.h | 2 +- dom/media/DOMMediaStream.cpp | 40 +- dom/media/DOMMediaStream.h | 38 +- dom/media/MediaInfo.h | 2 +- dom/media/MediaManager.cpp | 6 +- dom/media/MediaSegment.h | 2 +- dom/media/MediaStreamGraph.cpp | 82 +- dom/media/MediaStreamGraph.h | 42 +- dom/media/MediaStreamGraphImpl.h | 2 +- dom/media/MediaStreamTrack.h | 2 +- dom/media/PeerConnection.js | 1 - dom/media/StreamTracks.cpp | 117 +++ dom/media/StreamTracks.h | 343 ++++++++ dom/media/TrackUnionStream.cpp | 20 +- dom/media/TrackUnionStream.h | 6 +- dom/media/encoder/TrackEncoder.h | 2 +- dom/media/moz.build | 4 +- .../test_peerConnection_addIceCandidate.html | 24 +- dom/media/webaudio/AudioContext.cpp | 1 + dom/media/webaudio/AudioContext.h | 2 + .../webaudio/AudioNodeExternalInputStream.cpp | 4 +- dom/media/webaudio/AudioNodeStream.cpp | 10 +- .../MediaStreamAudioDestinationNode.cpp | 6 +- dom/media/webrtc/MediaEngineDefault.h | 4 +- .../webrtc/MediaEngineRemoteVideoSource.h | 2 +- dom/media/webrtc/MediaEngineWebRTC.h | 2 +- dom/system/NetworkGeolocationProvider.js | 47 +- dom/system/SystemUpdateService.jsm | 2 +- dom/telephony/gonk/USSDReceivedWrapper.js | 2 +- .../browser/browser_ConsoleStorageAPITests.js | 2 +- dom/tests/mochitest/general/chrome.ini | 1 + .../performance_timeline_main_test.html | 4 +- .../general/resource_timing_main_test.html | 6 +- .../mochitest/general/test_interfaces.html | 2 +- .../general/test_spacetopagedown.html | 76 ++ .../unit/test_geolocation_provider_timeout.js | 49 ++ dom/tests/unit/xpcshell.ini | 2 + dom/tethering/TetheringManager.js | 2 +- dom/tethering/tests/marionette/head.js | 2 +- dom/voicemail/gonk/VoicemailService.js | 2 +- dom/voicemail/test/marionette/head.js | 8 +- dom/wappush/gonk/CpPduHelper.jsm | 8 +- dom/wappush/gonk/SiPduHelper.jsm | 6 +- dom/wappush/gonk/SlPduHelper.jsm | 6 +- dom/wappush/gonk/WapPushManager.js | 4 +- dom/wappush/gonk/WbxmlPduHelper.jsm | 2 +- dom/wappush/tests/header_helpers.js | 4 +- dom/wappush/tests/test_cp_pdu_helper.js | 14 +- dom/wappush/tests/test_si_pdu_helper.js | 2 +- dom/wappush/tests/test_sl_pdu_helper.js | 2 +- dom/webidl/AudioContext.webidl | 6 +- dom/webidl/PageTransitionEvent.webidl | 11 + dom/webidl/U2F.webidl | 1 + dom/wifi/DOMWifiManager.js | 2 +- dom/wifi/WifiP2pManager.jsm | 6 +- dom/wifi/WifiWorker.js | 37 +- dom/wifi/test/marionette/head.js | 374 ++++++-- dom/wifi/test/marionette/manifest.ini | 10 + .../test_wifi_associate_WPA_EAP_PEAP.js | 623 ++++++++++++++ .../test_wifi_associate_WPA_EAP_TLS.js | 622 ++++++++++++++ .../test_wifi_associate_WPA_EAP_TTLS.js | 623 ++++++++++++++ .../test/marionette/test_wifi_auto_connect.js | 30 +- .../test_wifi_manage_pkcs12_certificate.js | 338 ++++++++ .../test_wifi_manage_server_certificate.js | 106 +++ .../test_wifi_manage_user_certificate.js | 34 + .../test/marionette/test_wifi_static_ip.js | 65 ++ .../test_wifi_tethering_wifi_active.js | 21 +- dom/workers/RuntimeService.cpp | 62 +- dom/workers/ScriptLoader.cpp | 85 +- dom/workers/ServiceWorkerClient.cpp | 27 +- dom/workers/ServiceWorkerRegistrar.cpp | 156 +++- dom/workers/ServiceWorkerRegistrar.h | 4 +- dom/workers/ServiceWorkerRegistration.cpp | 8 + dom/workers/ServiceWorkerScriptCache.cpp | 4 +- dom/workers/SharedWorker.cpp | 1 - dom/workers/WorkerPrivate.cpp | 68 ++ dom/workers/WorkerPrivate.h | 3 + dom/workers/WorkerScope.cpp | 6 +- dom/workers/WorkerScope.h | 2 +- dom/workers/test/browser_bug1047663.js | 50 ++ dom/workers/test/bug1047663_tab.html | 8 + dom/workers/test/bug1047663_worker.sjs | 40 + dom/workers/test/frame_script.js | 72 ++ dom/workers/test/gtest/TestReadWrite.cpp | 205 ++++- dom/workers/test/head.js | 91 ++ .../test/importScripts_3rdParty_worker.js | 82 ++ dom/workers/test/mochitest.ini | 2 + .../test_match_all_client_id.html | 1 + dom/workers/test/sharedWorker_ports.js | 1 + .../test/test_importScripts_3rdparty.html | 134 +++ dom/workers/test/test_sharedWorker_ports.html | 3 + dom/xbl/crashtests/crashtests.list | 4 +- dom/xbl/nsXBLProtoImplField.cpp | 7 +- dom/xbl/nsXBLPrototypeBinding.cpp | 3 +- dom/xbl/nsXBLPrototypeHandler.cpp | 48 +- dom/xbl/nsXBLService.cpp | 19 +- dom/xbl/test/file_bug821850.xhtml | 6 +- dom/xbl/test/test_bug379959.html | 3 - dom/xml/nsXMLContentSink.cpp | 79 +- dom/xml/nsXMLContentSink.h | 9 +- dom/xslt/base/txURIUtils.cpp | 24 + dom/xslt/base/txURIUtils.h | 8 + dom/xslt/nsIXSLTProcessorPrivate.idl | 9 +- dom/xslt/tests/mochitest/file_bug1222624.xml | 4 - dom/xslt/tests/mochitest/file_bug1222624.xsl | 12 - .../tests/mochitest/file_bug1222624_data1.xml | 1 - .../tests/mochitest/file_bug1222624_data2.xml | 1 - .../tests/mochitest/file_bug1222624_sub.xsl | 4 - .../mochitest/file_bug1222624_sub_sub.xsl | 6 - dom/xslt/tests/mochitest/mochitest.ini | 2 - dom/xslt/tests/mochitest/test_bug1222624.html | 50 -- dom/xslt/xml/txXMLParser.cpp | 36 +- dom/xslt/xml/txXMLParser.h | 8 +- dom/xslt/xpath/txMozillaXPathTreeWalker.cpp | 4 +- dom/xslt/xpath/txXPathTreeWalker.h | 2 +- dom/xslt/xslt/txDocumentFunctionCall.cpp | 54 +- dom/xslt/xslt/txExecutionState.cpp | 67 +- dom/xslt/xslt/txExecutionState.h | 23 +- dom/xslt/xslt/txMozillaStylesheetCompiler.cpp | 178 ++-- dom/xslt/xslt/txMozillaXSLTProcessor.cpp | 48 +- dom/xslt/xslt/txMozillaXSLTProcessor.h | 6 +- dom/xslt/xslt/txStylesheetCompileHandlers.cpp | 21 +- dom/xslt/xslt/txStylesheetCompiler.cpp | 189 ++-- dom/xslt/xslt/txStylesheetCompiler.h | 34 +- dom/xslt/xslt/txXSLTFunctions.h | 6 +- editor/libeditor/nsHTMLDataTransfer.cpp | 33 +- editor/libeditor/nsTableEditor.cpp | 6 +- editor/libeditor/nsTextEditRules.cpp | 10 +- editor/libeditor/tests/file_bug915962.html | 7 + editor/libeditor/tests/mochitest.ini | 5 + editor/libeditor/tests/test_bug1247483.html | 61 ++ editor/libeditor/tests/test_bug915962.html | 90 ++ gfx/2d/Logging.h | 1 + gfx/config/gfxConfig.cpp | 223 +++++ gfx/config/gfxConfig.h | 203 +++++ gfx/config/gfxFallback.h | 30 + gfx/config/gfxFeature.cpp | 241 ++++++ gfx/config/gfxFeature.h | 117 +++ gfx/config/moz.build | 18 + gfx/ipc/GraphicsMessages.ipdlh | 2 +- gfx/layers/BufferTexture.cpp | 48 +- gfx/layers/BufferTexture.h | 14 +- gfx/layers/Compositor.h | 14 +- gfx/layers/Layers.h | 2 +- gfx/layers/TextureDIB.cpp | 13 +- gfx/layers/TextureDIB.h | 8 +- gfx/layers/basic/BasicCompositor.cpp | 7 +- gfx/layers/basic/BasicCompositor.h | 7 +- gfx/layers/basic/TextureClientX11.cpp | 10 + gfx/layers/basic/TextureClientX11.h | 8 +- gfx/layers/basic/X11BasicCompositor.h | 2 +- gfx/layers/client/ClientTiledPaintedLayer.cpp | 21 +- gfx/layers/client/ContentClient.cpp | 2 +- .../client/SingleTiledContentClient.cpp | 9 +- gfx/layers/client/SingleTiledContentClient.h | 4 +- gfx/layers/client/TextureClient.cpp | 148 +++- gfx/layers/client/TextureClient.h | 96 ++- .../client/TextureClientSharedSurface.cpp | 11 +- .../client/TextureClientSharedSurface.h | 8 +- gfx/layers/client/TiledContentClient.cpp | 30 +- gfx/layers/client/TiledContentClient.h | 15 +- gfx/layers/composite/ContentHost.h | 4 + .../composite/LayerManagerComposite.cpp | 11 +- .../composite/PaintedLayerComposite.cpp | 11 + gfx/layers/composite/PaintedLayerComposite.h | 2 + gfx/layers/composite/TiledContentHost.cpp | 68 +- gfx/layers/composite/TiledContentHost.h | 12 + gfx/layers/d3d11/CompositorD3D11.cpp | 66 +- gfx/layers/d3d11/CompositorD3D11.h | 9 +- gfx/layers/d3d11/TextureD3D11.cpp | 27 +- gfx/layers/d3d11/TextureD3D11.h | 21 +- gfx/layers/d3d9/CompositorD3D9.cpp | 18 +- gfx/layers/d3d9/CompositorD3D9.h | 8 +- gfx/layers/d3d9/TextureD3D9.cpp | 26 +- gfx/layers/d3d9/TextureD3D9.h | 18 +- gfx/layers/ipc/AsyncTransactionTracker.cpp | 4 + gfx/layers/ipc/CompositorBridgeChild.cpp | 16 +- gfx/layers/ipc/CompositorBridgeParent.cpp | 39 +- gfx/layers/ipc/CompositorBridgeParent.h | 13 +- gfx/layers/ipc/LayerTransactionChild.cpp | 5 +- gfx/layers/ipc/LayersMessages.ipdlh | 2 + .../opengl/CompositingRenderTargetOGL.cpp | 2 +- gfx/layers/opengl/CompositorOGL.cpp | 30 +- gfx/layers/opengl/CompositorOGL.h | 8 +- gfx/layers/opengl/GrallocTextureClient.cpp | 11 + gfx/layers/opengl/GrallocTextureClient.h | 12 +- .../opengl/MacIOSurfaceTextureClientOGL.cpp | 17 +- .../opengl/MacIOSurfaceTextureClientOGL.h | 6 +- gfx/layers/opengl/TextureClientOGL.cpp | 22 + gfx/layers/opengl/TextureClientOGL.h | 21 +- gfx/moz.build | 1 + gfx/src/gfxTelemetry.cpp | 20 +- gfx/src/gfxTelemetry.h | 21 +- gfx/tests/gtest/TestCompositor.cpp | 15 +- gfx/thebes/gfxPlatform.cpp | 192 +++-- gfx/thebes/gfxPlatform.h | 22 +- gfx/thebes/gfxPrefs.h | 9 +- gfx/thebes/gfxUtils.cpp | 3 +- gfx/thebes/gfxWindowsPlatform.cpp | 518 ++++++----- gfx/thebes/gfxWindowsPlatform.h | 31 +- layout/forms/nsMeterFrame.h | 3 +- layout/generic/nsPluginFrame.h | 1 + layout/media/symbols.def.in | 1 + .../signaling/src/jsep/JsepSessionImpl.cpp | 17 +- media/webrtc/signaling/src/jsep/JsepTrack.cpp | 11 - media/webrtc/signaling/src/jsep/JsepTrack.h | 9 +- .../src/media-conduit/AudioConduit.cpp | 25 +- .../src/media-conduit/VideoConduit.cpp | 27 +- .../WebrtcMediaCodecVP8VideoCodec.cpp | 41 +- .../WebrtcMediaCodecVP8VideoCodec.h | 4 +- .../media-conduit/WebrtcOMXH264VideoCodec.cpp | 2 +- .../media-conduit/WebrtcOMXH264VideoCodec.h | 2 +- .../src/mediapipeline/MediaPipeline.cpp | 804 ++++++++++++------ .../src/mediapipeline/MediaPipeline.h | 15 +- .../src/peerconnection/PeerConnectionImpl.cpp | 2 +- .../src/peerconnection/PeerConnectionImpl.h | 2 +- .../peerconnection/PeerConnectionMedia.cpp | 1 + .../webrtc/signaling/src/sdp/SdpAttribute.cpp | 7 +- media/webrtc/signaling/src/sdp/SdpHelper.cpp | 48 +- .../signaling/src/sdp/SdpMediaSection.h | 2 +- media/webrtc/signaling/src/sdp/SipccSdp.cpp | 4 +- .../src/sdp/SipccSdpAttributeList.cpp | 23 +- .../signaling/src/sdp/SipccSdpAttributeList.h | 1 + media/webrtc/signaling/src/sdp/sipcc/sdp.h | 4 + .../webrtc/signaling/src/sdp/sipcc/sdp_attr.c | 43 +- .../signaling/src/sdp/sipcc/sdp_attr_access.c | 39 +- .../webrtc/signaling/src/sdp/sipcc/sdp_main.c | 2 +- .../signaling/src/sdp/sipcc/sdp_private.h | 4 + .../webrtc/signaling/test/FakeMediaStreams.h | 7 +- media/webrtc/signaling/test/FakePCObserver.h | 2 +- .../signaling/test/jsep_session_unittest.cpp | 63 +- media/webrtc/signaling/test/sdp_unittests.cpp | 22 +- media/webrtc/trunk/webrtc/build/common.gypi | 2 +- .../audio_coding/neteq/audio_classifier.cc | 4 +- .../audio_device/win/audio_device_core_win.cc | 3 + .../modules/audio_processing/aec/aec_core.c | 3 + .../desktop_capture/desktop_device_info.cc | 15 + .../win/desktop_device_info_win.cc | 12 + .../desktop_capture/window_capturer_mac.mm | 12 + .../desktop_capture/window_capturer_win.cc | 15 + .../desktop_capture/window_capturer_x11.cc | 10 + .../android/device_info_android.cc | 26 +- .../android/device_info_android.h | 4 +- .../VideoCaptureDeviceInfoAndroid.java | 16 +- .../android/video_capture_android.cc | 2 +- .../video_coding/codecs/vp8/vp8_impl.cc | 4 +- .../video_coding/codecs/vp9/vp9_impl.cc | 14 +- .../video_coding/codecs/vp9/vp9_impl.h | 4 + .../main/source/codec_database.cc | 3 +- .../main/source/generic_encoder.cc | 1 + .../video_coding/main/source/video_sender.cc | 4 + .../main/source/color_enhancement.cc | 6 + .../main/source/color_enhancement_private.h | 4 + .../trunk/webrtc/voice_engine/index.html | 11 - modules/libpref/init/all.js | 4 + parser/htmlparser/nsHTMLTagList.h | 4 +- .../pki/resources/content/exceptionDialog.xul | 46 +- .../manager/pki/resources/content/pippki.js | 53 +- security/manager/tools/makeCNNICHashes.js | 6 +- services/common/async.js | 10 + services/common/logmanager.js | 6 - services/common/rest.js | 5 +- services/sync/modules/engines/bookmarks.js | 104 +-- services/sync/modules/policies.js | 3 +- .../sync/tests/unit/test_bookmark_engine.js | 5 +- .../sync/tests/unit/test_bookmark_invalid.js | 56 +- storage/test/unit/test_js_helpers.js | 2 +- storage/test/unit/test_locale_collation.js | 2 +- .../test/unit/test_statement_executeAsync.js | 6 +- storage/test/unit/test_storage_connection.js | 57 +- storage/test/unit/test_storage_value_array.js | 93 +- storage/test/unit/test_unicode.js | 53 +- storage/test/unit/vacuumParticipant.js | 2 +- widget/CompositorWidgetProxy.cpp | 206 +++++ widget/CompositorWidgetProxy.h | 218 +++++ widget/GfxInfoBase.cpp | 139 ++- widget/GfxInfoBase.h | 5 + widget/PuppetWidget.h | 6 + widget/cocoa/nsChildView.mm | 1 - widget/cocoa/nsCocoaWindow.h | 5 + widget/moz.build | 2 + widget/nsBaseWidget.cpp | 76 +- widget/nsBaseWidget.h | 66 +- widget/nsIGfxInfo.idl | 29 + widget/nsIWidget.h | 113 +-- widget/windows/GfxInfo.cpp | 19 +- widget/windows/nsWindow.cpp | 62 +- widget/windows/nsWindow.h | 5 +- widget/windows/nsWindowGfx.cpp | 183 +--- 314 files changed, 9282 insertions(+), 2943 deletions(-) create mode 100644 dom/base/test/file_bug1263696_frame_fail.html create mode 100644 dom/base/test/file_bug1263696_frame_pass.html create mode 100644 dom/base/test/test_bug1263696.html create mode 100644 dom/media/StreamTracks.cpp create mode 100644 dom/media/StreamTracks.h create mode 100644 dom/tests/mochitest/general/test_spacetopagedown.html create mode 100644 dom/tests/unit/test_geolocation_provider_timeout.js create mode 100644 dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_PEAP.js create mode 100644 dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TLS.js create mode 100644 dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TTLS.js create mode 100644 dom/wifi/test/marionette/test_wifi_manage_pkcs12_certificate.js create mode 100644 dom/wifi/test/marionette/test_wifi_manage_server_certificate.js create mode 100644 dom/wifi/test/marionette/test_wifi_manage_user_certificate.js create mode 100644 dom/wifi/test/marionette/test_wifi_static_ip.js create mode 100644 dom/workers/test/browser_bug1047663.js create mode 100644 dom/workers/test/bug1047663_tab.html create mode 100644 dom/workers/test/bug1047663_worker.sjs create mode 100644 dom/workers/test/frame_script.js create mode 100644 dom/workers/test/head.js create mode 100644 dom/workers/test/importScripts_3rdParty_worker.js create mode 100644 dom/workers/test/test_importScripts_3rdparty.html delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624.xml delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624.xsl delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624_data1.xml delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624_data2.xml delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624_sub.xsl delete mode 100644 dom/xslt/tests/mochitest/file_bug1222624_sub_sub.xsl delete mode 100644 dom/xslt/tests/mochitest/test_bug1222624.html create mode 100644 editor/libeditor/tests/file_bug915962.html create mode 100644 editor/libeditor/tests/test_bug1247483.html create mode 100644 editor/libeditor/tests/test_bug915962.html create mode 100644 gfx/config/gfxConfig.cpp create mode 100644 gfx/config/gfxConfig.h create mode 100644 gfx/config/gfxFallback.h create mode 100644 gfx/config/gfxFeature.cpp create mode 100644 gfx/config/gfxFeature.h create mode 100644 gfx/config/moz.build delete mode 100644 media/webrtc/trunk/webrtc/voice_engine/index.html create mode 100644 widget/CompositorWidgetProxy.cpp create mode 100644 widget/CompositorWidgetProxy.h diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp index 5d7b56f6a4..6fcbe87302 100644 --- a/accessible/atk/AccessibleWrap.cpp +++ b/accessible/atk/AccessibleWrap.cpp @@ -1495,6 +1495,10 @@ a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType) case nsIAccessibleEvent::EVENT_VALUE_CHANGE: g_object_notify((GObject*)wrapper, "accessible-value"); break; + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: + case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: + g_signal_emit_by_name(wrapper, "selection_changed"); + break; } } @@ -1610,6 +1614,13 @@ MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr); } +void +a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t) +{ + MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget)); + g_signal_emit_by_name(obj, "selection_changed"); +} + // static void AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult) diff --git a/accessible/base/Platform.h b/accessible/base/Platform.h index e19d7d69fa..da60a118c4 100644 --- a/accessible/base/Platform.h +++ b/accessible/base/Platform.h @@ -77,6 +77,8 @@ void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr, bool aFromUser); void ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent, bool aInsert, bool aFromUser); +void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget, + uint32_t aType); } // namespace a11y } // namespace mozilla diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index 521ed298e8..4a8c693685 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -885,6 +885,15 @@ Accessible::HandleAccEvent(AccEvent* aEvent) event->IsFromUserInput()); break; } + case nsIAccessibleEvent::EVENT_SELECTION: + case nsIAccessibleEvent::EVENT_SELECTION_ADD: + case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: { + AccSelChangeEvent* selEvent = downcast_accEvent(aEvent); + uint64_t widgetID = selEvent->Widget()->IsDoc() ? 0 : + reinterpret_cast<uintptr_t>(selEvent->Widget()); + ipcDoc->SendSelectionEvent(id, widgetID, aEvent->GetEventType()); + break; + } default: ipcDoc->SendEvent(id, aEvent->GetEventType()); } diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index f04b2cbb85..451fd624a9 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -259,6 +259,31 @@ DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID, return true; } +bool +DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID, + const uint64_t& aWidgetID, + const uint32_t& aType) +{ + ProxyAccessible* target = GetAccessible(aID); + ProxyAccessible* widget = GetAccessible(aWidgetID); + if (!target || !widget) { + NS_ERROR("invalid id in selection event"); + return true; + } + + ProxySelectionEvent(target, widget, aType); + if (!nsCoreUtils::AccEventObserversExist()) { + return true; + } + xpcAccessibleGeneric* xpcTarget = GetXPCAccessible(target); + xpcAccessibleDocument* xpcDoc = GetAccService()->GetXPCDocument(this); + RefPtr<xpcAccEvent> event = new xpcAccEvent(aType, xpcTarget, xpcDoc, + nullptr, false); + nsCoreUtils::DispatchAccEvent(Move(event)); + + return true; +} + bool DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) { diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h index 0240a312aa..0fa527cee8 100644 --- a/accessible/ipc/DocAccessibleParent.h +++ b/accessible/ipc/DocAccessibleParent.h @@ -64,6 +64,10 @@ class DocAccessibleParent : public ProxyAccessible, const bool& aIsInsert, const bool& aFromUser) override; + virtual bool RecvSelectionEvent(const uint64_t& aID, + const uint64_t& aWidgetID, + const uint32_t& aType) override; + virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override; void Unbind() { diff --git a/accessible/ipc/PDocAccessible.ipdl b/accessible/ipc/PDocAccessible.ipdl index ba901ca9ed..2d7e6f485a 100644 --- a/accessible/ipc/PDocAccessible.ipdl +++ b/accessible/ipc/PDocAccessible.ipdl @@ -61,6 +61,7 @@ parent: async CaretMoveEvent(uint64_t aID, int32_t aOffset); async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen, bool aIsInsert, bool aFromUser); + async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType); /* * Tell the parent document to bind the existing document as a new child diff --git a/accessible/mac/Platform.mm b/accessible/mac/Platform.mm index f4f546e519..2b8fa58752 100644 --- a/accessible/mac/Platform.mm +++ b/accessible/mac/Platform.mm @@ -106,6 +106,11 @@ ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool) { } + +void +ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t) +{ +} } // namespace a11y } // namespace mozilla diff --git a/accessible/other/Platform.cpp b/accessible/other/Platform.cpp index 7a63094d52..6f4527a78d 100644 --- a/accessible/other/Platform.cpp +++ b/accessible/other/Platform.cpp @@ -54,3 +54,8 @@ void a11y::ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool) { } + +void +a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t) +{ +} diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index ec2be3a7a6..ab66ccd91c 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -127,3 +127,10 @@ a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible*, bool aInser AccessibleWrap* wrapper = WrapperFor(aTarget); AccessibleWrap::FireWinEvent(wrapper, event); } + +void +a11y::ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible*, uint32_t aType) +{ + AccessibleWrap* wrapper = WrapperFor(aTarget); + AccessibleWrap::FireWinEvent(wrapper, aType); +} diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index c37ef5e9ff..1ae3d86dc4 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -86,6 +86,7 @@ #include "mozilla/EventStates.h" #include "mozilla/Telemetry.h" #include "mozilla/dom/HTMLObjectElementBinding.h" +#include "mozilla/dom/HTMLSharedObjectElement.h" #ifdef XP_WIN // Thanks so much, Microsoft! :( @@ -2969,24 +2970,35 @@ nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) { aType = eFallbackAlternate; } + // We'll set this to null no matter what now, doing it here means we'll load + // child embeds as we find them in the upcoming loop. + mType = eType_Null; + + // Do a breadth-first traverse of node tree with the current element as root, + // looking for the first embed we can find. + nsTArray<nsINodeList*> childNodes; if ((thisContent->IsHTMLElement(nsGkAtoms::object) || thisContent->IsHTMLElement(nsGkAtoms::applet)) && (aType == eFallbackUnsupported || aType == eFallbackDisabled || aType == eFallbackBlocklisted)) { - // Show alternate content instead, if it exists - for (nsIContent* child = thisContent->GetFirstChild(); - child; child = child->GetNextSibling()) { - if (!child->IsHTMLElement(nsGkAtoms::param) && + for (nsIContent* child = thisContent->GetFirstChild(); child; + child = child->GetNextNode(thisContent)) { + if (aType != eFallbackAlternate && + !child->IsHTMLElement(nsGkAtoms::param) && nsStyleUtil::IsSignificantChild(child, true, false)) { aType = eFallbackAlternate; - break; + } + if (child->IsHTMLElement(nsGkAtoms::embed)) { + HTMLSharedObjectElement* object = static_cast<HTMLSharedObjectElement*>(child); + if (object) { + object->StartObjectLoad(true, true); + } } } } - mType = eType_Null; mFallbackType = aType; // Notify diff --git a/dom/base/test/file_bug1263696_frame_fail.html b/dom/base/test/file_bug1263696_frame_fail.html new file mode 100644 index 0000000000..b45561aa6f --- /dev/null +++ b/dom/base/test/file_bug1263696_frame_fail.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/REC-html401-19991224/strict.dtd"> +<html> + <head> + <title>Bug 1263696 - iframe that should not be loaded</title> + </head> + <body> + <script> + parent.SimpleTest.ok(false, "this iframe should not load"); + </script> + </body> +</html> diff --git a/dom/base/test/file_bug1263696_frame_pass.html b/dom/base/test/file_bug1263696_frame_pass.html new file mode 100644 index 0000000000..7f49d6541c --- /dev/null +++ b/dom/base/test/file_bug1263696_frame_pass.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/REC-html401-19991224/strict.dtd"> +<html> + <head> + <title>Bug 1263696 - iframe that should be loaded</title> + </head> + <body> + <script> + parent.index = parent.index + 1; + parent.SimpleTest.ok(true, "this iframe should load"); + </script> + </body> +</html> diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 186c9a4462..cf3980e02c 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -154,6 +154,8 @@ support-files = file_bug902350_frame.html file_bug907892.html file_bug945152.jar + file_bug1263696_frame_pass.html + file_bug1263696_frame_fail.html file_general_document.html file_html_in_xhr.html file_html_in_xhr.sjs @@ -854,3 +856,4 @@ skip-if = buildapp == 'b2g' #no ssl support [test_document_register.html] [test_bug962251.html] [test_bug1259588.html] +[test_bug1263696.html] diff --git a/dom/base/test/test_bug1263696.html b/dom/base/test/test_bug1263696.html new file mode 100644 index 0000000000..289a26ba4f --- /dev/null +++ b/dom/base/test/test_bug1263696.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html> + <head> + <meta><charset="utf-8"/> + <title>Test Embed/Object Node Conflicts</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="plugin-utils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + var index = 0; + function startTest() { + is(index, 12, "Should have loaded all passing frames."); + SimpleTest.finish(); + } + </script> + </head> + <body onload="startTest()"> + <object data="file_bug1263696_frame_pass.html" style="width: 100px; height: 100px"> + <embed type="text/html" src="file_bug1263696_frame_fail.html" /> + </object> + <object style="width: 100px; height: 100px" data="data:application/x-does-not-exist,test"> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + </object> + <object style="width: 100px; height: 100px" data="data:application/x-does-not-exist,test"> + <div></div> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + </object> + <object style="width: 100px; height: 100px" data="data:application/x-does-not-exist,test"> + <div> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + </div> + </object> + <object style="width: 100px; height: 100px" data="data:application/x-does-not-exist,test"> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + <object data="file_bug1263696_frame_pass.html"> + <embed type="text/html" src="file_bug1263696_frame_fail.html" /> + </object> + <object data="data:application/x-does-not-exist,test"> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + </object> + </object> + <div> + <object data="file_bug1263696_frame_pass.html" style="width: 100px; height: 100px"></object> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + </div> + <div> + <embed type="text/html" src="file_bug1263696_frame_pass.html" /> + <object data="file_bug1263696_frame_pass.html" style="width: 100px; height: 100px"></object> + </div> + </body> +</html> diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 604bf8bb12..90c71ff66f 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2008,7 +2008,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded, OutputMediaStream* out = mOutputStreams.AppendElement(); MediaStreamTrackSourceGetter* getter = new CaptureStreamTrackSourceGetter(this); - out->mStream = DOMMediaStream::CreateTrackUnionStream(window, aGraph, getter); + out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter); out->mFinishWhenEnded = aFinishWhenEnded; mAudioCaptured = true; diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h index 1a67c94fee..ade8b2e6ec 100644 --- a/dom/html/HTMLObjectElement.h +++ b/dom/html/HTMLObjectElement.h @@ -28,6 +28,7 @@ class HTMLObjectElement final : public nsGenericHTMLFormElement // nsISupports NS_DECL_ISUPPORTS_INHERITED + NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLObjectElement, object) virtual int32_t TabIndexDefault() override; #ifdef XP_MACOSX diff --git a/dom/html/HTMLPreElement.cpp b/dom/html/HTMLPreElement.cpp index d3a7ad6602..8c46ed934b 100644 --- a/dom/html/HTMLPreElement.cpp +++ b/dom/html/HTMLPreElement.cpp @@ -64,6 +64,10 @@ HTMLPreElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes, NS_IMETHODIMP_(bool) HTMLPreElement::IsAttributeMapped(const nsIAtom* aAttribute) const { + if (!mNodeInfo->Equals(nsGkAtoms::pre)) { + return nsGenericHTMLElement::IsAttributeMapped(aAttribute); + } + static const MappedAttributeEntry attributes[] = { { &nsGkAtoms::wrap }, { nullptr }, @@ -80,6 +84,10 @@ HTMLPreElement::IsAttributeMapped(const nsIAtom* aAttribute) const nsMapRuleToAttributesFunc HTMLPreElement::GetAttributeMappingFunction() const { + if (!mNodeInfo->Equals(nsGkAtoms::pre)) { + return nsGenericHTMLElement::GetAttributeMappingFunction(); + } + return &MapAttributesIntoRule; } diff --git a/dom/html/HTMLSharedElement.cpp b/dom/html/HTMLSharedElement.cpp index 0fd60c34be..bcb84d29b2 100644 --- a/dom/html/HTMLSharedElement.cpp +++ b/dom/html/HTMLSharedElement.cpp @@ -62,13 +62,15 @@ NS_IMPL_STRING_ATTR(HTMLSharedElement, Target, target) NS_IMETHODIMP HTMLSharedElement::GetHref(nsAString& aValue) { + MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base), + "This should only get called for <base> elements"); nsAutoString href; GetAttr(kNameSpaceID_None, nsGkAtoms::href, href); nsCOMPtr<nsIURI> uri; nsIDocument* doc = OwnerDoc(); nsContentUtils::NewURIWithDocumentCharset( - getter_AddRefs(uri), href, doc, doc->GetDocumentURI()); + getter_AddRefs(uri), href, doc, doc->GetFallbackBaseURI()); if (!uri) { aValue = href; diff --git a/dom/html/HTMLSharedObjectElement.cpp b/dom/html/HTMLSharedObjectElement.cpp index eac747e25b..9d28b48165 100644 --- a/dom/html/HTMLSharedObjectElement.cpp +++ b/dom/html/HTMLSharedObjectElement.cpp @@ -20,8 +20,9 @@ #ifdef XP_MACOSX #include "mozilla/EventDispatcher.h" #include "mozilla/dom/Event.h" -#include "mozilla/dom/HTMLObjectElement.h" #endif +#include "mozilla/dom/HTMLObjectElement.h" + NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(SharedObject) @@ -84,7 +85,7 @@ HTMLSharedObjectElement::DoneAddingChildren(bool aHaveNotified) // If we're already in a document, we need to trigger the load // Otherwise, BindToTree takes care of that. if (IsInComposedDoc()) { - StartObjectLoad(aHaveNotified); + StartObjectLoad(aHaveNotified, false); } } } @@ -192,7 +193,8 @@ HTMLSharedObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName, // a document, just in case that the caller wants to set additional // attributes before inserting the node into the document. if (aNotify && IsInComposedDoc() && mIsDoneAddingChildren && - aNameSpaceID == kNameSpaceID_None && aName == URIAttrName()) { + aNameSpaceID == kNameSpaceID_None && aName == URIAttrName() + && !BlockEmbedContentLoading()) { return LoadObject(aNotify, true); } @@ -320,15 +322,16 @@ HTMLSharedObjectElement::GetAttributeMappingFunction() const } void -HTMLSharedObjectElement::StartObjectLoad(bool aNotify) +HTMLSharedObjectElement::StartObjectLoad(bool aNotify, bool aForceLoad) { // BindToTree can call us asynchronously, and we may be removed from the tree // in the interim - if (!IsInComposedDoc() || !OwnerDoc()->IsActive()) { + if (!IsInComposedDoc() || !OwnerDoc()->IsActive() || + BlockEmbedContentLoading()) { return; } - LoadObject(aNotify); + LoadObject(aNotify, aForceLoad); SetIsNetworkCreated(false); } @@ -400,5 +403,31 @@ HTMLSharedObjectElement::GetContentPolicyType() const } } +bool +HTMLSharedObjectElement::BlockEmbedContentLoading() +{ + // Only check on embed elements + if (!IsHTMLElement(nsGkAtoms::embed)) { + return false; + } + // Traverse up the node tree to see if we have any ancestors that may block us + // from loading + for (nsIContent* parent = GetParent(); parent; parent = parent->GetParent()) { + if (parent->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) { + return true; + } + // If we have an ancestor that is an object with a source, it'll have an + // associated displayed type. If that type is not null, don't load content + // for the embed. + if (HTMLObjectElement* object = HTMLObjectElement::FromContent(parent)) { + uint32_t type = object->DisplayedType(); + if (type != eType_Null) { + return true; + } + } + } + return false; +} + } // namespace dom } // namespace mozilla diff --git a/dom/html/HTMLSharedObjectElement.h b/dom/html/HTMLSharedObjectElement.h index 11d9ba1b1b..0d6ed60ef0 100644 --- a/dom/html/HTMLSharedObjectElement.h +++ b/dom/html/HTMLSharedObjectElement.h @@ -80,7 +80,7 @@ class HTMLSharedObjectElement final : public nsGenericHTMLElement nsresult CopyInnerTo(Element* aDest); - void StartObjectLoad() { StartObjectLoad(true); } + void StartObjectLoad() { StartObjectLoad(true, false); } NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLSharedObjectElement, nsGenericHTMLElement) @@ -192,6 +192,11 @@ class HTMLSharedObjectElement final : public nsGenericHTMLElement return GetContentDocument(); } + /** + * Calls LoadObject with the correct arguments to start the plugin load. + */ + void StartObjectLoad(bool aNotify, bool aForceLoad); + protected: // Override for nsImageLoadingContent. nsIContent* AsContent() override { return this; } @@ -199,11 +204,6 @@ class HTMLSharedObjectElement final : public nsGenericHTMLElement private: virtual ~HTMLSharedObjectElement(); - /** - * Calls LoadObject with the correct arguments to start the plugin load. - */ - void StartObjectLoad(bool aNotify); - nsIAtom *URIAttrName() const { return mNodeInfo->Equals(nsGkAtoms::applet) ? @@ -224,6 +224,21 @@ class HTMLSharedObjectElement final : public nsGenericHTMLElement static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData); + + /** + * Decides whether we should load embed node content. + * + * If this is an embed node there are cases in which we should not try to load + * the content: + * + * - If the embed node is the child of a media element + * - If the embed node is the child of an object node that already has + * content being loaded. + * + * In these cases, this function will return false, which will cause + * us to skip calling LoadObject. + */ + bool BlockEmbedContentLoading(); }; } // namespace dom diff --git a/dom/html/test/test_bug389797.html b/dom/html/test/test_bug389797.html index d7e46d9233..60556224ce 100644 --- a/dom/html/test/test_bug389797.html +++ b/dom/html/test/test_bug389797.html @@ -166,7 +166,7 @@ HTML_TAG("legend", "Legend"); HTML_TAG("li", "LI"); HTML_TAG("link", "Link"); -HTML_TAG("listing", ""); +HTML_TAG("listing", "Pre"); HTML_TAG("main", ""); HTML_TAG("map", "Map"); HTML_TAG("mark", ""); @@ -223,7 +223,7 @@ HTML_TAG("ul", "UList"); HTML_TAG("var", ""); HTML_TAG("wbr", ""); -HTML_TAG("xmp", ""); +HTML_TAG("xmp", "Pre"); function tagName(aTag) { return "<" + aTag + ">"; diff --git a/dom/inputport/InputPort.cpp b/dom/inputport/InputPort.cpp index 63119af2d8..867c4d99ab 100644 --- a/dom/inputport/InputPort.cpp +++ b/dom/inputport/InputPort.cpp @@ -64,7 +64,7 @@ InputPort::Init(nsIInputPortData* aData, nsIInputPortListener* aListener, ErrorR MediaStreamGraph* graph = MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER, AudioChannel::Normal); - mStream = DOMMediaStream::CreateSourceStream(GetOwner(), graph); + mStream = DOMMediaStream::CreateSourceStreamAsInput(GetOwner(), graph); } void diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 9420442a0d..f126a4b96c 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -173,8 +173,8 @@ XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents tha IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation. # LOCALIZATION NOTE: Do not translate Will-change, %1$S,%2$S are numbers. IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored. -# LOCALIZATION NOTE: Do not translate "ServiceWorker". -HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed. +# LOCALIZATION NOTE: Do not translate "Worker". +HittingMaxWorkersPerDomain2=A Worker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The Worker is now queued and will be started after some of the other workers have completed. # LOCALIZATION NOTE: Do not translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor" PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features # LOCALIZATION NOTE: Do not translate "Application Cache API", "AppCache" and "ServiceWorker". diff --git a/dom/media/AudioCaptureStream.cpp b/dom/media/AudioCaptureStream.cpp index 96a0903d81..565cebd69f 100644 --- a/dom/media/AudioCaptureStream.cpp +++ b/dom/media/AudioCaptureStream.cpp @@ -71,7 +71,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, } uint32_t inputCount = mInputs.Length(); - StreamBuffer::Track* track = EnsureTrack(mTrackId); + StreamTracks::Track* track = EnsureTrack(mTrackId); // Notify the DOM everything is in order. if (!mTrackCreated) { for (uint32_t i = 0; i < mListeners.Length(); i++) { @@ -101,7 +101,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, AudioSegment output; for (uint32_t i = 0; i < inputCount; i++) { MediaStream* s = mInputs[i]->GetSource(); - StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO); + StreamTracks::TrackIter tracks(s->GetStreamTracks(), MediaSegment::AUDIO); while (!tracks.IsEnded()) { AudioSegment* inputSegment = tracks->Get<AudioSegment>(); StreamTime inputStart = s->GraphTimeToStreamTimeWithBlocking(aFrom); @@ -121,7 +121,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo, } // Regardless of the status of the input tracks, we go foward. - mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo))); + mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo))); } void diff --git a/dom/media/AudioCaptureStream.h b/dom/media/AudioCaptureStream.h index 27dab3aef5..ee37c26426 100644 --- a/dom/media/AudioCaptureStream.h +++ b/dom/media/AudioCaptureStream.h @@ -8,7 +8,7 @@ #include "MediaStreamGraph.h" #include "AudioMixer.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include <algorithm> namespace mozilla diff --git a/dom/media/CanvasCaptureMediaStream.h b/dom/media/CanvasCaptureMediaStream.h index 72209cf45a..254d1ad39d 100644 --- a/dom/media/CanvasCaptureMediaStream.h +++ b/dom/media/CanvasCaptureMediaStream.h @@ -8,7 +8,7 @@ #include "DOMMediaStream.h" #include "mozilla/dom/HTMLCanvasElement.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" class nsIPrincipal; diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 0308d042a1..7076936071 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -853,9 +853,9 @@ DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph) } already_AddRefed<DOMMediaStream> -DOMMediaStream::CreateSourceStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter) +DOMMediaStream::CreateSourceStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter) { RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter); stream->InitSourceStream(aGraph); @@ -863,9 +863,9 @@ DOMMediaStream::CreateSourceStream(nsPIDOMWindow* aWindow, } already_AddRefed<DOMMediaStream> -DOMMediaStream::CreateTrackUnionStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter) +DOMMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter) { RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter); stream->InitTrackUnionStream(aGraph); @@ -873,9 +873,9 @@ DOMMediaStream::CreateTrackUnionStream(nsPIDOMWindow* aWindow, } already_AddRefed<DOMMediaStream> -DOMMediaStream::CreateAudioCaptureStream(nsPIDOMWindow* aWindow, - nsIPrincipal* aPrincipal, - MediaStreamGraph* aGraph) +DOMMediaStream::CreateAudioCaptureStreamAsInput(nsPIDOMWindow* aWindow, + nsIPrincipal* aPrincipal, + MediaStreamGraph* aGraph) { // Audio capture doesn't create tracks dynamically MediaStreamTrackSourceGetter* getter = nullptr; @@ -1300,9 +1300,9 @@ DOMLocalMediaStream::StopImpl() } already_AddRefed<DOMLocalMediaStream> -DOMLocalMediaStream::CreateSourceStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter) +DOMLocalMediaStream::CreateSourceStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter) { RefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream(aWindow, aTrackSourceGetter); @@ -1311,9 +1311,9 @@ DOMLocalMediaStream::CreateSourceStream(nsPIDOMWindow* aWindow, } already_AddRefed<DOMLocalMediaStream> -DOMLocalMediaStream::CreateTrackUnionStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter) +DOMLocalMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter) { RefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream(aWindow, aTrackSourceGetter); @@ -1332,9 +1332,9 @@ DOMAudioNodeMediaStream::~DOMAudioNodeMediaStream() } already_AddRefed<DOMAudioNodeMediaStream> -DOMAudioNodeMediaStream::CreateTrackUnionStream(nsPIDOMWindow* aWindow, - AudioNode* aNode, - MediaStreamGraph* aGraph) +DOMAudioNodeMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + AudioNode* aNode, + MediaStreamGraph* aGraph) { RefPtr<DOMAudioNodeMediaStream> stream = new DOMAudioNodeMediaStream(aWindow, aNode); stream->InitTrackUnionStream(aGraph); @@ -1443,7 +1443,7 @@ DOMHwMediaStream::SetImageSize(uint32_t width, uint32_t height) #endif SourceMediaStream* srcStream = GetInputStream()->AsSourceStream(); - StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY); + StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY); if (!track || !track->GetSegment()) { return; @@ -1479,7 +1479,7 @@ DOMHwMediaStream::SetOverlayImage(OverlayImage* aImage) #endif SourceMediaStream* srcStream = GetInputStream()->AsSourceStream(); - StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY); + StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY); if (!track || !track->GetSegment()) { return; diff --git a/dom/media/DOMMediaStream.h b/dom/media/DOMMediaStream.h index 57d0e7a73a..8e24d77b99 100644 --- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -10,7 +10,7 @@ #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "nsIDOMWindow.h" #include "nsIPrincipal.h" #include "mozilla/DOMEventTargetHelper.h" @@ -484,25 +484,25 @@ class DOMMediaStream : public DOMEventTargetHelper, /** * Create a DOMMediaStream whose underlying input stream is a SourceMediaStream. */ - static already_AddRefed<DOMMediaStream> CreateSourceStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); + static already_AddRefed<DOMMediaStream> CreateSourceStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); /** * Create a DOMMediaStream whose underlying input stream is a TrackUnionStream. */ - static already_AddRefed<DOMMediaStream> CreateTrackUnionStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); + static already_AddRefed<DOMMediaStream> CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); /** * Create an DOMMediaStream whose underlying input stream is an * AudioCaptureStream. */ static already_AddRefed<DOMMediaStream> - CreateAudioCaptureStream(nsPIDOMWindow* aWindow, - nsIPrincipal* aPrincipal, - MediaStreamGraph* aGraph); + CreateAudioCaptureStreamAsInput(nsPIDOMWindow* aWindow, + nsIPrincipal* aPrincipal, + MediaStreamGraph* aGraph); void SetLogicalStreamStartTime(StreamTime aTime) { @@ -719,17 +719,17 @@ class DOMLocalMediaStream : public DOMMediaStream * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream. */ static already_AddRefed<DOMLocalMediaStream> - CreateSourceStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); + CreateSourceStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); /** * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream. */ static already_AddRefed<DOMLocalMediaStream> - CreateTrackUnionStream(nsPIDOMWindow* aWindow, - MediaStreamGraph* aGraph, - MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); + CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + MediaStreamGraph* aGraph, + MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr); protected: virtual ~DOMLocalMediaStream(); @@ -753,9 +753,9 @@ class DOMAudioNodeMediaStream : public DOMMediaStream * Create a DOMAudioNodeMediaStream whose underlying stream is a TrackUnionStream. */ static already_AddRefed<DOMAudioNodeMediaStream> - CreateTrackUnionStream(nsPIDOMWindow* aWindow, - AudioNode* aNode, - MediaStreamGraph* aGraph); + CreateTrackUnionStreamAsInput(nsPIDOMWindow* aWindow, + AudioNode* aNode, + MediaStreamGraph* aGraph); protected: ~DOMAudioNodeMediaStream(); diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index 5b69c70a3b..a1ebd58fa4 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -14,7 +14,7 @@ #include "nsTArray.h" #include "ImageTypes.h" #include "MediaData.h" -#include "StreamBuffer.h" // for TrackID +#include "StreamTracks.h" // for TrackID #include "TimeUnits.h" namespace mozilla { diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 0963b871d2..cd2bf29016 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -835,7 +835,7 @@ class GetUserMediaStreamRunnable : public Runnable // not a problem here, we got explicit user content. nsCOMPtr<nsIPrincipal> principal = window->GetExtantDoc()->NodePrincipal(); domStream = - DOMMediaStream::CreateAudioCaptureStream(window, principal, msg); + DOMMediaStream::CreateAudioCaptureStreamAsInput(window, principal, msg); stream = msg->CreateSourceStream(nullptr); // Placeholder msg->RegisterCaptureStreamForWindow( @@ -921,8 +921,8 @@ class GetUserMediaStreamRunnable : public Runnable // avoid us blocking. Pass a simple TrackSourceGetter for potential // fake tracks. Apart from them gUM never adds tracks dynamically. domStream = - DOMLocalMediaStream::CreateSourceStream(window, msg, - new FakeTrackSourceGetter(principal)); + DOMLocalMediaStream::CreateSourceStreamAsInput(window, msg, + new FakeTrackSourceGetter(principal)); if (mAudioDevice) { nsString audioDeviceName; diff --git a/dom/media/MediaSegment.h b/dom/media/MediaSegment.h index 31c2f74c01..7c7c17d001 100644 --- a/dom/media/MediaSegment.h +++ b/dom/media/MediaSegment.h @@ -45,7 +45,7 @@ typedef int64_t MediaTime; const int64_t MEDIA_TIME_MAX = TRACK_TICKS_MAX; /** - * Media time relative to the start of a StreamBuffer. + * Media time relative to the start of a StreamTracks. */ typedef MediaTime StreamTime; const StreamTime STREAM_TIME_MAX = MEDIA_TIME_MAX; diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 772ff253b0..a796e04c0f 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -101,7 +101,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream) return; STREAM_LOG(LogLevel::Debug, ("MediaStream %p will finish", aStream)); #ifdef DEBUG - for (StreamBuffer::TrackIter track(aStream->mBuffer); + for (StreamTracks::TrackIter track(aStream->mTracks); !track.IsEnded(); track.Next()) { if (!track->IsEnded()) { STREAM_LOG(LogLevel::Error, @@ -112,7 +112,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream) } #endif aStream->mFinished = true; - aStream->mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX); + aStream->mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX); SetStreamOrderDirty(); } @@ -120,7 +120,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream) void MediaStreamGraphImpl::AddStreamGraphThread(MediaStream* aStream) { - aStream->mBufferStartTime = mProcessedTime; + aStream->mTracksStartTime = mProcessedTime; if (aStream->IsSuspended()) { mSuspendedStreams.AppendElement(aStream); STREAM_LOG(LogLevel::Debug, ("Adding media stream %p to the graph, in the suspended stream array", aStream)); @@ -180,14 +180,14 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, StreamTime t = aStream->GraphTimeToStreamTime(aDesiredUpToTime); STREAM_LOG(LogLevel::Verbose, ("Calling NotifyPull aStream=%p t=%f current end=%f", aStream, MediaTimeToSeconds(t), - MediaTimeToSeconds(aStream->mBuffer.GetEnd()))); - if (t > aStream->mBuffer.GetEnd()) { + MediaTimeToSeconds(aStream->mTracks.GetEnd()))); + if (t > aStream->mTracks.GetEnd()) { *aEnsureNextIteration = true; #ifdef DEBUG if (aStream->mListeners.Length() == 0) { STREAM_LOG(LogLevel::Error, ("No listeners in NotifyPull aStream=%p desired=%f current end=%f", aStream, MediaTimeToSeconds(t), - MediaTimeToSeconds(aStream->mBuffer.GetEnd()))); + MediaTimeToSeconds(aStream->mTracks.GetEnd()))); aStream->DumpTrackInfo(); } #endif @@ -206,7 +206,7 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, SourceMediaStream::TrackData* data = &aStream->mUpdateTracks[i]; aStream->ApplyTrackDisabling(data->mID, data->mData); StreamTime offset = (data->mCommands & SourceMediaStream::TRACK_CREATE) - ? data->mStart : aStream->mBuffer.FindTrack(data->mID)->GetSegment()->GetDuration(); + ? data->mStart : aStream->mTracks.FindTrack(data->mID)->GetSegment()->GetDuration(); for (MediaStreamListener* l : aStream->mListeners) { l->NotifyQueuedTrackChanges(this, data->mID, offset, data->mCommands, *data->mData); @@ -227,14 +227,14 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, int64_t(segment->GetDuration()))); data->mEndOfFlushedData += segment->GetDuration(); - aStream->mBuffer.AddTrack(data->mID, data->mStart, segment); + aStream->mTracks.AddTrack(data->mID, data->mStart, segment); // The track has taken ownership of data->mData, so let's replace // data->mData with an empty clone. data->mData = segment->CreateEmptyClone(); data->mCommands &= ~SourceMediaStream::TRACK_CREATE; notifiedTrackCreated = true; } else if (data->mData->GetDuration() > 0) { - MediaSegment* dest = aStream->mBuffer.FindTrack(data->mID)->GetSegment(); + MediaSegment* dest = aStream->mTracks.FindTrack(data->mID)->GetSegment(); STREAM_LOG(LogLevel::Verbose, ("SourceMediaStream %p track %d, advancing end from %lld to %lld", aStream, data->mID, int64_t(dest->GetDuration()), @@ -243,7 +243,7 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, dest->AppendFrom(data->mData); } if (data->mCommands & SourceMediaStream::TRACK_END) { - aStream->mBuffer.FindTrack(data->mID)->SetEnded(); + aStream->mTracks.FindTrack(data->mID)->SetEnded(); aStream->mUpdateTracks.RemoveElementAt(i); } } @@ -253,10 +253,10 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, } } if (!aStream->mFinished) { - aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime); + aStream->mTracks.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime); } } - if (aStream->mBuffer.GetEnd() > 0) { + if (aStream->mTracks.GetEnd() > 0) { aStream->mHasCurrentData = true; } if (finished) { @@ -271,7 +271,7 @@ MediaStreamGraphImpl::GraphTimeToStreamTimeWithBlocking(MediaStream* aStream, MOZ_ASSERT(aTime <= mStateComputedTime, "Don't ask about times where we haven't made blocking decisions yet"); return std::max<StreamTime>(0, - std::min(aTime, aStream->mStartBlocking) - aStream->mBufferStartTime); + std::min(aTime, aStream->mStartBlocking) - aStream->mTracksStartTime); } GraphTime @@ -294,7 +294,7 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime) blockedTime); STREAM_LOG(LogLevel::Verbose, ("MediaStream %p bufferStartTime=%f blockedTime=%f", stream, - MediaTimeToSeconds(stream->mBufferStartTime), + MediaTimeToSeconds(stream->mTracksStartTime), MediaTimeToSeconds(blockedTime))); stream->mStartBlocking = mStateComputedTime; @@ -326,7 +326,7 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime) // out. if (stream->mFinished && !stream->mNotifiedFinished && mProcessedTime >= - stream->StreamTimeToGraphTime(stream->GetStreamBuffer().GetAllTracksEnd())) { + stream->StreamTimeToGraphTime(stream->GetStreamTracks().GetAllTracksEnd())) { stream->mNotifiedFinished = true; SetStreamOrderDirty(); for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) { @@ -382,7 +382,7 @@ MediaStreamGraphImpl::ProcessChunkMetadata(GraphTime aPrevCurrentTime) for (MediaStream* stream : AllStreams()) { StreamTime iterationStart = stream->GraphTimeToStreamTime(aPrevCurrentTime); StreamTime iterationEnd = stream->GraphTimeToStreamTime(mProcessedTime); - for (StreamBuffer::TrackIter tracks(stream->mBuffer); + for (StreamTracks::TrackIter tracks(stream->mTracks); !tracks.IsEnded(); tracks.Next()) { MediaSegment* segment = tracks->GetSegment(); if (!segment) { @@ -416,13 +416,13 @@ MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream, // This stream isn't finished or suspended. We don't need to call // StreamTimeToGraphTime since an underrun is the only thing that can block // it. - GraphTime bufferEnd = aStream->GetBufferEnd() + aStream->mBufferStartTime; + GraphTime bufferEnd = aStream->GetTracksEnd() + aStream->mTracksStartTime; #ifdef DEBUG if (bufferEnd < mProcessedTime) { STREAM_LOG(LogLevel::Error, ("MediaStream %p underrun, " "bufferEnd %f < mProcessedTime %f (%lld < %lld), Streamtime %lld", aStream, MediaTimeToSeconds(bufferEnd), MediaTimeToSeconds(mProcessedTime), - bufferEnd, mProcessedTime, aStream->GetBufferEnd())); + bufferEnd, mProcessedTime, aStream->GetTracksEnd())); aStream->DumpTrackInfo(); NS_ASSERTION(bufferEnd >= mProcessedTime, "Buffer underran"); } @@ -455,7 +455,7 @@ MediaStreamGraphImpl::AudioTrackPresent(bool& aNeedsAEC) if (stream->AsAudioNodeStream()) { audioTrackPresent = true; } else { - for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer(), MediaSegment::AUDIO); + for (StreamTracks::TrackIter tracks(stream->GetStreamTracks(), MediaSegment::AUDIO); !tracks.IsEnded(); tracks.Next()) { audioTrackPresent = true; } @@ -749,7 +749,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream) return; } - if (!aStream->GetStreamBuffer().GetAndResetTracksDirty() && + if (!aStream->GetStreamTracks().GetAndResetTracksDirty() && !aStream->mAudioOutputStreams.IsEmpty()) { return; } @@ -761,7 +761,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream) audioOutputStreamsFound.AppendElement(false); } - for (StreamBuffer::TrackIter tracks(aStream->GetStreamBuffer(), MediaSegment::AUDIO); + for (StreamTracks::TrackIter tracks(aStream->GetStreamTracks(), MediaSegment::AUDIO); !tracks.IsEnded(); tracks.Next()) { uint32_t i; for (i = 0; i < audioOutputStreamsFound.Length(); ++i) { @@ -820,13 +820,13 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream) ticksWritten = 0; MediaStream::AudioOutputStream& audioOutput = aStream->mAudioOutputStreams[i]; - StreamBuffer::Track* track = aStream->mBuffer.FindTrack(audioOutput.mTrackID); + StreamTracks::Track* track = aStream->mTracks.FindTrack(audioOutput.mTrackID); AudioSegment* audio = track->Get<AudioSegment>(); AudioSegment output; StreamTime offset = aStream->GraphTimeToStreamTime(mProcessedTime); - // We don't update aStream->mBufferStartTime here to account for time spent + // We don't update aStream->mTracksStartTime here to account for time spent // blocked. Instead, we'll update it in UpdateCurrentTimeForStreams after // the blocked period has completed. But we do need to make sure we play // from the right offsets in the stream buffer, even if we've already @@ -945,7 +945,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream) PrincipalHandle lastPrincipalHandle = PRINCIPAL_HANDLE_NONE; RefPtr<Image> blackImage; - MOZ_ASSERT(mProcessedTime >= aStream->mBufferStartTime, "frame position before buffer?"); + MOZ_ASSERT(mProcessedTime >= aStream->mTracksStartTime, "frame position before buffer?"); // We only look at the non-blocking interval StreamTime frameBufferTime = aStream->GraphTimeToStreamTime(mProcessedTime); StreamTime bufferEndTime = aStream->GraphTimeToStreamTime(aStream->mStartBlocking); @@ -957,7 +957,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream) // Pick the last track that has a video chunk for the time, and // schedule its frame. chunk = nullptr; - for (StreamBuffer::TrackIter tracks(aStream->GetStreamBuffer(), + for (StreamTracks::TrackIter tracks(aStream->GetStreamTracks(), MediaSegment::VIDEO); !tracks.IsEnded(); tracks.Next()) { @@ -1388,14 +1388,14 @@ MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions) // The stream's not suspended, and since it's finished, underruns won't // stop it playing out. So there's no blocking other than what we impose // here. - GraphTime endTime = stream->GetStreamBuffer().GetAllTracksEnd() + - stream->mBufferStartTime; + GraphTime endTime = stream->GetStreamTracks().GetAllTracksEnd() + + stream->mTracksStartTime; if (endTime <= mStateComputedTime) { STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being finished", stream)); stream->mStartBlocking = mStateComputedTime; } else { STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)", - stream, MediaTimeToSeconds(stream->GetBufferEnd()), + stream, MediaTimeToSeconds(stream->GetTracksEnd()), MediaTimeToSeconds(endTime))); // Data can't be added to a finished stream, so underruns are irrelevant. stream->mStartBlocking = std::min(endTime, aEndBlockingDecisions); @@ -1459,7 +1459,7 @@ MediaStreamGraphImpl::Process() } else { ps->ProcessInput(mProcessedTime, mStateComputedTime, ProcessedMediaStream::ALLOW_FINISH); - NS_WARN_IF_FALSE(stream->mBuffer.GetEnd() >= + NS_WARN_IF_FALSE(stream->mTracks.GetEnd() >= GraphTimeToStreamTimeWithBlocking(stream, mStateComputedTime), "Stream did not produce enough data"); } @@ -1948,7 +1948,7 @@ MediaStreamGraphImpl::AppendMessage(UniquePtr<ControlMessage> aMessage) } MediaStream::MediaStream(DOMMediaStream* aWrapper) - : mBufferStartTime(0) + : mTracksStartTime(0) , mStartBlocking(GRAPH_TIME_MAX) , mSuspendedCount(0) , mFinished(false) @@ -1988,7 +1988,7 @@ MediaStream::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const // - mListeners - elements // - mAudioOutputStream - elements - amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf); + amount += mTracks.SizeOfExcludingThis(aMallocSizeOf); amount += mAudioOutputs.ShallowSizeOfExcludingThis(aMallocSizeOf); amount += mVideoOutputs.ShallowSizeOfExcludingThis(aMallocSizeOf); amount += mListeners.ShallowSizeOfExcludingThis(aMallocSizeOf); @@ -2023,7 +2023,7 @@ MediaStream::SetGraphImpl(MediaStreamGraphImpl* aGraph) MOZ_ASSERT(!mGraph, "Should only be called once"); mGraph = aGraph; mAudioChannelType = aGraph->AudioChannel(); - mBuffer.InitGraphRate(aGraph->GraphRate()); + mTracks.InitGraphRate(aGraph->GraphRate()); } void @@ -2039,16 +2039,16 @@ MediaStream::GraphTimeToStreamTime(GraphTime aTime) NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime || aTime <= mStartBlocking, "Incorrectly ignoring blocking!"); - return aTime - mBufferStartTime; + return aTime - mTracksStartTime; } GraphTime MediaStream::StreamTimeToGraphTime(StreamTime aTime) { NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime || - aTime + mBufferStartTime <= mStartBlocking, + aTime + mTracksStartTime <= mStartBlocking, "Incorrectly ignoring blocking!"); - return aTime + mBufferStartTime; + return aTime + mTracksStartTime; } StreamTime @@ -2063,16 +2063,16 @@ MediaStream::FinishOnGraphThread() GraphImpl()->FinishStream(this); } -StreamBuffer::Track* +StreamTracks::Track* MediaStream::FindTrack(TrackID aID) { - return mBuffer.FindTrack(aID); + return mTracks.FindTrack(aID); } -StreamBuffer::Track* +StreamTracks::Track* MediaStream::EnsureTrack(TrackID aTrackId) { - StreamBuffer::Track* track = mBuffer.FindTrack(aTrackId); + StreamTracks::Track* track = mTracks.FindTrack(aTrackId); if (!track) { nsAutoPtr<MediaSegment> segment(new AudioSegment()); for (uint32_t j = 0; j < mListeners.Length(); ++j) { @@ -2084,7 +2084,7 @@ MediaStream::EnsureTrack(TrackID aTrackId) // change this. l->NotifyFinishedTrackCreation(Graph()); } - track = &mBuffer.AddTrack(aTrackId, 0, segment.forget()); + track = &mTracks.AddTrack(aTrackId, 0, segment.forget()); } return track; } @@ -2400,7 +2400,7 @@ MediaStream::AddTrackListenerImpl(already_AddRefed<MediaStreamTrackListener> aLi l->mListener = aListener; l->mTrackID = aTrackID; - StreamBuffer::Track* track = FindTrack(aTrackID); + StreamTracks::Track* track = FindTrack(aTrackID); if (!track) { return; } diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index 0f33221bd2..640e5edfe3 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -16,7 +16,7 @@ #include "AudioStream.h" #include "nsTArray.h" #include "nsIRunnable.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "VideoFrameContainer.h" #include "VideoSegment.h" #include "MainThreadUtils.h" @@ -477,7 +477,7 @@ struct TrackBound * time. To ensure video plays in sync with audio, make sure that the same * stream is playing both the audio and video. * - * The data in a stream is managed by StreamBuffer. It consists of a set of + * The data in a stream is managed by StreamTracks. It consists of a set of * tracks of various types that can start and end over time. * * Streams are explicitly managed. The client creates them via @@ -541,7 +541,7 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> /** * Returns sample rate of the graph. */ - TrackRate GraphRate() { return mBuffer.GraphRate(); } + TrackRate GraphRate() { return mTracks.GraphRate(); } // Control API. // Since a stream can be played multiple ways, we need to combine independent @@ -674,9 +674,9 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> * This must be idempotent. */ virtual void DestroyImpl(); - StreamTime GetBufferEnd() { return mBuffer.GetEnd(); } + StreamTime GetTracksEnd() { return mTracks.GetEnd(); } #ifdef DEBUG - void DumpTrackInfo() { return mBuffer.DumpTrackInfo(); } + void DumpTrackInfo() { return mTracks.DumpTrackInfo(); } #endif void SetAudioOutputVolumeImpl(void* aKey, float aVolume); void AddAudioOutputImpl(void* aKey); @@ -713,36 +713,36 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> { return mConsumers.Length(); } - StreamBuffer& GetStreamBuffer() { return mBuffer; } - GraphTime GetStreamBufferStartTime() { return mBufferStartTime; } + StreamTracks& GetStreamTracks() { return mTracks; } + GraphTime GetStreamTracksStartTime() { return mTracksStartTime; } double StreamTimeToSeconds(StreamTime aTime) { NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time"); - return static_cast<double>(aTime)/mBuffer.GraphRate(); + return static_cast<double>(aTime)/mTracks.GraphRate(); } int64_t StreamTimeToMicroseconds(StreamTime aTime) { NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time"); - return (aTime*1000000)/mBuffer.GraphRate(); + return (aTime*1000000)/mTracks.GraphRate(); } StreamTime SecondsToNearestStreamTime(double aSeconds) { NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX/TRACK_RATE_MAX, "Bad seconds"); - return mBuffer.GraphRate() * aSeconds + 0.5; + return mTracks.GraphRate() * aSeconds + 0.5; } StreamTime MicrosecondsToStreamTimeRoundDown(int64_t aMicroseconds) { - return (aMicroseconds*mBuffer.GraphRate())/1000000; + return (aMicroseconds*mTracks.GraphRate())/1000000; } TrackTicks TimeToTicksRoundUp(TrackRate aRate, StreamTime aTime) { - return RateConvertTicksRoundUp(aRate, mBuffer.GraphRate(), aTime); + return RateConvertTicksRoundUp(aRate, mTracks.GraphRate(), aTime); } StreamTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks) { - return RateConvertTicksRoundDown(mBuffer.GraphRate(), aRate, aTicks); + return RateConvertTicksRoundDown(mTracks.GraphRate(), aRate, aTicks); } /** * Convert graph time to stream time. aTime must be <= mStateComputedTime @@ -773,9 +773,9 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> /** * Find track by track id. */ - StreamBuffer::Track* FindTrack(TrackID aID); + StreamTracks::Track* FindTrack(TrackID aID); - StreamBuffer::Track* EnsureTrack(TrackID aTrack); + StreamTracks::Track* EnsureTrack(TrackID aTrack); virtual void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr); @@ -808,8 +808,8 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> protected: void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime) { - mBufferStartTime += aBlockedTime; - mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime); + mTracksStartTime += aBlockedTime; + mTracks.ForgetUpTo(aCurrentTime - mTracksStartTime); } void NotifyMainThreadListeners() @@ -836,14 +836,14 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> // This state is all initialized on the main thread but // otherwise modified only on the media graph thread. - // Buffered data. The start of the buffer corresponds to mBufferStartTime. + // Buffered data. The start of the buffer corresponds to mTracksStartTime. // Conceptually the buffer contains everything this stream has ever played, // but we forget some prefix of the buffered data to bound the space usage. - StreamBuffer mBuffer; + StreamTracks mTracks; // The time when the buffered data could be considered to have started playing. // This increases over time to account for time the stream was blocked before // mCurrentTime. - GraphTime mBufferStartTime; + GraphTime mTracksStartTime; // Client-set volume of this stream struct AudioOutput { @@ -863,7 +863,7 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> // GraphTime at which this stream starts blocking. // This is only valid up to mStateComputedTime. The stream is considered to - // have not been blocked before mCurrentTime (its mBufferStartTime is increased + // have not been blocked before mCurrentTime (its mTracksStartTime is increased // as necessary to account for that time instead). GraphTime mStartBlocking; diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 3cb5d1c7f5..95708dc4b9 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -403,7 +403,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph, void PlayVideo(MediaStream* aStream); /** * No more data will be forthcoming for aStream. The stream will end - * at the current buffer end point. The StreamBuffer's tracks must be + * at the current buffer end point. The StreamTracks's tracks must be * explicitly set to finished by the caller. */ void OpenAudioInputImpl(int aID, diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h index 01da71cae6..55807383f8 100644 --- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -10,7 +10,7 @@ #include "nsError.h" #include "nsID.h" #include "nsIPrincipal.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "MediaTrackConstraints.h" #include "mozilla/CORSMode.h" #include "PrincipalChangeObserver.h" diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index a719e6bae8..a4957ecc4a 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -1172,7 +1172,6 @@ RTCPeerConnection.prototype = { return null; } - sdp = this._localIdp.addIdentityAttribute(sdp); return new this._win.RTCSessionDescription({ type: this._localType, sdp: sdp }); }, diff --git a/dom/media/StreamTracks.cpp b/dom/media/StreamTracks.cpp new file mode 100644 index 0000000000..b03b444900 --- /dev/null +++ b/dom/media/StreamTracks.cpp @@ -0,0 +1,117 @@ +/* -*- 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 "StreamTracks.h" +#include "mozilla/Logging.h" +#include <algorithm> + +namespace mozilla { + +extern LazyLogModule gMediaStreamGraphLog; +#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg) + +#ifdef DEBUG +void +StreamTracks::DumpTrackInfo() const +{ + STREAM_LOG(LogLevel::Info, ("DumpTracks: mTracksKnownTime %lld", mTracksKnownTime)); + for (uint32_t i = 0; i < mTracks.Length(); ++i) { + Track* track = mTracks[i]; + if (track->IsEnded()) { + STREAM_LOG(LogLevel::Info, ("Track[%d] %d: ended", i, track->GetID())); + } else { + STREAM_LOG(LogLevel::Info, ("Track[%d] %d: %lld", i, track->GetID(), + track->GetEnd())); + } + } +} +#endif + +StreamTime +StreamTracks::GetEnd() const +{ + StreamTime t = mTracksKnownTime; + for (uint32_t i = 0; i < mTracks.Length(); ++i) { + Track* track = mTracks[i]; + if (!track->IsEnded()) { + t = std::min(t, track->GetEnd()); + } + } + return t; +} + +StreamTime +StreamTracks::GetAllTracksEnd() const +{ + if (mTracksKnownTime < STREAM_TIME_MAX) { + // A track might be added. + return STREAM_TIME_MAX; + } + StreamTime t = 0; + for (uint32_t i = 0; i < mTracks.Length(); ++i) { + Track* track = mTracks[i]; + if (!track->IsEnded()) { + return STREAM_TIME_MAX; + } + t = std::max(t, track->GetEnd()); + } + return t; +} + +StreamTracks::Track* +StreamTracks::FindTrack(TrackID aID) +{ + if (aID == TRACK_NONE || mTracks.IsEmpty()) { + return nullptr; + } + + // The tracks are sorted by ID. We can use a binary search. + + uint32_t left = 0, right = mTracks.Length() - 1; + while (left <= right) { + uint32_t middle = (left + right) / 2; + if (mTracks[middle]->GetID() == aID) { + return mTracks[middle]; + } + + if (mTracks[middle]->GetID() > aID) { + if (middle == 0) { + break; + } + + right = middle - 1; + } else { + left = middle + 1; + } + } + + return nullptr; +} + +void +StreamTracks::ForgetUpTo(StreamTime aTime) +{ + // Only prune if there is a reasonable chunk (50ms @ 48kHz) to forget, so we + // don't spend too much time pruning segments. + const StreamTime minChunkSize = 2400; + if (aTime < mForgottenTime + minChunkSize) { + return; + } + mForgottenTime = aTime; + + for (uint32_t i = 0; i < mTracks.Length(); ++i) { + Track* track = mTracks[i]; + if (track->IsEnded() && track->GetEnd() <= aTime) { + mTracks.RemoveElementAt(i); + mTracksDirty = true; + --i; + continue; + } + StreamTime forgetTo = std::min(track->GetEnd() - 1, aTime); + track->ForgetUpTo(forgetTo); + } +} + +} // namespace mozilla diff --git a/dom/media/StreamTracks.h b/dom/media/StreamTracks.h new file mode 100644 index 0000000000..a152e9e54e --- /dev/null +++ b/dom/media/StreamTracks.h @@ -0,0 +1,343 @@ +/* -*- 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_STREAMTRACKS_H_ +#define MOZILLA_STREAMTRACKS_H_ + +#include "MediaSegment.h" +#include "nsAutoPtr.h" + +namespace mozilla { + +/** + * Unique ID for track within a StreamTracks. Tracks from different + * StreamTrackss may have the same ID; this matters when appending StreamTrackss, + * since tracks with the same ID are matched. Only IDs greater than 0 are allowed. + */ +typedef int32_t TrackID; +const TrackID TRACK_NONE = 0; +const TrackID TRACK_INVALID = -1; +const TrackID TRACK_ANY = -2; + +inline bool IsTrackIDExplicit(const TrackID& aId) { + return aId > TRACK_NONE; +} + +inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate, + TrackRate aInRate, + TrackTicks aTicks) +{ + NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate"); + NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate"); + NS_WARN_IF_FALSE(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks"); // bug 957691 + return (aTicks * aOutRate) / aInRate; +} +inline TrackTicks RateConvertTicksRoundUp(TrackRate aOutRate, + TrackRate aInRate, TrackTicks aTicks) +{ + NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate"); + NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate"); + NS_ASSERTION(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks"); + return (aTicks * aOutRate + aInRate - 1) / aInRate; +} + +/** + * This object contains the decoded data for a stream's tracks. + * A StreamTracks can be appended to. Logically a StreamTracks only gets longer, + * but we also have the ability to "forget" data before a certain time that + * we know won't be used again. (We prune a whole number of seconds internally.) + * + * StreamTrackss should only be used from one thread at a time. + * + * A StreamTracks has a set of tracks that can be of arbitrary types --- + * the data for each track is a MediaSegment. The set of tracks can vary + * over the timeline of the StreamTracks. + */ +class StreamTracks +{ +public: + /** + * Every track has a start time --- when it started in the StreamTracks. + * It has an end flag; when false, no end point is known; when true, + * the track ends when the data we have for the track runs out. + * Tracks have a unique ID assigned at creation. This allows us to identify + * the same track across StreamTrackss. A StreamTracks should never have + * two tracks with the same ID (even if they don't overlap in time). + * TODO Tracks can also be enabled and disabled over time. + * Takes ownership of aSegment. + */ + class Track final + { + Track(TrackID aID, StreamTime aStart, MediaSegment* aSegment) + : mStart(aStart), + mSegment(aSegment), + mID(aID), + mEnded(false) + { + MOZ_COUNT_CTOR(Track); + + NS_ASSERTION(aID > TRACK_NONE, "Bad track ID"); + NS_ASSERTION(0 <= aStart && aStart <= aSegment->GetDuration(), "Bad start position"); + } + + public: + ~Track() + { + MOZ_COUNT_DTOR(Track); + } + + template <class T> T* Get() const + { + if (mSegment->GetType() == T::StaticType()) { + return static_cast<T*>(mSegment.get()); + } + return nullptr; + } + + MediaSegment* GetSegment() const { return mSegment; } + TrackID GetID() const { return mID; } + bool IsEnded() const { return mEnded; } + StreamTime GetStart() const { return mStart; } + StreamTime GetEnd() const { return mSegment->GetDuration(); } + MediaSegment::Type GetType() const { return mSegment->GetType(); } + + void SetEnded() { mEnded = true; } + void AppendFrom(Track* aTrack) + { + NS_ASSERTION(!mEnded, "Can't append to ended track"); + NS_ASSERTION(aTrack->mID == mID, "IDs must match"); + NS_ASSERTION(aTrack->mStart == 0, "Source track must start at zero"); + NS_ASSERTION(aTrack->mSegment->GetType() == GetType(), "Track types must match"); + + mSegment->AppendFrom(aTrack->mSegment); + mEnded = aTrack->mEnded; + } + MediaSegment* RemoveSegment() + { + return mSegment.forget(); + } + void ForgetUpTo(StreamTime aTime) + { + mSegment->ForgetUpTo(aTime); + } + void FlushAfter(StreamTime aNewEnd) + { + // Forget everything after a given endpoint + // a specified amount + mSegment->FlushAfter(aNewEnd); + } + + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const + { + size_t amount = aMallocSizeOf(this); + if (mSegment) { + amount += mSegment->SizeOfIncludingThis(aMallocSizeOf); + } + return amount; + } + + private: + friend class StreamTracks; + + // Start offset is in ticks at rate mRate + StreamTime mStart; + // The segment data starts at the start of the owning StreamTracks, i.e., + // there's mStart silence/no video at the beginning. + nsAutoPtr<MediaSegment> mSegment; + // Unique ID + TrackID mID; + // True when the track ends with the data in mSegment + bool mEnded; + }; + + class MOZ_STACK_CLASS CompareTracksByID final + { + public: + bool Equals(Track* aA, Track* aB) const { + return aA->GetID() == aB->GetID(); + } + bool LessThan(Track* aA, Track* aB) const { + return aA->GetID() < aB->GetID(); + } + }; + + StreamTracks() + : mGraphRate(0) + , mTracksKnownTime(0) + , mForgottenTime(0) + , mTracksDirty(false) +#ifdef DEBUG + , mGraphRateIsSet(false) +#endif + { + MOZ_COUNT_CTOR(StreamTracks); + } + ~StreamTracks() + { + MOZ_COUNT_DTOR(StreamTracks); + } + + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const + { + size_t amount = 0; + amount += mTracks.ShallowSizeOfExcludingThis(aMallocSizeOf); + for (size_t i = 0; i < mTracks.Length(); i++) { + amount += mTracks[i]->SizeOfIncludingThis(aMallocSizeOf); + } + return amount; + } + + /** + * Initialize the graph rate for use in calculating StreamTimes from track + * ticks. Called when a MediaStream's graph pointer is initialized. + */ + void InitGraphRate(TrackRate aGraphRate) + { + mGraphRate = aGraphRate; +#if DEBUG + MOZ_ASSERT(!mGraphRateIsSet); + mGraphRateIsSet = true; +#endif + } + + TrackRate GraphRate() const + { + MOZ_ASSERT(mGraphRateIsSet); + return mGraphRate; + } + + /** + * Takes ownership of aSegment. Don't do this while iterating, or while + * holding a Track reference. + * aSegment must have aStart worth of null data. + */ + Track& AddTrack(TrackID aID, StreamTime aStart, MediaSegment* aSegment) + { + NS_ASSERTION(!FindTrack(aID), "Track with this ID already exists"); + + Track* track = new Track(aID, aStart, aSegment); + mTracks.InsertElementSorted(track, CompareTracksByID()); + mTracksDirty = true; + + if (mTracksKnownTime == STREAM_TIME_MAX) { + // There exists code like + // http://mxr.mozilla.org/mozilla-central/source/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp?rev=96b197deb91e&mark=1292-1297#1292 + NS_WARNING("Adding track to StreamTracks that should have no more tracks"); + } else { + NS_ASSERTION(mTracksKnownTime <= aStart, "Start time too early"); + } + return *track; + } + + void AdvanceKnownTracksTime(StreamTime aKnownTime) + { + NS_ASSERTION(aKnownTime >= mTracksKnownTime, "Can't move tracks-known time earlier"); + mTracksKnownTime = aKnownTime; + } + + /** + * The end time for the StreamTracks is the latest time for which we have + * data for all tracks that haven't ended by that time. + */ + StreamTime GetEnd() const; + + /** + * Returns the earliest time >= 0 at which all tracks have ended + * and all their data has been played out and no new tracks can be added, + * or STREAM_TIME_MAX if there is no such time. + */ + StreamTime GetAllTracksEnd() const; + +#ifdef DEBUG + void DumpTrackInfo() const; +#endif + + Track* FindTrack(TrackID aID); + + class MOZ_STACK_CLASS TrackIter final + { + public: + /** + * Iterate through the tracks of aBuffer in order of ID. + */ + explicit TrackIter(const StreamTracks& aBuffer) : + mBuffer(&aBuffer.mTracks), mIndex(0), mMatchType(false) {} + /** + * Iterate through the tracks of aBuffer with type aType, in order of ID. + */ + TrackIter(const StreamTracks& aBuffer, MediaSegment::Type aType) : + mBuffer(&aBuffer.mTracks), mIndex(0), mType(aType), mMatchType(true) { FindMatch(); } + bool IsEnded() { return mIndex >= mBuffer->Length(); } + void Next() + { + ++mIndex; + FindMatch(); + } + Track* get() { return mBuffer->ElementAt(mIndex); } + Track& operator*() { return *mBuffer->ElementAt(mIndex); } + Track* operator->() { return mBuffer->ElementAt(mIndex); } + private: + void FindMatch() + { + if (!mMatchType) + return; + while (mIndex < mBuffer->Length() && + mBuffer->ElementAt(mIndex)->GetType() != mType) { + ++mIndex; + } + } + + const nsTArray<nsAutoPtr<Track> >* mBuffer; + uint32_t mIndex; + MediaSegment::Type mType; + bool mMatchType; + }; + friend class TrackIter; + + /** + * Forget stream data before aTime; they will no longer be needed. + * Also can forget entire tracks that have ended at or before aTime. + * Can't be used to forget beyond GetEnd(). + */ + void ForgetUpTo(StreamTime aTime); + /** + * Returns the latest time passed to ForgetUpTo. + */ + StreamTime GetForgottenDuration() + { + return mForgottenTime; + } + + bool GetAndResetTracksDirty() + { + if (!mTracksDirty) { + return false; + } + + mTracksDirty = false; + return true; + } + +protected: + TrackRate mGraphRate; // StreamTime per second + // Any new tracks added will start at or after this time. In other words, the track + // list is complete and correct for all times less than this time. + StreamTime mTracksKnownTime; + StreamTime mForgottenTime; + +private: + // All known tracks for this StreamTracks + nsTArray<nsAutoPtr<Track>> mTracks; + bool mTracksDirty; + +#ifdef DEBUG + bool mGraphRateIsSet; +#endif +}; + +} // namespace mozilla + +#endif /* MOZILLA_STREAMTRACKS_H_ */ + diff --git a/dom/media/TrackUnionStream.cpp b/dom/media/TrackUnionStream.cpp index 464174f0ab..4f12473820 100644 --- a/dom/media/TrackUnionStream.cpp +++ b/dom/media/TrackUnionStream.cpp @@ -87,14 +87,14 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : allHaveCurrentData = false; } bool trackAdded = false; - for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer()); + for (StreamTracks::TrackIter tracks(stream->GetStreamTracks()); !tracks.IsEnded(); tracks.Next()) { bool found = false; for (uint32_t j = 0; j < mTrackMap.Length(); ++j) { TrackMapEntry* map = &mTrackMap[j]; if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) { - bool trackFinished; - StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID); + bool trackFinished = false; + StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID); found = true; if (!outputTrack || outputTrack->IsEnded() || !mInputs[i]->PassTrackThrough(tracks->GetID())) { @@ -138,7 +138,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : // so we're finished now. FinishOnGraphThread(); } else { - mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo)); + mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo)); } if (allHaveCurrentData) { // We can make progress if we're not blocked @@ -146,7 +146,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : } } - uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, + uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamTracks::Track* aTrack, GraphTime aFrom) { STREAM_LOG(LogLevel::Verbose, ("TrackUnionStream %p adding track %d for " @@ -205,8 +205,8 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : aPort->GetSource(), aTrack->GetID()); } segment->AppendNullData(outputStart); - StreamBuffer::Track* track = - &mBuffer.AddTrack(id, outputStart, segment.forget()); + StreamTracks::Track* track = + &mTracks.AddTrack(id, outputStart, segment.forget()); STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p added track %d for input stream %p track %d, start ticks %lld", this, track->GetID(), aPort->GetSource(), aTrack->GetID(), (long long)outputStart)); @@ -246,7 +246,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : void TrackUnionStream::EndTrack(uint32_t aIndex) { - StreamBuffer::Track* outputTrack = mBuffer.FindTrack(mTrackMap[aIndex].mOutputTrackID); + StreamTracks::Track* outputTrack = mTracks.FindTrack(mTrackMap[aIndex].mOutputTrackID); if (!outputTrack || outputTrack->IsEnded()) return; STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p ending track %d", this, outputTrack->GetID())); @@ -269,12 +269,12 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : outputTrack->SetEnded(); } - void TrackUnionStream::CopyTrackData(StreamBuffer::Track* aInputTrack, + void TrackUnionStream::CopyTrackData(StreamTracks::Track* aInputTrack, uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo, bool* aOutputTrackFinished) { TrackMapEntry* map = &mTrackMap[aMapIndex]; - StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID); + StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID); MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track"); MediaSegment* segment = map->mSegment; diff --git a/dom/media/TrackUnionStream.h b/dom/media/TrackUnionStream.h index a21686bd15..5351b00d6a 100644 --- a/dom/media/TrackUnionStream.h +++ b/dom/media/TrackUnionStream.h @@ -41,7 +41,7 @@ class TrackUnionStream : public ProcessedMediaStream { // We keep track IDs instead of track pointers because // tracks can be removed without us being notified (e.g. // when a finished track is forgotten.) When we need a Track*, - // we call StreamBuffer::FindTrack, which will return null if + // we call StreamTracks::FindTrack, which will return null if // the track has been deleted. TrackID mInputTrackID; TrackID mOutputTrackID; @@ -54,10 +54,10 @@ class TrackUnionStream : public ProcessedMediaStream { // Add the track to this stream, retaining its TrackID if it has never // been previously used in this stream, allocating a new TrackID otherwise. - uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, + uint32_t AddTrack(MediaInputPort* aPort, StreamTracks::Track* aTrack, GraphTime aFrom); void EndTrack(uint32_t aIndex); - void CopyTrackData(StreamBuffer::Track* aInputTrack, + void CopyTrackData(StreamTracks::Track* aInputTrack, uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo, bool* aOutputTrackFinished); diff --git a/dom/media/encoder/TrackEncoder.h b/dom/media/encoder/TrackEncoder.h index 5f11620431..46b7e0ea84 100644 --- a/dom/media/encoder/TrackEncoder.h +++ b/dom/media/encoder/TrackEncoder.h @@ -10,7 +10,7 @@ #include "AudioSegment.h" #include "EncodedFrameContainer.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "TrackMetadataBase.h" #include "VideoSegment.h" #include "MediaStreamGraph.h" diff --git a/dom/media/moz.build b/dom/media/moz.build index 3ffde9a160..279461df61 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -136,7 +136,7 @@ EXPORTS += [ 'SeekTask.h', 'SelfRef.h', 'SharedBuffer.h', - 'StreamBuffer.h', + 'StreamTracks.h', 'ThreadPoolCOMListener.h', 'TimeUnits.h', 'TrackUnionStream.h', @@ -239,7 +239,7 @@ UNIFIED_SOURCES += [ 'RtspMediaResource.cpp', 'SeekJob.cpp', 'SeekTask.cpp', - 'StreamBuffer.cpp', + 'StreamTracks.cpp', 'TextTrack.cpp', 'TextTrackCue.cpp', 'TextTrackCueList.cpp', diff --git a/dom/media/tests/mochitest/test_peerConnection_addIceCandidate.html b/dom/media/tests/mochitest/test_peerConnection_addIceCandidate.html index b844403f02..93cbdd0832 100644 --- a/dom/media/tests/mochitest/test_peerConnection_addIceCandidate.html +++ b/dom/media/tests/mochitest/test_peerConnection_addIceCandidate.html @@ -8,7 +8,7 @@ <script type="application/javascript"> createHTML({ bug: "1087551", - title: "addCandidate behavior in different states" + title: "addIceCandidate behavior (local and remote) including invalid data" }); var test; @@ -71,6 +71,28 @@ sdpMLineIndex: 0}); return test.pcRemote._pc.addIceCandidate(candidate) .then(ok(true, "Successfully added valid ICE candidate")); + }, + // bug 1095793 + function PC_REMOTE_ADD_MISMATCHED_MID_AND_LEVEL_CANDIDATE(test) { + var bogus = new mozRTCIceCandidate( + {candidate:"candidate:1 1 UDP 2130706431 192.168.2.1 50005 typ host", + sdpMLineIndex: 0, + sdpMid: "sdparta_1"}); + return test.pcRemote._pc.addIceCandidate(bogus) + .then( + generateErrorCallback("addIceCandidate should have failed."), + err => { + is(err.name, "InvalidCandidateError", "Error is InvalidCandidateError"); + } + ); + }, + function PC_REMOTE_ADD_MATCHING_MID_AND_LEVEL_CANDIDATE(test) { + var candidate = new mozRTCIceCandidate( + {candidate:"candidate:1 1 UDP 2130706431 192.168.2.1 50005 typ host", + sdpMLineIndex: 0, + sdpMid: "sdparta_0"}); + return test.pcRemote._pc.addIceCandidate(candidate) + .then(ok(true, "Successfully added valid ICE candidate with matching mid and level")); } ]); test.run(); diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 001a46e473..029a54c7ce 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -514,6 +514,7 @@ AudioContext::CreateOscillator(ErrorResult& aRv) already_AddRefed<PeriodicWave> AudioContext::CreatePeriodicWave(const Float32Array& aRealData, const Float32Array& aImagData, + const PeriodicWaveConstraints& aConstraints, ErrorResult& aRv) { aRealData.ComputeLengthAndData(); diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 15870890af..e5cb4b7d0b 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -68,6 +68,7 @@ class ScriptProcessorNode; class StereoPannerNode; class WaveShaperNode; class PeriodicWave; +struct PeriodicWaveConstraints; class Promise; enum class OscillatorType : uint32_t; @@ -255,6 +256,7 @@ class AudioContext final : public DOMEventTargetHelper, already_AddRefed<PeriodicWave> CreatePeriodicWave(const Float32Array& aRealData, const Float32Array& aImagData, + const PeriodicWaveConstraints& aConstraints, ErrorResult& aRv); already_AddRefed<Promise> diff --git a/dom/media/webaudio/AudioNodeExternalInputStream.cpp b/dom/media/webaudio/AudioNodeExternalInputStream.cpp index bcf5220dee..4c711fc0c0 100644 --- a/dom/media/webaudio/AudioNodeExternalInputStream.cpp +++ b/dom/media/webaudio/AudioNodeExternalInputStream.cpp @@ -135,9 +135,9 @@ AudioNodeExternalInputStream::ProcessInput(GraphTime aFrom, GraphTime aTo, MediaStream* source = mInputs[0]->GetSource(); AutoTArray<AudioSegment,1> audioSegments; uint32_t inputChannels = 0; - for (StreamBuffer::TrackIter tracks(source->mBuffer, MediaSegment::AUDIO); + for (StreamTracks::TrackIter tracks(source->mTracks, MediaSegment::AUDIO); !tracks.IsEnded(); tracks.Next()) { - const StreamBuffer::Track& inputTrack = *tracks; + const StreamTracks::Track& inputTrack = *tracks; if (!mInputs[0]->PassTrackThrough(tracks->GetID())) { continue; } diff --git a/dom/media/webaudio/AudioNodeStream.cpp b/dom/media/webaudio/AudioNodeStream.cpp index 4e835ed144..d388d50811 100644 --- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -385,9 +385,9 @@ class AudioNodeStream::AdvanceAndResumeMessage final : public ControlMessage { void Run() override { auto ns = static_cast<AudioNodeStream*>(mStream); - ns->mBufferStartTime -= mAdvance; + ns->mTracksStartTime -= mAdvance; - StreamBuffer::Track* track = ns->EnsureTrack(AUDIO_TRACK); + StreamTracks::Track* track = ns->EnsureTrack(AUDIO_TRACK); track->Get<AudioSegment>()->AppendNullData(mAdvance); ns->GraphImpl()->DecrementSuspendCount(mStream); @@ -630,9 +630,9 @@ AudioNodeStream::ProduceOutputBeforeInput(GraphTime aFrom) void AudioNodeStream::AdvanceOutputSegment() { - StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); + StreamTracks::Track* track = EnsureTrack(AUDIO_TRACK); // No more tracks will be coming - mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX); + mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX); AudioSegment* segment = track->Get<AudioSegment>(); @@ -655,7 +655,7 @@ AudioNodeStream::AdvanceOutputSegment() void AudioNodeStream::FinishOutput() { - StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK); + StreamTracks::Track* track = EnsureTrack(AUDIO_TRACK); track->SetEnded(); for (uint32_t j = 0; j < mListeners.Length(); ++j) { diff --git a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp index 6b7b8358c9..b20fc721a4 100644 --- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp +++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp @@ -30,9 +30,9 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a ChannelCountMode::Explicit, ChannelInterpretation::Speakers) , mDOMStream( - DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(), - this, - aContext->Graph())) + DOMAudioNodeMediaStream::CreateTrackUnionStreamAsInput(GetOwner(), + this, + aContext->Graph())) { // Ensure an audio track with the correct ID is exposed to JS nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc(); diff --git a/dom/media/webrtc/MediaEngineDefault.h b/dom/media/webrtc/MediaEngineDefault.h index 82cf41d85e..71aacbcf11 100644 --- a/dom/media/webrtc/MediaEngineDefault.h +++ b/dom/media/webrtc/MediaEngineDefault.h @@ -16,7 +16,7 @@ #include "MediaEngine.h" #include "VideoSegment.h" #include "AudioSegment.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "MediaStreamGraph.h" #include "MediaTrackConstraints.h" @@ -134,7 +134,7 @@ class MediaEngineDefaultAudioSource : public nsITimerCallback, const PrincipalHandle& aPrincipalHandle) override { #ifdef DEBUG - StreamBuffer::Track* data = aSource->FindTrack(aId); + StreamTracks::Track* data = aSource->FindTrack(aId); NS_WARN_IF_FALSE(!data || data->IsEnded() || aDesiredTime <= aSource->GetEndOfAppendedData(aId), "MediaEngineDefaultAudioSource data underrun"); diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.h b/dom/media/webrtc/MediaEngineRemoteVideoSource.h index d7776b619f..0a04c67ec8 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h @@ -24,7 +24,7 @@ #include "MediaEngineCameraVideoSource.h" #include "VideoSegment.h" #include "AudioSegment.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "MediaStreamGraph.h" #include "MediaEngineWrapper.h" diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index c70a909a3e..3c47d0d608 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -27,7 +27,7 @@ #include "MediaEngineCameraVideoSource.h" #include "VideoSegment.h" #include "AudioSegment.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "MediaStreamGraph.h" #include "cubeb/cubeb.h" #include "CubebUtils.h" diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index 7a76df39da..a11c071402 100755 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -220,20 +220,9 @@ WifiGeoCoordsObject.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords]) }; -function WifiGeoPositionObject(lat, lng, acc, cc, tz, zip, city, rc, region, country, isp, org, as) { +function WifiGeoPositionObject(lat, lng, acc) { this.coords = new WifiGeoCoordsObject(lat, lng, acc, 0, 0); this.address = null; - this.countrycode = cc; - this.timezone = tz; - this.zipcode = zip; - this.postalcode = zip; - this.city = city; - this.regioncode = rc; - this.region = region; - this.country = country; - this.isp = isp; - this.org = org; - this.as = as; this.timestamp = Date.now(); } @@ -394,8 +383,9 @@ WifiGeoPositionProvider.prototype = { let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length); if (result != -1) { LOG("Filtering out " + ap.ssid + " " + result); + return false; } - return result; + return true; }; function sort(a, b) { @@ -455,7 +445,7 @@ WifiGeoPositionProvider.prototype = { break; // CDMA cases to be handled in bug 1010282 }; - result.push({ radio: radioTechFamily, + result.push({ radioType: radioTechFamily, mobileCountryCode: voice.network.mcc, mobileNetworkCode: voice.network.mnc, locationAreaCode: cell.gsmLocationAreaCode, @@ -506,43 +496,38 @@ WifiGeoPositionProvider.prototype = { this.notifyListener("locationUpdatePending"); try { - xhr.open("GET", url, true); + xhr.open("POST", url, true); } catch (e) { this.notifyListener("notifyError", [POSITION_UNAVAILABLE]); return; } + xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); xhr.responseType = "json"; xhr.mozBackgroundRequest = true; xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS; - + xhr.timeout = Services.prefs.getIntPref("geo.wifi.xhr.timeout"); + xhr.ontimeout = (function() { + LOG("Location request XHR timed out.") + this.notifyListener("notifyError", + [POSITION_UNAVAILABLE]); + }).bind(this); xhr.onerror = (function() { this.notifyListener("notifyError", [POSITION_UNAVAILABLE]); }).bind(this); - xhr.onload = (function() { LOG("server returned status: " + xhr.status + " --> " + JSON.stringify(xhr.response)); if ((xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) || - !xhr.response || !xhr.response.status || xhr.response.status == 'fail') { + !xhr.response || !xhr.response.location) { this.notifyListener("notifyError", [POSITION_UNAVAILABLE]); return; } - let newLocation = new WifiGeoPositionObject(xhr.response.lat, - xhr.response.lon, - null, //accuracy not provided - xhr.response.countryCode, - xhr.response.timezone, - xhr.response.zip, - xhr.response.city, - xhr.response.region, - xhr.response.regionName, - xhr.response.country, - xhr.response.isp, - xhr.response.org, - xhr.response.as); + let newLocation = new WifiGeoPositionObject(xhr.response.location.lat, + xhr.response.location.lng, + xhr.response.accuracy); this.notifyListener("update", [newLocation]); gCachedRequest = new CachedRequest(newLocation, data.cellTowers, data.wifiAccessPoints); diff --git a/dom/system/SystemUpdateService.jsm b/dom/system/SystemUpdateService.jsm index bb62f2a438..41647ea8f5 100644 --- a/dom/system/SystemUpdateService.jsm +++ b/dom/system/SystemUpdateService.jsm @@ -27,7 +27,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm", function ActiveProvider(aProvider) { this.id = aProvider.id; - this._instance = Cc[aProvider.contractId].getService(Ci.nsISystemUpdateProvider); + this._instance = Components.classesByID[aProvider.id].getService(Ci.nsISystemUpdateProvider); this._instance.setListener(this); } diff --git a/dom/telephony/gonk/USSDReceivedWrapper.js b/dom/telephony/gonk/USSDReceivedWrapper.js index 54ead325f3..4d78932a2a 100644 --- a/dom/telephony/gonk/USSDReceivedWrapper.js +++ b/dom/telephony/gonk/USSDReceivedWrapper.js @@ -13,7 +13,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; -let DEBUG; +var DEBUG; function debug(s) { dump("USSDReceivedWrapper: " + s + "\n"); } diff --git a/dom/tests/browser/browser_ConsoleStorageAPITests.js b/dom/tests/browser/browser_ConsoleStorageAPITests.js index 48712b56b1..df33f24190 100644 --- a/dom/tests/browser/browser_ConsoleStorageAPITests.js +++ b/dom/tests/browser/browser_ConsoleStorageAPITests.js @@ -4,7 +4,7 @@ const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html"; const TEST_URI_NAV = "http://example.com/browser/dom/tests/browser/"; -let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"] +var ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"] .getService(Ci.nsIConsoleAPIStorage); var apiCallCount; diff --git a/dom/tests/mochitest/general/chrome.ini b/dom/tests/mochitest/general/chrome.ini index 83bdb93f34..43978b14a0 100644 --- a/dom/tests/mochitest/general/chrome.ini +++ b/dom/tests/mochitest/general/chrome.ini @@ -6,3 +6,4 @@ skip-if = buildapp == 'b2g' [test_offsets.js] [test_offsets.xul] skip-if = buildapp == 'mulet' +[test_spacetopagedown.html] diff --git a/dom/tests/mochitest/general/performance_timeline_main_test.html b/dom/tests/mochitest/general/performance_timeline_main_test.html index a90d226124..81456d44d2 100644 --- a/dom/tests/mochitest/general/performance_timeline_main_test.html +++ b/dom/tests/mochitest/general/performance_timeline_main_test.html @@ -94,8 +94,8 @@ <p id="display"></p> <div id="content"> <img src="http://mochi.test:8888/tests/image/test/mochitest/over.png"> - <object data="http://mochi.test:8888/tests/image/test/mochitest/clear.png" type="image/png"/> - <embed src="http://mochi.test:8888/tests/image/test/mochitest/green.png" type="image/png"/> + <object data="http://mochi.test:8888/tests/image/test/mochitest/clear.png" type="image/png"></object> + <embed src="http://mochi.test:8888/tests/image/test/mochitest/green.png" type="image/png"/> </div> </body> </html> diff --git a/dom/tests/mochitest/general/resource_timing_main_test.html b/dom/tests/mochitest/general/resource_timing_main_test.html index e5d4669c2d..44311ce19a 100644 --- a/dom/tests/mochitest/general/resource_timing_main_test.html +++ b/dom/tests/mochitest/general/resource_timing_main_test.html @@ -276,9 +276,9 @@ <p id="display"></p> <div id="content"> <img src="http://mochi.test:8888/tests/image/test/mochitest/blue.png"> - <object data="http://mochi.test:8888/tests/image/test/mochitest/red.png" type="image/png"/> - <embed src="http://mochi.test:8888/tests/image/test/mochitest/big.png" type="image/png"/> - <iframe sandbox="allow-same-origin allow-scripts" id="if_2" src="resource_timing_iframe.html" height="10" width="10"></iframe> + <object data="http://mochi.test:8888/tests/image/test/mochitest/red.png" type="image/png"></object> + <embed src="http://mochi.test:8888/tests/image/test/mochitest/big.png" type="image/png"/> + <iframe sandbox="allow-same-origin allow-scripts" id="if_2" src="resource_timing_iframe.html" height="10" width="10"></iframe> </div> </body> </html> diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index cfdb849b9f..8ee3c638e1 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -1367,7 +1367,7 @@ // IMPORTANT: Do not change this list without review from a DOM peer! {name: "TVTuner", b2g: true, permission: ["tv"]}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "U2F", release: false}, + {name: "U2F", disabled: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "UDPMessageEvent", b2g: true, permission: ["udp-socket"]}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/tests/mochitest/general/test_spacetopagedown.html b/dom/tests/mochitest/general/test_spacetopagedown.html new file mode 100644 index 0000000000..03f840f3d6 --- /dev/null +++ b/dom/tests/mochitest/general/test_spacetopagedown.html @@ -0,0 +1,76 @@ +<html> +<head> + <meta charset="utf-8"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> + <script type="application/javascript;version=1.7"> + +SimpleTest.waitForExplicitFinish(); + +Components.utils.import("resource://gre/modules/Task.jsm"); + +var windowUtils = SpecialPowers.getDOMWindowUtils(window); + +function pressKey(isShift) +{ + return new Promise(resolve => { + synthesizeKey(" ", { shiftKey: isShift }); + windowUtils.advanceTimeAndRefresh(100); + SimpleTest.executeSoon(resolve); + }); +} + +function initTest() +{ + SpecialPowers.pushPrefEnv({"set":[["general.smoothScroll", false]]}, runTest); +} + +function runTest() +{ + Task.async(function () { + yield pressKey(false); + + ok(window.scrollY > 0, "Space with no focus" + window.scrollY); + yield pressKey(true); + is(window.scrollY, 0, "Shift+Space with no focus"); + + let checkbox = document.getElementById("checkbox"); + checkbox.focus(); + yield pressKey(false); + + is(window.scrollY, 0, "Space with checkbox focused"); + ok(checkbox.checked, "Space with checkbox focused, checked"); + yield pressKey(true); + is(window.scrollY, 0, "Shift+Space with checkbox focused"); + ok(!checkbox.checked, "Space with checkbox focused, unchecked"); + + let input = document.getElementById("input"); + input.focus(); + yield pressKey(false); + is(window.scrollY, 0, "Space with input focused"); + is(input.value, " ", "Space with input focused, value"); + yield pressKey(true); + is(window.scrollY, 0, "Shift+Space with input focused"); + is(input.value, " ", "Space with input focused, value"); + + windowUtils.restoreNormalRefresh(); + SimpleTest.finish(); + })(); +} + + </script> +</head> +<body onload="SimpleTest.waitForFocus(initTest)"> + +<input id="checkbox" type="checkbox">Checkbox +<input id="input"> +<p style="height: 4000px">Text</p> + +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/tests/unit/test_geolocation_provider_timeout.js b/dom/tests/unit/test_geolocation_provider_timeout.js new file mode 100644 index 0000000000..da5091e49a --- /dev/null +++ b/dom/tests/unit/test_geolocation_provider_timeout.js @@ -0,0 +1,49 @@ +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://testing-common/httpd.js"); + +var httpserver = null; +var geolocation = null; + +function geoHandler(metadata, response) +{ + response.processAsync(); +} + +function successCallback() { + // The call shouldn't be sucessful. + do_check_true(false); + do_test_finished(); +} + +function errorCallback() { + do_check_true(true); + do_test_finished(); +} + +function run_test() +{ + do_test_pending(); + + // XPCShell does not get a profile by default. The geolocation service + // depends on the settings service which uses IndexedDB and IndexedDB + // needs a place where it can store databases. + do_get_profile(); + + httpserver = new HttpServer(); + httpserver.registerPathHandler("/geo", geoHandler); + httpserver.start(-1); + var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); + prefs.setCharPref("geo.wifi.uri", "http://localhost:" + + httpserver.identity.primaryPort + "/geo"); + prefs.setBoolPref("dom.testing.ignore_ipc_principal", true); + prefs.setBoolPref("geo.wifi.scan", false); + + // Setting timeout to a very low value to ensure time out will happen. + prefs.setIntPref("geo.wifi.xhr.timeout", 5); + + geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports); + geolocation.getCurrentPosition(successCallback, errorCallback); +} diff --git a/dom/tests/unit/xpcshell.ini b/dom/tests/unit/xpcshell.ini index 450350f71a..fee5fcfb42 100644 --- a/dom/tests/unit/xpcshell.ini +++ b/dom/tests/unit/xpcshell.ini @@ -24,3 +24,5 @@ skip-if = os == "android" skip-if = os == "mac" || os == "android" [test_PromiseDebugging.js] [test_xhr_init.js] +[test_geolocation_provider_timeout.js] +skip-if = os == "android" diff --git a/dom/tethering/TetheringManager.js b/dom/tethering/TetheringManager.js index d3f75b27ee..1e3d3a0ea2 100644 --- a/dom/tethering/TetheringManager.js +++ b/dom/tethering/TetheringManager.js @@ -82,7 +82,7 @@ TetheringManager.prototype = { this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TetheringManager]); -let debug; +var debug; if (DEBUG) { debug = function (s) { dump("-*- TetheringManager component: " + s + "\n"); diff --git a/dom/tethering/tests/marionette/head.js b/dom/tethering/tests/marionette/head.js index d7b6cad077..c6b6abe26e 100644 --- a/dom/tethering/tests/marionette/head.js +++ b/dom/tethering/tests/marionette/head.js @@ -38,7 +38,7 @@ function Deferred() { Object.freeze(this); } -let gTestSuite = (function() { +var gTestSuite = (function() { let suite = {}; let tetheringManager; diff --git a/dom/voicemail/gonk/VoicemailService.js b/dom/voicemail/gonk/VoicemailService.js index 85adc83fe0..fa6f622f68 100644 --- a/dom/voicemail/gonk/VoicemailService.js +++ b/dom/voicemail/gonk/VoicemailService.js @@ -31,7 +31,7 @@ const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; const kPrefDefaultServiceId = "dom.voicemail.defaultServiceId"; -let DEBUG; +var DEBUG; function debug(s) { dump("VoicemailService: " + s); } diff --git a/dom/voicemail/test/marionette/head.js b/dom/voicemail/test/marionette/head.js index 0dd08fe938..1ccf09b37e 100644 --- a/dom/voicemail/test/marionette/head.js +++ b/dom/voicemail/test/marionette/head.js @@ -5,7 +5,7 @@ const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers; -let RIL = SpecialPowers.wrap(SpecialPowers.createBlankObject()); +var RIL = SpecialPowers.wrap(SpecialPowers.createBlankObject()); SpecialPowers.Cu.import("resource://gre/modules/ril_consts.js", RIL); // Emulate Promise.jsm semantics. @@ -27,7 +27,7 @@ const MWI_TIMESTAMP = "00000000000000"; // Only bring in what we need from ril_worker/RadioInterfaceLayer here. Reusing // that code turns out to be a nightmare, so there is some code duplication. -let PDUBuilder = { +var PDUBuilder = { toHexString: function(n, length) { let str = n.toString(16); if (str.length < length) { @@ -200,7 +200,7 @@ let PDUBuilder = { } }; -let pendingEmulatorCmdCount = 0; +var pendingEmulatorCmdCount = 0; /** * Send emulator command with safe guard. @@ -258,7 +258,7 @@ function pushPermissions(aPermissions) { return deferred.promise; } -let voicemail; +var voicemail; /** * Add required permissions and test if |navigator.mozVoicemail| exists. diff --git a/dom/wappush/gonk/CpPduHelper.jsm b/dom/wappush/gonk/CpPduHelper.jsm index 3c0ef5418e..d9ff71efd8 100644 --- a/dom/wappush/gonk/CpPduHelper.jsm +++ b/dom/wappush/gonk/CpPduHelper.jsm @@ -6,16 +6,16 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -let WSP = {}; +var WSP = {}; Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); -let WBXML = {}; +var WBXML = {}; Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML); Cu.import("resource://services-crypto/utils.js"); Cu.import("resource://services-common/utils.js"); // set to true to see debug messages -let DEBUG = WBXML.DEBUG_ALL | false; +var DEBUG = WBXML.DEBUG_ALL | false; /** * Public identifier for CP @@ -468,7 +468,7 @@ const CP_VALUE_FIELDS = (function () { return names; })(); -let debug; +var debug; if (DEBUG) { debug = function (s) { dump("-$- CpPduHelper: " + s + "\n"); diff --git a/dom/wappush/gonk/SiPduHelper.jsm b/dom/wappush/gonk/SiPduHelper.jsm index 69367d0c22..c3b81f326c 100644 --- a/dom/wappush/gonk/SiPduHelper.jsm +++ b/dom/wappush/gonk/SiPduHelper.jsm @@ -6,13 +6,13 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -let WSP = {}; +var WSP = {}; Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); -let WBXML = {}; +var WBXML = {}; Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML); // set to true to see debug messages -let DEBUG = WBXML.DEBUG_ALL | false; +var DEBUG = WBXML.DEBUG_ALL | false; /** * Public identifier for SI diff --git a/dom/wappush/gonk/SlPduHelper.jsm b/dom/wappush/gonk/SlPduHelper.jsm index 1973b9cb4e..7870c37aec 100644 --- a/dom/wappush/gonk/SlPduHelper.jsm +++ b/dom/wappush/gonk/SlPduHelper.jsm @@ -6,13 +6,13 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -let WSP = {}; +var WSP = {}; Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); -let WBXML = {}; +var WBXML = {}; Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML); // set to true to see debug messages -let DEBUG = WBXML.DEBUG_ALL | false; +var DEBUG = WBXML.DEBUG_ALL | false; /** * Public identifier for SL diff --git a/dom/wappush/gonk/WapPushManager.js b/dom/wappush/gonk/WapPushManager.js index 0a23802917..96f8459b73 100644 --- a/dom/wappush/gonk/WapPushManager.js +++ b/dom/wappush/gonk/WapPushManager.js @@ -4,7 +4,7 @@ "use strict"; -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -161,7 +161,7 @@ this.WapPushManager = { }, }; -let debug; +var debug; if (DEBUG) { debug = function (s) { dump("-*- WapPushManager: " + s + "\n"); diff --git a/dom/wappush/gonk/WbxmlPduHelper.jsm b/dom/wappush/gonk/WbxmlPduHelper.jsm index 69e154af41..0ae93cc769 100644 --- a/dom/wappush/gonk/WbxmlPduHelper.jsm +++ b/dom/wappush/gonk/WbxmlPduHelper.jsm @@ -6,7 +6,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -let WSP = {}; +var WSP = {}; Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); /** diff --git a/dom/wappush/tests/header_helpers.js b/dom/wappush/tests/header_helpers.js index ef3adb8d85..8adb519651 100644 --- a/dom/wappush/tests/header_helpers.js +++ b/dom/wappush/tests/header_helpers.js @@ -3,8 +3,8 @@ "use strict"; -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; -let subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] +var subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader); diff --git a/dom/wappush/tests/test_cp_pdu_helper.js b/dom/wappush/tests/test_cp_pdu_helper.js index 5b68169e0c..4369cf6a00 100644 --- a/dom/wappush/tests/test_cp_pdu_helper.js +++ b/dom/wappush/tests/test_cp_pdu_helper.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let CP = {}; +var CP = {}; subscriptLoader.loadSubScript("resource://gre/modules/CpPduHelper.jsm", CP); CP.debug = do_print; @@ -30,7 +30,7 @@ function test_hmac(rawDataArray, mac, key, expectResult) { /* * Test data from OMA-TS-WAP_ProvCont-V1_1-2009 0421-C.pdf, clause 6.1 */ -let text_data_array = new Uint8Array([ +var text_data_array = new Uint8Array([ 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x3F, 0x3E, 0x3C, 0x21, 0x44, @@ -288,7 +288,7 @@ let text_data_array = new Uint8Array([ /* * Test data from OMA-TS-WAP_ProvCont-V1_1-20090421-C.pdf, Appendix C */ -let wbxml_data_array = new Uint8Array([ +var wbxml_data_array = new Uint8Array([ // WBXML version 1.3 0x03, // The Public Identifier for "-//WAPFORUM//DTD PROV 1.0//EN" @@ -444,7 +444,7 @@ let wbxml_data_array = new Uint8Array([ /* * Test data from CHT CP, with code page change */ -let wbxml_code_page_data_array = new Uint8Array([ +var wbxml_code_page_data_array = new Uint8Array([ 0x03, 0x0B, 0x6A, 0x00, 0x45, 0xC6, 0x56, 0x01, 0x87, 0x07, 0x06, 0x03, 0x43, 0x48, 0x54, 0x5F, 0x65, 0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0x01, @@ -513,11 +513,11 @@ let wbxml_code_page_data_array = new Uint8Array([ /* * Test data from OMA-TS-WAP_ProvCont-V1_1-20090421-C.pdf, clause 6.1 */ -let xml_header = +var xml_header = "<?xml version=\"1.0\"?>" + "<!DOCTYPE wap-provisioningdoc PUBLIC \"-//WAPFORUM//DTD PROV 1.0//EN\" \"http://www.wapforum.org/DTD/prov.dtd\">"; -let xml_body = +var xml_body = "<wap-provisioningdoc version=\"1.0\">" + "<characteristic type=\"PXLOGICAL\">" + "<parm name=\"PROXY-ID\" value=\"170.187.51.4\"/>" + @@ -572,7 +572,7 @@ let xml_body = "</characteristic>" + "</wap-provisioningdoc>"; -let wbxml_code_page_content = +var wbxml_code_page_content = "<wap-provisioningdoc>" + "<characteristic type=\"BOOTSTRAP\">" + "<parm name=\"NAME\" value=\"CHT_emome\"/>" + diff --git a/dom/wappush/tests/test_si_pdu_helper.js b/dom/wappush/tests/test_si_pdu_helper.js index 7609e45474..3e05a35df8 100644 --- a/dom/wappush/tests/test_si_pdu_helper.js +++ b/dom/wappush/tests/test_si_pdu_helper.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let SI = {}; +var SI = {}; subscriptLoader.loadSubScript("resource://gre/modules/SiPduHelper.jsm", SI); SI.debug = do_print; diff --git a/dom/wappush/tests/test_sl_pdu_helper.js b/dom/wappush/tests/test_sl_pdu_helper.js index 482c512d78..d1813a85cc 100644 --- a/dom/wappush/tests/test_sl_pdu_helper.js +++ b/dom/wappush/tests/test_sl_pdu_helper.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let SL = {}; +var SL = {}; subscriptLoader.loadSubScript("resource://gre/modules/SlPduHelper.jsm", SL); SL.debug = do_print; diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index 5da21a2bb9..654f04ee46 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -19,6 +19,10 @@ enum AudioContextState { "closed" }; +dictionary PeriodicWaveConstraints { + boolean disableNormalization = false; +}; + [Constructor, Constructor(AudioChannel audioChannelType)] interface AudioContext : EventTarget { @@ -88,7 +92,7 @@ interface AudioContext : EventTarget { [NewObject, Throws] OscillatorNode createOscillator(); [NewObject, Throws] - PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag); + PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag, optional PeriodicWaveConstraints constraints); }; diff --git a/dom/webidl/PageTransitionEvent.webidl b/dom/webidl/PageTransitionEvent.webidl index 3b8c319063..d4a050c192 100644 --- a/dom/webidl/PageTransitionEvent.webidl +++ b/dom/webidl/PageTransitionEvent.webidl @@ -4,9 +4,20 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/** + * The PageTransitionEvent interface is used for the pageshow and + * pagehide events, which are generic events that apply to both page + * load/unload and saving/restoring a document from session history. + */ + [Constructor(DOMString type, optional PageTransitionEventInit eventInitDict)] interface PageTransitionEvent : Event { + /** + * Set to true if the document has been or will be persisted across + * firing of the event. For example, if a document is being cached in + * session history, |persisted| is true for the PageHide event. + */ readonly attribute boolean persisted; }; diff --git a/dom/webidl/U2F.webidl b/dom/webidl/U2F.webidl index 0381f43202..3222b0dedd 100644 --- a/dom/webidl/U2F.webidl +++ b/dom/webidl/U2F.webidl @@ -68,6 +68,7 @@ dictionary SignResponse { callback U2FRegisterCallback = void(RegisterResponse response); callback U2FSignCallback = void(SignResponse response); +[Pref="security.webauth.u2f"] interface U2F { // These enumerations are defined in the FIDO U2F Javascript API under the // interface "ErrorCode" as constant integers, and also in the U2F.cpp file. diff --git a/dom/wifi/DOMWifiManager.js b/dom/wifi/DOMWifiManager.js index fa570ddf23..8bedfc3989 100644 --- a/dom/wifi/DOMWifiManager.js +++ b/dom/wifi/DOMWifiManager.js @@ -533,7 +533,7 @@ this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ MozWifiConnectionInfo ]); -let debug; +var debug; if (DEBUG) { debug = function (s) { dump("-*- DOMWifiManager component: " + s + "\n"); diff --git a/dom/wifi/WifiP2pManager.jsm b/dom/wifi/WifiP2pManager.jsm index de6fc25edc..c1b687438e 100644 --- a/dom/wifi/WifiP2pManager.jsm +++ b/dom/wifi/WifiP2pManager.jsm @@ -106,7 +106,7 @@ const GO_DHCP_SERVER_IP_RANGE = { endIp: "192.168.2.30" }; -let gDebug = false; +var gDebug = false; // Device Capability bitmap const DEVICE_CAPAB_SERVICE_DISCOVERY = 1; @@ -1188,7 +1188,7 @@ function P2pStateMachine(aP2pCommand, aNetUtil) { enter: function() { this.groupOwner = { macAddress: _groupInfo.goAddress, - ipAddress: _groupInfo.networkInterface.gateways[0], + ipAddress: _groupInfo.networkInterface.info.gateways[0], passphrase: _groupInfo.passphrase, ssid: _groupInfo.ssid, freq: _groupInfo.freq, @@ -1443,7 +1443,7 @@ function P2pStateMachine(aP2pCommand, aNetUtil) { debug("Client. Request IP from DHCP server on interface: " + _groupInfo.ifname); - aNetUtil.runDhcp(aInfo.ifname, function(dhcpData) { + aNetUtil.runDhcp(aInfo.ifname, 0, function(dhcpData) { if(!dhcpData || !dhcpData.info) { debug('Failed to run DHCP client'); onFailure(); diff --git a/dom/wifi/WifiWorker.js b/dom/wifi/WifiWorker.js index 56c0960d30..243ba8b978 100755 --- a/dom/wifi/WifiWorker.js +++ b/dom/wifi/WifiWorker.js @@ -416,7 +416,7 @@ var WifiManager = (function() { let currentNetwork = Object.create(null); currentNetwork.netId = manager.connectionInfo.id; - manager.getNetworkConfiguration(currentNetwork, function (){ + manager.getNetworkConfiguration(currentNetwork, function () { curNetworkKey = getNetworkKey(currentNetwork); // Add additional information to static ip configuration @@ -435,15 +435,19 @@ var WifiManager = (function() { // If the ssid of current connection is the same as configured ssid // It means we need update current connection to use static IP address. if (setNetworkKey == curNetworkKey) { - // Use configureInterface directly doesn't work, the network iterface + // Use configureInterface directly doesn't work, the network interface // and routing table is changed but still cannot connect to network // so the workaround here is disable interface the enable again to // trigger network reconnect with static ip. gNetworkService.disableInterface(manager.ifname, function (ok) { gNetworkService.enableInterface(manager.ifname, function (ok) { + callback(ok); }); }); + return; } + + callback(true); }); } @@ -865,6 +869,16 @@ var WifiManager = (function() { if (eventData.indexOf("CTRL-EVENT-EAP") === 0) { return handleWpaEapEvents(event); } + if (eventData.indexOf("CTRL-EVENT-ASSOC-REJECT") === 0) { + debug("CTRL-EVENT-ASSOC-REJECT: network error"); + notify("passwordmaybeincorrect"); + if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) { + manager.authenticationFailuresCount = 0; + debug("CTRL-EVENT-ASSOC-REJECT: disconnect network"); + notify("disconnected", {connectionInfo: manager.connectionInfo}); + } + return true; + } if (eventData.indexOf("WPS-TIMEOUT") === 0) { notifyStateChange({ state: "WPS_TIMEOUT", BSSID: null, id: -1 }); return true; @@ -1772,7 +1786,7 @@ function isWepHexKey(s) { } -let WifiNetworkInterface = { +var WifiNetworkInterface = { QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]), @@ -1839,8 +1853,8 @@ function WifiScanResult() {} // TODO Make the difference between a DOM-based network object and our // networks objects much clearer. -let netToDOM; -let netFromDOM; +var netToDOM; +var netFromDOM; function WifiWorker() { var self = this; @@ -2192,7 +2206,10 @@ function WifiWorker() { ssid: quote(WifiManager.connectionInfo.ssid), mode: MODE_ESS, frequency: 0}; - self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) }); + WifiManager.getNetworkConfiguration(self.currentNetwork, function (){ + // Notify again because we get complete network information. + self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) }); + }); break; case "ASSOCIATED": // set to full power mode when ready to do 4 way handsharke. @@ -2628,7 +2645,9 @@ WifiWorker.prototype = { // Only fire the event if the link speed changed or the signal // strength changed by more than 10%. - function tensPlace(percent) ((percent / 10) | 0) + function tensPlace(percent) { + return (percent / 10) | 0; + } if (last && last.linkSpeed === info.linkSpeed && last.ipAddress === info.ipAddress && @@ -3507,7 +3526,7 @@ WifiWorker.prototype = { }, setStaticIpMode: function(msg) { - const message = "WifiManager:setStaticMode:Return"; + const message = "WifiManager:setStaticIpMode:Return"; let self = this; let network = msg.data.network; let info = msg.data.info; @@ -3895,7 +3914,7 @@ WifiWorker.prototype = { this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiWorker]); -let debug; +var debug; function updateDebug() { if (DEBUG) { debug = function (s) { diff --git a/dom/wifi/test/marionette/head.js b/dom/wifi/test/marionette/head.js index dd28995bae..f4a212b119 100644 --- a/dom/wifi/test/marionette/head.js +++ b/dom/wifi/test/marionette/head.js @@ -43,13 +43,14 @@ const HOSTAPD_CONFIG_LIST = [ }, ]; -let gTestSuite = (function() { +var gTestSuite = (function() { let suite = {}; // Private member variables of the returned object |suite|. let wifiManager; let wifiOrigEnabled; let pendingEmulatorShellCount = 0; + let sdkVersion; /** * A wrapper function of "is". @@ -433,6 +434,23 @@ let gTestSuite = (function() { .then(event => event.target.result); } + /** + * Set the given network to static ip mode. + * + * Resolve when we set static ip mode successfully; reject when any error + * occurs. + * + * Fulfill params: (none) + * Reject params: (none) + * + * @return A deferred promise. + */ + function setStaticIpMode(aNetwork, aConfig) { + let request = wifiManager.setStaticIpMode(aNetwork, aConfig); + return wrapDomRequestAsPromise(request) + .then(event => event.target.result); + } + /** * Issue a request to scan all wifi available networks. * @@ -450,6 +468,57 @@ let gTestSuite = (function() { .then(event => event.target.result); } + /** + * Import a certificate with nickname and password. + * + * Resolve when we import certificate successfully; reject when any error + * occurs. + * + * Fulfill params: An object of certificate information. + * Reject params: (none) + * + * @return A deferred promise. + */ + function importCert(certBlob, password, nickname) { + let request = wifiManager.importCert(certBlob, password, nickname); + return wrapDomRequestAsPromise(request) + .then(event => event.target.result); + } + + /** + * Delete certificate of nickname. + * + * Resolve when we delete certificate successfully; reject when any error + * occurs. + * + * Fulfill params: (none) + * Reject params: (none) + * + * @return A deferred promise. + */ + function deleteCert(nickname) { + let request = wifiManager.deleteCert(nickname); + return wrapDomRequestAsPromise(request) + .then(event => event.target.result); + } + + /** + * Get list of imported certificates. + * + * Resolve when we get certificate list successfully; reject when any error + * occurs. + * + * Fulfill params: Nickname of imported certificate arranged by usage. + * Reject params: (none) + * + * @return A deferred promise. + */ + function getImportedCerts() { + let request = wifiManager.getImportedCerts(); + return wrapDomRequestAsPromise(request) + .then(event => event.target.result); + } + /** * Request wifi scan and verify the scan result as well. * @@ -707,7 +776,12 @@ let gTestSuite = (function() { .then(() => runEmulatorShellSafe(['hostapd', '-B', configFileName])) .then(function (reply) { // It may fail at the first time due to the previous ungracefully terminated one. - if (reply[0] === 'bind(PF_UNIX): Address already in use') { + if (reply.length === 0) { + // The hostapd starts successfully + return; + } + + if (reply[0].indexOf('bind(PF_UNIX): Address already in use') !== -1) { return startOneHostapd(aIndex); } }); @@ -784,10 +858,21 @@ let gTestSuite = (function() { * @return A deferred promise. */ function writeFile(aFilePath, aContent) { - if (-1 === aContent.indexOf(' ')) { - aContent = '"' + aContent + '"'; + const CONTENT_MAX_LENGTH = 900; + var commands = []; + for (var i = 0; i < aContent.length; i += CONTENT_MAX_LENGTH) { + var content = aContent.substr(i, CONTENT_MAX_LENGTH); + if (-1 === content.indexOf(' ')) { + content = '"' + content + '"'; + } + commands.push(['echo', '-n', content, i === 0 ? '>' : '>>', aFilePath]); } - return runEmulatorShellSafe(['echo', aContent, '>', aFilePath]); + + let chain = Promise.resolve(); + commands.forEach(function (command) { + chain = chain.then(() => runEmulatorShellSafe(command)); + }); + return chain; } /** @@ -964,111 +1049,149 @@ let gTestSuite = (function() { } /** - * Verify everything about routing when the wifi tethering is either on or off. + * Execute 'netcfg' shell and parse the result. * - * We use two unix commands to verify the routing: 'netcfg' and 'ip route'. - * For now the following two things will be checked: - * 1) The default route interface should be 'rmnet0'. - * 2) wlan0 is up and its ip is set to a private subnet. + * Resolve when the executing is successful and reject otherwise. * - * We also verify iptables output as netd's NatController will execute - * $ iptables -t nat -A POSTROUTING -o rmnet0 -j MASQUERADE + * Fulfill params: Command result object, each key of which is the interface + * name and value is { ip(string), prefix(string) }. + * Reject params: String that indicates the reason of rejection. * - * Resolve when the verification is successful and reject otherwise. + * @return A deferred promise. + */ + function exeAndParseNetcfg() { + return runEmulatorShellSafe(['netcfg']) + .then(function (aLines) { + // Sample output: + // + // lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00 + // eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56 + // rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:58 + // rmnet2 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59 + // rmnet3 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:5a + // wlan0 UP 192.168.1.1/24 0x00001043 52:54:00:12:34:5b + // sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00 + // rmnet0 UP 10.0.2.100/24 0x00001043 52:54:00:12:34:57 + // + let netcfgResult = {}; + aLines.forEach(function (aLine) { + let tokens = aLine.split(/\s+/); + if (tokens.length < 5) { + return; + } + let ifname = tokens[0]; + let [ip, prefix] = tokens[2].split('/'); + netcfgResult[ifname] = { ip: ip, prefix: prefix }; + }); + log("netcfg result:" + JSON.stringify(netcfgResult)); + + return netcfgResult; + }); + } + + /** + * Execute 'ip route' and parse the result. * - * Fulfill params: (none) + * Resolve when the executing is successful and reject otherwise. + * + * Fulfill params: Command result object, each key of which is the interface + * name and value is { src(string), gateway(string), + * default(boolean) }. * Reject params: String that indicates the reason of rejection. * * @return A deferred promise. */ - function verifyTetheringRouting(aEnabled) { - let netcfgResult = {}; - let ipRouteResult = {}; - - // Execute 'netcfg' and parse to |netcfgResult|, each key of which is the - // interface name and value is { ip(string) }. - function exeAndParseNetcfg() { - return runEmulatorShellSafe(['netcfg']) - .then(function (aLines) { - // Sample output: - // - // lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00 - // eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56 - // rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:58 - // rmnet2 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59 - // rmnet3 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:5a - // wlan0 UP 192.168.1.1/24 0x00001043 52:54:00:12:34:5b - // sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00 - // rmnet0 UP 10.0.2.100/24 0x00001043 52:54:00:12:34:57 - // - aLines.forEach(function (aLine) { - let tokens = aLine.split(/\s+/); - if (tokens.length < 5) { - return; - } - let ifname = tokens[0]; - let ip = (tokens[2].split('/'))[0]; - netcfgResult[ifname] = { ip: ip }; - }); - }); - } + function exeAndParseIpRoute() { + return runEmulatorShellSafe(['ip', 'route']) + .then(function (aLines) { + // Sample output: + // + // 10.0.2.4 via 10.0.2.2 dev rmnet0 + // 10.0.2.3 via 10.0.2.2 dev rmnet0 + // 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.1 + // 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 + // 10.0.2.0/24 dev rmnet0 proto kernel scope link src 10.0.2.100 + // default via 10.0.2.2 dev rmnet0 + // default via 10.0.2.2 dev eth0 metric 2 + // - // Execute 'ip route' and parse to |ipRouteResult|, each key of which is the - // interface name and value is { src(string), default(boolean) }. - function exeAndParseIpRoute() { - return runEmulatorShellSafe(['ip', 'route']) - .then(function (aLines) { - // Sample output: - // - // 10.0.2.4 via 10.0.2.2 dev rmnet0 - // 10.0.2.3 via 10.0.2.2 dev rmnet0 - // 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.1 - // 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 - // 10.0.2.0/24 dev rmnet0 proto kernel scope link src 10.0.2.100 - // default via 10.0.2.2 dev rmnet0 - // default via 10.0.2.2 dev eth0 metric 2 - // + let ipRouteResult = {}; + + // Parse source ip for each interface. + aLines.forEach(function (aLine) { + let tokens = aLine.trim().split(/\s+/); + let srcIndex = tokens.indexOf('src'); + if (srcIndex < 0 || srcIndex + 1 >= tokens.length) { + return; + } + let ifname = tokens[2]; + let src = tokens[srcIndex + 1]; + ipRouteResult[ifname] = { src: src, default: false, gateway: null }; + }); - // Parse source ip for each interface. - aLines.forEach(function (aLine) { - let tokens = aLine.trim().split(/\s+/); - let srcIndex = tokens.indexOf('src'); - if (srcIndex < 0 || srcIndex + 1 >= tokens.length) { + // Parse default interfaces. + aLines.forEach(function (aLine) { + let tokens = aLine.split(/\s+/); + if (tokens.length < 2) { + return; + } + if ('default' === tokens[0]) { + let ifnameIndex = tokens.indexOf('dev'); + if (ifnameIndex < 0 || ifnameIndex + 1 >= tokens.length) { return; } - let ifname = tokens[2]; - let src = tokens[srcIndex + 1]; - ipRouteResult[ifname] = { src: src, default: false }; - }); - - // Parse default interfaces. - aLines.forEach(function (aLine) { - let tokens = aLine.split(/\s+/); - if (tokens.length < 2) { + let ifname = tokens[ifnameIndex + 1]; + if (!ipRouteResult[ifname]) { return; } - if ('default' === tokens[0]) { - let ifnameIndex = tokens.indexOf('dev'); - if (ifnameIndex < 0 || ifnameIndex + 1 >= tokens.length) { - return; - } - let ifname = tokens[ifnameIndex + 1]; - if (ipRouteResult[ifname]) { - ipRouteResult[ifname].default = true; - } + ipRouteResult[ifname].default = true; + let gwIndex = tokens.indexOf('via'); + if (gwIndex < 0 || gwIndex + 1 >= tokens.length) { return; } - }); - + ipRouteResult[ifname].gateway = tokens[gwIndex + 1]; + return; + } }); + log("ip route result:" + JSON.stringify(ipRouteResult)); - } + return ipRouteResult; + }); + } + + /** + * Verify everything about routing when the wifi tethering is either on or off. + * + * We use two unix commands to verify the routing: 'netcfg' and 'ip route'. + * For now the following two things will be checked: + * 1) The default route interface should be 'rmnet0'. + * 2) wlan0 is up and its ip is set to a private subnet. + * + * We also verify iptables output as netd's NatController will execute + * $ iptables -t nat -A POSTROUTING -o rmnet0 -j MASQUERADE + * + * Resolve when the verification is successful and reject otherwise. + * + * Fulfill params: (none) + * Reject params: String that indicates the reason of rejection. + * + * @return A deferred promise. + */ + function verifyTetheringRouting(aEnabled) { + let netcfgResult; + let ipRouteResult; // Find MASQUERADE in POSTROUTING section. 'MASQUERADE' should be found // when tethering is enabled. 'MASQUERADE' shouldn't be found when tethering // is disabled. function verifyIptables() { - return runEmulatorShellSafe(['iptables', '-t', 'nat', '-L', 'POSTROUTING']) + let MASQUERADE_checkSection = 'POSTROUTING'; + if (sdkVersion > 15) { + // Check 'natctrl_nat_POSTROUTING' section after ICS. + MASQUERADE_checkSection = 'natctrl_nat_POSTROUTING'; + } + + return runEmulatorShellSafe(['iptables', '-t', 'nat', '-L', MASQUERADE_checkSection]) .then(function(aLines) { // $ iptables -t nat -L POSTROUTING // @@ -1096,9 +1219,6 @@ let gTestSuite = (function() { } function verifyDefaultRouteAndIp(aExpectedWifiTetheringIp) { - log(JSON.stringify(ipRouteResult)); - log(JSON.stringify(netcfgResult)); - if (aEnabled) { isOrThrow(ipRouteResult['rmnet0'].src, netcfgResult['rmnet0'].ip, 'rmnet0.ip'); isOrThrow(ipRouteResult['rmnet0'].default, true, 'rmnet0.default'); @@ -1111,7 +1231,9 @@ let gTestSuite = (function() { return verifyIptables() .then(exeAndParseNetcfg) + .then((aResult) => { netcfgResult = aResult; }) .then(exeAndParseIpRoute) + .then((aResult) => { ipRouteResult = aResult; }) .then(() => getSettings(SETTINGS_TETHERING_WIFI_IP)) .then(ip => verifyDefaultRouteAndIp(ip)); } @@ -1163,6 +1285,10 @@ let gTestSuite = (function() { throw 'window.navigator.mozWifiManager is NULL'; } wifiOrigEnabled = wifiManager.enabled; + }) + .then(() => runEmulatorShellSafe(['getprop', 'ro.build.version.sdk'])) + .then(aLines => { + sdkVersion = parseInt(aLines[0]); }); } @@ -1182,12 +1308,19 @@ let gTestSuite = (function() { suite.getFirstIndexBySsid = getFirstIndexBySsid; suite.testAssociate = testAssociate; suite.getKnownNetworks = getKnownNetworks; + suite.setStaticIpMode = setStaticIpMode; suite.requestWifiScan = requestWifiScan; suite.waitForConnected = waitForConnected; suite.forgetNetwork = forgetNetwork; suite.waitForTimeout = waitForTimeout; suite.waitForRilDataConnected = waitForRilDataConnected; suite.requestTetheringEnabled = requestTetheringEnabled; + suite.importCert = importCert; + suite.getImportedCerts = getImportedCerts; + suite.deleteCert = deleteCert; + suite.writeFile = writeFile; + suite.exeAndParseNetcfg = exeAndParseNetcfg; + suite.exeAndParseIpRoute = exeAndParseIpRoute; /** * Common test routine. @@ -1280,7 +1413,12 @@ let gTestSuite = (function() { return suite.doTest(function() { return verifyInitialState() .then(initTetheringTestEnvironment) + // Since stock hostapd is not reliable after ICS, we just + // turn off potential stock hostapd during testing to avoid + // interference. + .then(stopStockHostapd) .then(aTestCaseChain) + .then(startStockHostapd) .then(restoreToInitialState, function onreject(aReason) { return restoreToInitialState() .then(() => { throw aReason; }); // Re-throw the orignal reject reason. @@ -1288,5 +1426,61 @@ let gTestSuite = (function() { }); }; + /** + * Run test with imported certificate. + * + * Certificate will be imported and confirmed before running test, and be + * deleted after running test. + * + * Fulfill params: (none) + * + * @param certBlob + * Certificate content as Blob. + * @param password + * Password for importing certificate, only used for importing PKCS#12. + * @param nickanem + * Nickname for imported certificate. + * @param usage + * Expected usage of imported certificate. + * @param aTestCaseChain + * The test case entry point, which can be a function or a promise. + * + * @return A deferred promise. + */ + suite.doTestWithCertificate = function(certBlob, password, nickname, usage, aTestCaseChain) { + return suite.doTestWithoutStockAp(function() { + return ensureWifiEnabled(true) + // Import test certificate. + .then(() => importCert(certBlob, password, nickname)) + .then(function(info) { + // Check import result. + is(info.nickname, nickname, "Imported nickname"); + for (let i = 0; i < usage.length; i++) { + isnot(info.usage.indexOf(usage[i]), -1, "Usage " + usage[i]); + } + }) + // Get imported certificate list. + .then(getImportedCerts) + // Check if certificate exists in imported certificate list. + .then(function(list) { + for (let i = 0; i < usage.length; i++) { + isnot(list[usage[i]].indexOf(nickname), -1, + "Certificate \"" + nickname + "\" of usage " + usage[i] + " is imported"); + } + }) + // Run test case. + .then(aTestCaseChain) + // Delete imported certificates. + .then(() => deleteCert(nickname)) + // Check if certificate doesn't exist in imported certificate list. + .then(getImportedCerts) + .then(function(list) { + for (let i = 0; i < usage.length; i++) { + is(list[usage[i]].indexOf(nickname), -1, "Certificate is deleted"); + } + }) + }); + }; + return suite; })(); diff --git a/dom/wifi/test/marionette/manifest.ini b/dom/wifi/test/marionette/manifest.ini index 97123d10bf..5d245739c0 100644 --- a/dom/wifi/test/marionette/manifest.ini +++ b/dom/wifi/test/marionette/manifest.ini @@ -8,7 +8,17 @@ qemu = true [test_wifi_associate.js] [test_wifi_associate_wo_connect.js] [test_wifi_auto_connect.js] +[test_wifi_static_ip.js] [test_wifi_tethering_wifi_disabled.js] [test_wifi_tethering_wifi_inactive.js] [test_wifi_tethering_wifi_active.js] +[test_wifi_manage_server_certificate.js] +[test_wifi_manage_user_certificate.js] +[test_wifi_manage_pkcs12_certificate.js] +[test_wifi_associate_WPA_EAP_PEAP.js] +skip-if = android_version < '16' # EAP test not working before KK. +[test_wifi_associate_WPA_EAP_TTLS.js] +skip-if = android_version < '16' +[test_wifi_associate_WPA_EAP_TLS.js] +skip-if = android_version < '16' [test_wifi_enable_api.js] diff --git a/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_PEAP.js b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_PEAP.js new file mode 100644 index 0000000000..ce53da2d7a --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_PEAP.js @@ -0,0 +1,623 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +const SCAN_RETRY_CNT = 5; + +const EAP_USERNAME = 'username'; +const EAP_PASSWORD = 'password'; + +const SERVER_EAP_USER_CONF = { + path: HOSTAPD_CONFIG_PATH + 'hostapd.eap_user', + content: '* PEAP,TTLS,TLS\n' + + '"' + EAP_USERNAME + '" MSCHAPV2,TTLS-MSCHAPV2 "' + EAP_PASSWORD + '" [2]\n' +}; +const CA_CERT = { + path: HOSTAPD_CONFIG_PATH + 'ca.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIIDsTCCApmgAwIBAgIJAKxTf+8X8qngMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\n' + + 'BAYTAlRXMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTER\n' + + 'MA8GA1UEAwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdt\n' + + 'YWlsLmNvbTAgFw0xNDEyMjQxMTI4NTBaGA8yMjg4MTAwNzExMjg1MFowbjELMAkG\n' + + 'A1UEBhMCVFcxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCGNodWNrbGVl\n' + + 'MREwDwYDVQQDDAhjaHVja2xlZTEkMCIGCSqGSIb3DQEJARYVY2h1Y2tsaTA3MDZA\n' + + 'Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo3c2yFxY\n' + + 'o6gGg0I83jy00ME+MAfzCd+4ShL45ZLqysQP93jRBfPzU9ZuZ29ysVwgWIdqkZao\n' + + 'XTuV/NAW2GMGd8W1jQJ3J81fjb9wvhlny3rrACwvUn1N1S1BnM+BAAiDLGxEmvAQ\n' + + 'onp2aaa6HsHsYS8ONX+d2Qh4LEA4vupeSGAqJychCZv/l+aq/ErFZhFYB3CPUQEt\n' + + 'cClO24ucsIYP95lA0zhscnmAj06qplFD4Bv6IVrdDqujy1zNwCQwsJq/8OQdaTN/\n' + + 'h3y9pWvNKMBMM2niOUAjtuNpqsSK/lTS1WAT3PdtVECX9fYBi0Bg+HM92xs/6gt6\n' + + 'kh9jPV8keXHvSwIDAQABo1AwTjAdBgNVHQ4EFgQU7hBqhuG04xeCzrQ3ngx18ZJ3\n' + + 'lUswHwYDVR0jBBgwFoAU7hBqhuG04xeCzrQ3ngx18ZJ3lUswDAYDVR0TBAUwAwEB\n' + + '/zANBgkqhkiG9w0BAQsFAAOCAQEAFYX2iy680GAnBTttk0gyX6gk+8pYr3D22k/G\n' + + '6rvcjefzS7ELQPRKr6mfmwXq3mMf/4jiS2zI5zmXsestPYzHYxf2viQ6t7vr9XiJ\n' + + '3WfFjNw4ERlRisAvg0aqqTNNQq5v2VME4sdFZagy217f73C7azwCHl0bqOLH05rl\n' + + '8RubOxiHEj7ZybJqnRciK/bht4D+rZkwf4bBBmoloqH7xT0+rFQclpYXDGGjNUQB\n' + + 'LcHLF10xcr7g3ZVVu82fe6+d85gIGOIMR9+TKhdw6gO3CNcnDAj6gxksghgtcxmh\n' + + 'OzOggCn7nlIwImtsg2sZkpWB4lEi9hdv4lkNuyFjOL3bnuc+NA==\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_CERT = { + path: HOSTAPD_CONFIG_PATH + 'server.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIID1DCCArygAwIBAgIBADANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJUVzET\n' + + 'MBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIY2h1Y2tsZWUxETAPBgNVBAMM\n' + + 'CGNodWNrbGVlMSQwIgYJKoZIhvcNAQkBFhVjaHVja2xpMDcwNkBnbWFpbC5jb20w\n' + + 'IBcNMTQxMjI0MTEyOTQ5WhgPMjI4ODEwMDcxMTI5NDlaMG4xCzAJBgNVBAYTAlRX\n' + + 'MRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTERMA8GA1UE\n' + + 'AwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdtYWlsLmNv\n' + + 'bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdhQmKilTJbWZRxTiSV\n' + + 'rqIU+LYW1RKghx5o+0JpNRJVLuz5kBMaNskbbfUSNuHbEq0QA9BDKAZWIc4LSotk\n' + + 'lCo8TbcO9CJvJPQGGjGdHcohWX5vy6BE/OVE46CUteMFyZF6F8R2fNUww08iR/u1\n' + + 'YZebL5pWO1j43sPpAzEy6Tij2ACPt6EZcFaZG3SF2mVJWkCQnBqrojP65WUvZQqp\n' + + 'seUhW2YAS8Nu0Yrohgxz6VYk+cNDuDZVGs6qWRStZzJfYrfc76DtkHof5B14M+xp\n' + + 'XJaBLxN+whvnYkDTfinaCxnW1O7eXUltr87fLc5zmeBkgwaiaQuIdcfZm7vDUiz8\n' + + 'vnUCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH\n' + + 'ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFKK4f9/YavTHOfEiAB83Deac\n' + + '6gT5MB8GA1UdIwQYMBaAFO4QaobhtOMXgs60N54MdfGSd5VLMA0GCSqGSIb3DQEB\n' + + 'CwUAA4IBAQBWnO9o9KSJIqjoz5Nwll63ULOdcvgGdOeJIw1fcKQ817Rsp+TVcjcH\n' + + 'IrIADsT/QZGXRO/l6p1750e2iFtJEo1hsRaxtA1wWn2I9HO3+av2spQhr3jpYGPf\n' + + 'zpsMTp4RNYV7Q8+q1kZIz9PY4V1T0p6lveK8+fUj2hSLnxSj0QiGSJJtnEC3w4Rv\n' + + 'C9T6oUwIeToULmi+8FXQFdEqwKRU98DPq3eLzN28ZxUgoPE1C8+42D2UW8uyp/Gm\n' + + 'tGOa/k7nzkCdVqZI7lX7f0AjEvQgjtAMQ/k7Mhxx7TzW2HO+1YPMoKji6Z4WkNwt\n' + + 'JEj9ZUBSNt8B26UksJMBDkcvSegF3a7o\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_KEY = { + path: HOSTAPD_CONFIG_PATH + 'server.key', + content: '-----BEGIN RSA PRIVATE KEY-----\n' + + 'MIIEpAIBAAKCAQEAx2FCYqKVMltZlHFOJJWuohT4thbVEqCHHmj7Qmk1ElUu7PmQ\n' + + 'Exo2yRtt9RI24dsSrRAD0EMoBlYhzgtKi2SUKjxNtw70Im8k9AYaMZ0dyiFZfm/L\n' + + 'oET85UTjoJS14wXJkXoXxHZ81TDDTyJH+7Vhl5svmlY7WPjew+kDMTLpOKPYAI+3\n' + + 'oRlwVpkbdIXaZUlaQJCcGquiM/rlZS9lCqmx5SFbZgBLw27RiuiGDHPpViT5w0O4\n' + + 'NlUazqpZFK1nMl9it9zvoO2Qeh/kHXgz7GlcloEvE37CG+diQNN+KdoLGdbU7t5d\n' + + 'SW2vzt8tznOZ4GSDBqJpC4h1x9mbu8NSLPy+dQIDAQABAoIBAASG4Mr8hgaurEoC\n' + + 'iJOsElr7vunjetMBcg/uskW/vcS8ymP3Bp5oafYG+WgnEbfvEW18f5mq7K24JuxW\n' + + 'tUqU7ghHdjxByqk9fMlNmiqmNpbwSufkAeuRpWxPNBvhRH/zEbCL5R5A0nTEtqqF\n' + + 'TL0aUSzwCRSoAJD0lZo9ICVt0n3GsDyM9rqQg/uZmh1qsRdwPsRuYORND9g48rKq\n' + + '6WN9leskSxhhsYE2D9ocOFd9bNt8Zxejh9ppVSnG/KsIdt18iBzcabatgAQ046fb\n' + + 'Z3vprcZJLg93Sg2gSuVqlSTs3M2W8VQnm22/EBMb1y0M48MSRCgnbPLG/CcCLLfF\n' + + 'LwxCOgECgYEA/eYt67xyJ6JeAdxdwOZuT1WWGbFpLiG9+2OgiHumyRQ5969XMTWo\n' + + 'fIhMKchDdjoy9RR236\/\/EFCs7UEyB7+a7ODRzNiK2zCD8Smjp+21fUPSthEeQesk\n' + + 'eiMYICIu5Ay35x9sxIX+XOUVvRhPOGcD29GVeRnKh1inTHOz2dje8LkCgYEAyQeY\n' + + 'STi9jjCEcHkM1E/UeDiLfHHepLXi8wS41JNRHl5Jacp7XB5djAjKu/jf367/VpFy\n' + + 'GDDMetE7n8eWkrnAvovxOwZ000YDMtL1sUYSjL+XtBS5s6VY1p4qaSAY9nUUGrJh\n' + + 'JvtvsuI7SKTtL+60vjBOH7zDnvOdBgAp0utLhZ0CgYEAuLzzqrPKB8afShFSchn4\n' + + 'J2dpuLYahsNsXW7HDqeR2nsKFosRETAusLXnXPtnAq4kB6jlOarwFqnsuRCX24Vx\n' + + 'r2uBm9/vYL7zMdUPTA+s30ErHuhjsKjsOKYyVqcooSwT32pBFNk+E89nutfmRG7I\n' + + 'IvhjHuNCNqqtx/Xj5d1jkZkCgYBQicppC2Jl5OoqZVTOem0U/RJk+PnJ41TZJ7sk\n' + + '7yBAmmWvDH\/\/l+rCf4M5a6vFYcbKV9rt9h711X2dtciNX/3oWQh8LUoAmrwNUJc+\n' + + 'PmSQHvIYI3WCk2vUD+nN1B4sHxu+1lg11eYaNKiroeeknG2tBI1ICcgVlmQCU25u\n' + + 'IfZPwQKBgQCdO6QHhPLtcHUDNFA6FQ1jKL1iEd7G0JLVRz4Xkpkn1Vrr5MD6JFDa\n' + + '5ccabADyl0lpFqDIVJQIzLku2hOD2i9aBNCY0pL391HeOS7CkZX+TdOY1tquoBq5\n' + + 'MnmixZjDCVd2VcrVyTA6ntOBoharKFW0rH1PqU+qu7dZF7CBPbAdEw==\n' + + '-----END RSA PRIVATE KEY-----\n' +}; + +const WPA_EAP_AP_LIST = [ + { + ssid: 'WPA-EAP-PEAP', + ieee8021x: 1, + eapol_version: 1, + eap_server: 1, + eapol_key_index_workaround: 0, + eap_user_file: SERVER_EAP_USER_CONF.path, + ca_cert: CA_CERT.path, + server_cert: SERVER_CERT.path, + private_key: SERVER_KEY.path, + wpa: 3, + wpa_key_mgmt: 'WPA-EAP' + } +]; + +const CLIENT_PKCS12_CERT = { + nickname: 'client', + password: 'password', + usage: ['UserCert', 'ServerCert'], + content: [0x30, 0x82, 0x0E, 0x01, 0x02, 0x01, 0x03, 0x30, + 0x82, 0x0D, 0xC7, 0x06, 0x09, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, + 0x0D, 0xB8, 0x04, 0x82, 0x0D, 0xB4, 0x30, 0x82, + 0x0D, 0xB0, 0x30, 0x82, 0x08, 0x67, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, + 0x06, 0xA0, 0x82, 0x08, 0x58, 0x30, 0x82, 0x08, + 0x54, 0x02, 0x01, 0x00, 0x30, 0x82, 0x08, 0x4D, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x01, 0x30, 0x1C, 0x06, 0x0A, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, + 0x06, 0x30, 0x0E, 0x04, 0x08, 0x67, 0x7A, 0xF3, + 0x61, 0xBE, 0xE0, 0x51, 0xC1, 0x02, 0x02, 0x08, + 0x00, 0x80, 0x82, 0x08, 0x20, 0xFC, 0x6A, 0x79, + 0xA1, 0x6C, 0xAF, 0xBE, 0xEE, 0x62, 0x45, 0x33, + 0xB8, 0x48, 0xE1, 0x68, 0xA1, 0x15, 0x11, 0x4B, + 0x95, 0xCB, 0x77, 0xC0, 0x5D, 0xA2, 0xCB, 0xDB, + 0xD1, 0x83, 0x74, 0x60, 0xD7, 0xEC, 0x42, 0xA6, + 0x3A, 0x23, 0xF7, 0x85, 0xEB, 0xC1, 0xFE, 0x6A, + 0x57, 0x8E, 0xC1, 0x44, 0xF3, 0x1F, 0xFE, 0xB8, + 0x2D, 0x8C, 0x4D, 0xC9, 0x5B, 0xAE, 0x21, 0x2E, + 0x4C, 0x1A, 0xEB, 0x84, 0x09, 0xF3, 0x40, 0x92, + 0x39, 0x7F, 0x56, 0x02, 0x46, 0x61, 0x16, 0xDE, + 0x5C, 0x48, 0xB6, 0x0C, 0x1D, 0xD3, 0x5F, 0x10, + 0x9A, 0x39, 0xB8, 0x66, 0x31, 0xFC, 0x39, 0x71, + 0x87, 0x23, 0x46, 0x9D, 0xE8, 0x3C, 0x2B, 0xA1, + 0x39, 0x8A, 0xD3, 0xFF, 0xD9, 0x43, 0xB6, 0x61, + 0xC6, 0x67, 0x70, 0x40, 0xBD, 0xFE, 0xD3, 0xC1, + 0x68, 0xF5, 0xF7, 0xC8, 0x89, 0xD8, 0x17, 0xC5, + 0xE8, 0x3D, 0x29, 0xD5, 0x91, 0xDF, 0x1F, 0x56, + 0x74, 0x5A, 0xC4, 0xA8, 0x14, 0xBA, 0xD4, 0xFA, + 0x13, 0x49, 0x2A, 0x9F, 0x63, 0xF1, 0xB2, 0x45, + 0xF1, 0xF0, 0x2A, 0xDD, 0x75, 0x66, 0x8A, 0xF7, + 0xAB, 0x73, 0x86, 0x26, 0x9D, 0x1F, 0x07, 0xAD, + 0xD3, 0xFE, 0xE0, 0xA3, 0xED, 0xA0, 0x96, 0x3E, + 0x1E, 0x89, 0x86, 0x02, 0x4C, 0x28, 0xFD, 0x57, + 0xA1, 0x67, 0x55, 0xF0, 0x82, 0x3B, 0x7F, 0xCC, + 0x2A, 0x32, 0x01, 0x93, 0x1D, 0x8B, 0x66, 0x8A, + 0x20, 0x52, 0x84, 0xDD, 0x2C, 0xFD, 0xEE, 0x72, + 0xF3, 0x8C, 0x58, 0xB9, 0x99, 0xE5, 0xC1, 0x22, + 0x63, 0x59, 0x00, 0xE2, 0x76, 0xC5, 0x3A, 0x17, + 0x7F, 0x93, 0xE9, 0x67, 0x61, 0xAA, 0x10, 0xC3, + 0xD9, 0xC8, 0x24, 0x46, 0x5B, 0xBE, 0x8C, 0x1F, + 0x2D, 0x66, 0x48, 0xD2, 0x02, 0x11, 0xFB, 0x74, + 0x14, 0x76, 0x76, 0x5A, 0x98, 0x54, 0x35, 0xA7, + 0x85, 0x66, 0x20, 0x26, 0x8B, 0x13, 0x6F, 0x68, + 0xE3, 0xC9, 0x58, 0x7D, 0x1C, 0x3E, 0x01, 0x8D, + 0xF8, 0xD6, 0x7F, 0xCF, 0xA2, 0x07, 0xB7, 0x95, + 0xFD, 0xF0, 0x02, 0x34, 0x32, 0x30, 0xE8, 0xD4, + 0x57, 0x5E, 0x53, 0xFB, 0x54, 0xE2, 0x03, 0x32, + 0xCC, 0x52, 0x2E, 0xD2, 0x35, 0xD9, 0x58, 0x85, + 0x2D, 0xEC, 0x2D, 0x71, 0xD1, 0x8A, 0x29, 0xD0, + 0xB0, 0x24, 0xBD, 0x24, 0xDC, 0x1A, 0x28, 0x3F, + 0xA0, 0x12, 0x81, 0x15, 0x24, 0xC9, 0xB5, 0x4A, + 0x23, 0xB6, 0xA3, 0x45, 0x50, 0x2D, 0x73, 0x99, + 0x6B, 0x1C, 0xFB, 0xA4, 0x53, 0xD7, 0x5C, 0xF4, + 0x6C, 0xB0, 0xE5, 0x74, 0xB3, 0x76, 0xF8, 0xB1, + 0x0D, 0x59, 0x70, 0x9F, 0xCA, 0xDE, 0xF2, 0xAA, + 0x4C, 0x7D, 0x11, 0x54, 0xC4, 0x19, 0x0F, 0x36, + 0x4A, 0x62, 0xFF, 0x8B, 0x10, 0xCB, 0x93, 0x50, + 0xDA, 0x79, 0x5E, 0x4E, 0x09, 0x1F, 0x22, 0xC8, + 0x19, 0x85, 0xE9, 0xEE, 0xB7, 0x71, 0x65, 0xB9, + 0x10, 0xD2, 0x0A, 0x73, 0x5B, 0xA6, 0xDA, 0x37, + 0x46, 0x02, 0x00, 0x98, 0x9E, 0x20, 0x6C, 0x7D, + 0xC7, 0x69, 0xBB, 0xC2, 0x00, 0x40, 0x9C, 0x57, + 0x00, 0xC2, 0x36, 0x76, 0xE8, 0x2A, 0x8D, 0xAD, + 0x62, 0x57, 0xC8, 0xD0, 0x9D, 0x66, 0x27, 0x5A, + 0xD8, 0x0D, 0x35, 0x60, 0x28, 0x38, 0x62, 0x94, + 0x78, 0x36, 0x25, 0x58, 0xFD, 0xF8, 0x66, 0x1F, + 0x68, 0x04, 0x0F, 0xD8, 0x00, 0xDF, 0xA0, 0x6C, + 0x25, 0x42, 0x9A, 0x4C, 0xEB, 0x80, 0x13, 0x51, + 0x7D, 0x2D, 0xA8, 0x89, 0xD6, 0x1B, 0x67, 0x72, + 0x01, 0xF3, 0x2D, 0x16, 0x77, 0xFE, 0x22, 0xBC, + 0x8A, 0x45, 0x09, 0x1F, 0x9C, 0x2F, 0x2A, 0xA9, + 0x61, 0x5B, 0x4A, 0xE6, 0x64, 0x2C, 0x62, 0x1A, + 0x3A, 0x96, 0xE6, 0x0A, 0xAE, 0x05, 0x1A, 0xC8, + 0xCB, 0xD6, 0x8F, 0x3A, 0x4B, 0xE0, 0x7F, 0x82, + 0xB4, 0x98, 0xF1, 0x9D, 0xD7, 0x14, 0x76, 0x5E, + 0x77, 0x85, 0x87, 0xEC, 0x13, 0xDA, 0xFD, 0xAF, + 0xCB, 0xA3, 0x1C, 0x99, 0xC1, 0xFE, 0x17, 0x0C, + 0x40, 0x4D, 0x3C, 0x8F, 0x70, 0x86, 0x63, 0x64, + 0xB7, 0x75, 0xA8, 0x71, 0x36, 0xDC, 0x54, 0x10, + 0x57, 0x0C, 0xA8, 0xF2, 0xA1, 0xBB, 0xED, 0x03, + 0x41, 0x57, 0x34, 0x2C, 0x8F, 0x7C, 0xA0, 0x09, + 0xF3, 0x9E, 0x41, 0xB7, 0xA8, 0xD4, 0x66, 0x0D, + 0x0D, 0xC0, 0x6A, 0xFC, 0x6A, 0xA2, 0xAC, 0xE2, + 0x60, 0x00, 0xE3, 0xF7, 0x75, 0x43, 0x23, 0xEB, + 0xC8, 0x61, 0xFA, 0xB3, 0xB8, 0x28, 0xCE, 0xCA, + 0xF4, 0x47, 0x7F, 0x30, 0x6D, 0x61, 0x89, 0x47, + 0xA1, 0x4A, 0xFE, 0xD1, 0x21, 0x0B, 0x6D, 0xF4, + 0x3F, 0x00, 0x86, 0x30, 0x8E, 0x33, 0x21, 0x6F, + 0xDA, 0x15, 0xFD, 0x5F, 0xEC, 0x8E, 0xF1, 0x12, + 0x3F, 0xC9, 0x83, 0x0C, 0xCA, 0x22, 0x01, 0xF1, + 0x70, 0x5F, 0x1F, 0x66, 0xB5, 0xF8, 0x3E, 0x7A, + 0x6F, 0xDE, 0xDB, 0xA7, 0x8D, 0x18, 0x9E, 0xBE, + 0xDB, 0xAD, 0x3D, 0x66, 0x30, 0xC1, 0x6C, 0x0C, + 0x87, 0xB4, 0x65, 0x75, 0xE0, 0x9D, 0xEA, 0x16, + 0x0D, 0x07, 0x37, 0x33, 0xC5, 0xEC, 0x97, 0x93, + 0x37, 0xEB, 0x8E, 0x65, 0x9C, 0x40, 0x63, 0x6C, + 0x43, 0x60, 0xB0, 0x40, 0x4D, 0x85, 0xEF, 0xC2, + 0x47, 0x5F, 0xE7, 0x6B, 0xCB, 0x40, 0xE8, 0xEA, + 0xD8, 0xAB, 0xB1, 0x9A, 0x72, 0xDC, 0x4C, 0x14, + 0xFA, 0x43, 0x61, 0x5F, 0xA6, 0x5C, 0x3A, 0x05, + 0x17, 0x2E, 0x74, 0xF3, 0x5E, 0x45, 0xD9, 0x47, + 0xAA, 0x59, 0xB6, 0x8F, 0x42, 0x66, 0x42, 0x29, + 0x90, 0x95, 0x48, 0x46, 0x91, 0x88, 0x3C, 0x8C, + 0xDE, 0xCC, 0xED, 0xB3, 0xAA, 0x62, 0xEA, 0xBC, + 0xB4, 0x0C, 0x48, 0x4C, 0x53, 0x23, 0x5E, 0x24, + 0x85, 0xBF, 0x92, 0xDA, 0x14, 0xDB, 0x1A, 0x3D, + 0xEF, 0x30, 0xD9, 0x49, 0x64, 0x4D, 0xE5, 0x01, + 0xFC, 0xA4, 0x4B, 0xD1, 0x9F, 0xDE, 0x96, 0x7F, + 0x50, 0xBC, 0x4D, 0x38, 0x44, 0xE9, 0x23, 0x5F, + 0x37, 0x57, 0x1A, 0xA6, 0x52, 0x5A, 0x0F, 0x4F, + 0x87, 0x33, 0x4A, 0x7B, 0x66, 0xEE, 0x3D, 0x66, + 0x0A, 0x63, 0x39, 0x1F, 0x23, 0x38, 0x35, 0x73, + 0x60, 0x5E, 0x47, 0x20, 0x4F, 0xC0, 0xC8, 0x3C, + 0x09, 0xF9, 0x29, 0x4F, 0x5E, 0x55, 0x69, 0xC4, + 0x6B, 0xE8, 0xF8, 0x91, 0xC0, 0x22, 0x65, 0x15, + 0x1E, 0xFB, 0xB9, 0x61, 0xCE, 0x45, 0xBE, 0x2B, + 0xEE, 0xB9, 0x04, 0x2B, 0xFD, 0xAE, 0x61, 0x1C, + 0x3D, 0x3D, 0x7C, 0xBF, 0xC1, 0xF7, 0x3C, 0x4E, + 0x9E, 0x0E, 0x54, 0xC8, 0xAD, 0xA9, 0xDF, 0x43, + 0x49, 0xB9, 0x41, 0x05, 0xE5, 0xF1, 0x49, 0xAA, + 0x77, 0x6C, 0x34, 0x5B, 0x93, 0x24, 0x24, 0x23, + 0x74, 0x68, 0x11, 0xCE, 0x15, 0x80, 0xA1, 0xA4, + 0x1F, 0x8D, 0x81, 0xCD, 0xB2, 0x98, 0xCA, 0x14, + 0x0B, 0x0C, 0x61, 0x50, 0x69, 0x72, 0xAE, 0xFA, + 0x8B, 0xC0, 0x3F, 0x0D, 0xE7, 0xF2, 0x0F, 0xEB, + 0xC1, 0x11, 0xB9, 0x10, 0x03, 0x6A, 0xF5, 0x97, + 0x3C, 0x53, 0x2F, 0x67, 0x86, 0x09, 0x6A, 0xE3, + 0x28, 0xC0, 0x78, 0xC8, 0xB4, 0x39, 0x8E, 0xD1, + 0xCE, 0x25, 0xE8, 0x66, 0xF7, 0x09, 0x40, 0x7D, + 0x81, 0xFB, 0xAF, 0xFA, 0x59, 0xC4, 0x9B, 0x2B, + 0x83, 0x45, 0x5B, 0xA8, 0x66, 0x9E, 0x38, 0xC8, + 0xFD, 0xAC, 0xF2, 0x2D, 0x21, 0xDE, 0x50, 0x4C, + 0x03, 0xCB, 0x88, 0x42, 0xDD, 0x84, 0x09, 0x99, + 0x8E, 0x8B, 0x40, 0x97, 0x1B, 0x14, 0x85, 0x37, + 0x11, 0x01, 0xE0, 0x74, 0x6B, 0x33, 0x52, 0x8C, + 0x68, 0x3A, 0x89, 0xB2, 0xAF, 0x35, 0xE6, 0x65, + 0xC3, 0x58, 0x70, 0xD2, 0xE7, 0x1F, 0x1F, 0xF6, + 0xE5, 0x0A, 0xB1, 0xFE, 0xD0, 0xC9, 0x51, 0x50, + 0xE7, 0xFD, 0x58, 0xF5, 0xC4, 0x58, 0x65, 0x94, + 0xD1, 0x57, 0x55, 0x5E, 0xD2, 0x27, 0x98, 0xAF, + 0xE7, 0x55, 0x0B, 0x87, 0x50, 0x9B, 0xEF, 0xE8, + 0x2B, 0xFC, 0xE7, 0x3B, 0x4E, 0xD7, 0xB7, 0x4D, + 0xF4, 0xBC, 0xF4, 0x88, 0x63, 0xE4, 0x8A, 0x20, + 0x4B, 0x22, 0xB0, 0xA0, 0x53, 0x7F, 0xA8, 0xC9, + 0x0C, 0xF8, 0xD7, 0xBD, 0x46, 0x39, 0xA7, 0x7D, + 0xDD, 0x10, 0x91, 0x50, 0x54, 0x06, 0x47, 0xF0, + 0x3C, 0xAA, 0x43, 0x40, 0xF8, 0x54, 0xDD, 0x8A, + 0xEA, 0x8A, 0x0B, 0xA5, 0x7F, 0xCD, 0x5E, 0xAA, + 0x02, 0x2E, 0x1F, 0xC6, 0x50, 0x15, 0xF8, 0x0A, + 0x0C, 0x1B, 0x3C, 0x55, 0x3A, 0xC3, 0x6F, 0x88, + 0xD7, 0xBF, 0xB1, 0x02, 0xCC, 0xE0, 0x08, 0x29, + 0x97, 0xD2, 0xAA, 0x23, 0xC4, 0x6D, 0xE3, 0xE3, + 0x76, 0x39, 0x92, 0xC3, 0x2E, 0x7A, 0xE2, 0x98, + 0xD1, 0xFC, 0xAE, 0xCC, 0x95, 0xD8, 0xB4, 0xDC, + 0x92, 0xEA, 0x6A, 0x5F, 0xF2, 0x92, 0x17, 0x0B, + 0x8D, 0xC3, 0xFA, 0x9C, 0x62, 0xCE, 0x44, 0x8D, + 0xC3, 0x1E, 0xC3, 0xB2, 0xD5, 0x00, 0xCD, 0xB4, + 0x9E, 0x2D, 0x7B, 0xF2, 0x98, 0xA3, 0x00, 0x8B, + 0x81, 0x30, 0x77, 0x5B, 0x02, 0x99, 0xB1, 0xCD, + 0xC3, 0x1D, 0x74, 0x74, 0xEF, 0x41, 0xCB, 0x69, + 0x63, 0x8E, 0xA6, 0xD3, 0x2D, 0x3E, 0x1F, 0x1D, + 0x12, 0x9E, 0xD9, 0x18, 0x67, 0x06, 0xAF, 0x37, + 0x29, 0xAD, 0x65, 0xD8, 0xEB, 0x71, 0xC4, 0x7D, + 0x94, 0x3D, 0xEA, 0xCC, 0xDF, 0x72, 0x41, 0x51, + 0x3C, 0xA1, 0x66, 0x98, 0x32, 0x32, 0x40, 0x54, + 0xB0, 0x2F, 0xEB, 0xCE, 0xDF, 0x4A, 0x64, 0xFB, + 0x9A, 0x90, 0xDC, 0xF6, 0x6F, 0xA9, 0xD4, 0xCA, + 0xCB, 0x91, 0xC4, 0xFE, 0xEE, 0x9C, 0x01, 0x50, + 0x2E, 0xAC, 0xCC, 0x5F, 0x89, 0xD0, 0x91, 0xA3, + 0xD9, 0xF9, 0x4B, 0x8D, 0xDE, 0x6C, 0x60, 0x21, + 0x19, 0xB1, 0xD3, 0x4D, 0x75, 0x56, 0x6F, 0xB8, + 0x25, 0xA4, 0x92, 0x4F, 0x12, 0xF5, 0x8F, 0xC1, + 0x17, 0x4B, 0xB3, 0x34, 0x21, 0x22, 0xAC, 0x52, + 0xD2, 0x64, 0xC9, 0x9A, 0x7D, 0xFC, 0xC0, 0x0A, + 0x89, 0x34, 0xFF, 0x08, 0xD3, 0x04, 0xDC, 0xFE, + 0x7C, 0xB3, 0xB8, 0xFD, 0x85, 0xDD, 0x79, 0x51, + 0xA7, 0x89, 0xE8, 0xF1, 0x23, 0xB1, 0xDF, 0xD7, + 0x1F, 0x7B, 0xB1, 0x5D, 0x42, 0xF9, 0x61, 0xF8, + 0xDC, 0x81, 0x04, 0xF1, 0xCC, 0xFA, 0xD7, 0xED, + 0xBF, 0x47, 0xAC, 0xBD, 0xE5, 0xFA, 0xAC, 0xB3, + 0x1C, 0xD9, 0xA1, 0xB3, 0x60, 0xEE, 0x9C, 0x8A, + 0x36, 0x57, 0xB4, 0x2F, 0xA1, 0xA2, 0xF3, 0xE2, + 0x09, 0x9A, 0x6E, 0x43, 0x9B, 0xE5, 0x93, 0xB8, + 0x3D, 0x9E, 0x9F, 0xC1, 0xC6, 0x0D, 0x02, 0xEB, + 0x4D, 0x38, 0xE9, 0xB4, 0x9F, 0xEA, 0x33, 0x8C, + 0x07, 0xD8, 0xB4, 0x71, 0xAD, 0xE5, 0x43, 0xB2, + 0xCC, 0x55, 0x93, 0x6A, 0xDB, 0x1E, 0x80, 0xDB, + 0xC2, 0xEA, 0x42, 0x8E, 0xFC, 0x86, 0x44, 0xC9, + 0x8A, 0xC4, 0xF2, 0x46, 0xA7, 0x39, 0x50, 0x0D, + 0x1A, 0xAA, 0x07, 0x04, 0xBE, 0xD4, 0xCE, 0x62, + 0x4D, 0x0F, 0x91, 0x7D, 0x29, 0x88, 0x9C, 0x4C, + 0xAF, 0xF7, 0xD8, 0x40, 0x93, 0x88, 0xC7, 0x20, + 0xD2, 0x17, 0x2A, 0xC4, 0x92, 0x72, 0xD0, 0xC0, + 0x4E, 0x56, 0x47, 0xB1, 0x27, 0x02, 0xE6, 0x61, + 0x82, 0x5E, 0xC8, 0x2E, 0x90, 0xD2, 0x31, 0x22, + 0xE2, 0xA9, 0x4A, 0x91, 0x45, 0x69, 0xB1, 0xA5, + 0x0F, 0x66, 0x2C, 0x30, 0xAD, 0x7F, 0x1B, 0x0E, + 0x22, 0x17, 0x60, 0x2E, 0x3D, 0x7F, 0x7F, 0x8C, + 0x33, 0x51, 0xA0, 0x25, 0xDE, 0xFD, 0x75, 0xBC, + 0xEF, 0xE6, 0xE7, 0x20, 0x04, 0x5A, 0xEC, 0x50, + 0x21, 0x48, 0x56, 0x98, 0xE2, 0x33, 0x6D, 0x22, + 0x5C, 0xC3, 0xFB, 0xFC, 0x6F, 0xB3, 0xA7, 0x8E, + 0x6F, 0x67, 0x70, 0x9D, 0xDA, 0x02, 0x01, 0x59, + 0x7B, 0x3D, 0x2B, 0x38, 0xCC, 0x0F, 0x44, 0x3D, + 0xFB, 0x9A, 0xB3, 0x23, 0x15, 0x50, 0x6E, 0xBF, + 0x8B, 0xA1, 0x94, 0x33, 0xE5, 0x7B, 0x88, 0x4E, + 0xCB, 0x6D, 0x9F, 0xBF, 0xBC, 0x7A, 0xA8, 0x1E, + 0x68, 0x25, 0xED, 0x8E, 0x53, 0x21, 0x72, 0xC5, + 0x70, 0xB3, 0xE4, 0xA6, 0xA1, 0x5A, 0x2D, 0xC8, + 0x43, 0x9D, 0x60, 0x77, 0x78, 0xE0, 0xC4, 0xAF, + 0xC8, 0x29, 0xBA, 0xD0, 0x4D, 0x39, 0x83, 0x51, + 0xA7, 0x10, 0x7F, 0x0C, 0x34, 0x0E, 0x6C, 0x75, + 0x26, 0xD7, 0xD6, 0xC7, 0x32, 0x53, 0xAF, 0x4E, + 0xBE, 0xF2, 0xC2, 0x0F, 0x99, 0x23, 0xB9, 0xE1, + 0xC8, 0xB4, 0xBC, 0x5A, 0xC6, 0xCB, 0xEB, 0x4D, + 0x28, 0x56, 0x72, 0xFE, 0x1B, 0x2C, 0x5D, 0xE3, + 0xBC, 0xC7, 0xA3, 0xC0, 0x7D, 0x27, 0xF0, 0xD0, + 0x4F, 0x3F, 0x1F, 0xF7, 0x87, 0x15, 0xF2, 0xEA, + 0xD4, 0x03, 0x6D, 0x2F, 0xD4, 0x8E, 0x50, 0x4B, + 0x05, 0xBF, 0xF7, 0x8C, 0x67, 0x5A, 0xDC, 0x4D, + 0xCD, 0xCF, 0x9D, 0x02, 0xB6, 0xE7, 0xAE, 0x49, + 0xD1, 0x7C, 0x00, 0xE7, 0x3B, 0xEA, 0xFB, 0x0D, + 0x2A, 0x7B, 0x41, 0x33, 0x66, 0xD0, 0x29, 0x9F, + 0xB3, 0x8A, 0x71, 0xB0, 0xE2, 0x76, 0xA9, 0xDB, + 0xFD, 0x64, 0x04, 0x69, 0xDF, 0x89, 0x1F, 0x56, + 0x86, 0x92, 0xD9, 0xD9, 0xB9, 0xF3, 0x4F, 0xAC, + 0xAE, 0x61, 0x48, 0x20, 0xCE, 0x3C, 0x2B, 0x44, + 0xAB, 0x42, 0xFA, 0xAB, 0x2E, 0x94, 0x82, 0xC8, + 0xD9, 0x97, 0xCF, 0x27, 0xDF, 0xAC, 0xAC, 0xE7, + 0xCA, 0xB2, 0x84, 0xAB, 0xF2, 0x5D, 0xDF, 0x56, + 0x0C, 0x8C, 0x07, 0x3C, 0x3D, 0xA8, 0xDD, 0xBE, + 0xFF, 0x4E, 0x28, 0x0D, 0xB2, 0x2D, 0xE6, 0x9D, + 0x44, 0x21, 0xCB, 0xE7, 0x33, 0x63, 0x22, 0x8F, + 0x4C, 0xFF, 0xB6, 0x1D, 0x9A, 0x71, 0x3F, 0xB1, + 0x29, 0xAE, 0x3A, 0x35, 0xEE, 0x9C, 0x97, 0x68, + 0xA7, 0x52, 0x66, 0x01, 0xD8, 0x9A, 0x5D, 0xF4, + 0xB3, 0x2F, 0x5C, 0xD4, 0x0E, 0xF9, 0xCF, 0x07, + 0xF6, 0x8C, 0xBA, 0xA6, 0x8D, 0x6B, 0xC6, 0x01, + 0xC2, 0x69, 0xAE, 0x60, 0x08, 0x1A, 0x0E, 0x3F, + 0xAE, 0x60, 0x29, 0xF3, 0x48, 0x0D, 0xE0, 0xD0, + 0xAE, 0x52, 0x44, 0xE9, 0x7F, 0x1F, 0x92, 0x5F, + 0x71, 0xAD, 0xEC, 0x6B, 0x47, 0x66, 0x92, 0x22, + 0x27, 0xAE, 0x6E, 0x25, 0xCD, 0xF3, 0x5F, 0x55, + 0x59, 0xBD, 0x73, 0xCE, 0x2B, 0x7E, 0x99, 0x44, + 0x56, 0x70, 0xA3, 0xE7, 0x7A, 0x59, 0x75, 0xD8, + 0x48, 0x0C, 0x39, 0x2B, 0xD7, 0x53, 0xC6, 0xAD, + 0x4A, 0x6F, 0xB4, 0x14, 0x96, 0xDF, 0xF2, 0x4A, + 0x0C, 0xA2, 0xD5, 0x29, 0x98, 0x7C, 0x42, 0x87, + 0xD9, 0x1F, 0x97, 0x61, 0xD9, 0xBF, 0x99, 0x4F, + 0x2C, 0x4C, 0x75, 0xAC, 0xB8, 0x06, 0x75, 0xD6, + 0x87, 0x76, 0x7E, 0xE3, 0x23, 0x4B, 0xEA, 0x1A, + 0x1A, 0xF4, 0xB7, 0x09, 0xAF, 0x53, 0xEB, 0xA6, + 0x39, 0x10, 0xFE, 0xD4, 0xEB, 0x1B, 0xAE, 0x38, + 0x31, 0x33, 0xBA, 0x68, 0xEE, 0xC7, 0x65, 0x76, + 0xFB, 0x49, 0x77, 0xD4, 0x19, 0xC4, 0xE6, 0xA7, + 0x05, 0xFE, 0x2A, 0xDA, 0x39, 0x99, 0x1A, 0x92, + 0xD2, 0xF0, 0x61, 0x97, 0xF6, 0x06, 0x6C, 0x88, + 0x7B, 0x6F, 0x60, 0xE6, 0x70, 0x08, 0xF0, 0xB4, + 0x6B, 0x39, 0x6F, 0x05, 0x41, 0x81, 0xF9, 0xBE, + 0x7A, 0x51, 0xC4, 0x75, 0xB0, 0x6A, 0x89, 0xA0, + 0xA6, 0x9A, 0x5B, 0xEE, 0x7D, 0x78, 0x17, 0x5F, + 0x9F, 0x3B, 0x7D, 0xDD, 0x8A, 0x9E, 0xAA, 0x1A, + 0xDA, 0x49, 0x08, 0xE9, 0xFD, 0x91, 0xA6, 0xFA, + 0xCE, 0xCF, 0x67, 0xDF, 0x0F, 0xC9, 0xD6, 0x38, + 0xD9, 0xD5, 0xD1, 0xC0, 0x76, 0x59, 0x42, 0x53, + 0xBF, 0x48, 0xE9, 0x11, 0x74, 0xC7, 0x11, 0xD8, + 0xE7, 0x8E, 0xD3, 0xC8, 0x25, 0xA1, 0x26, 0x50, + 0xBB, 0xB4, 0x35, 0xAF, 0xAF, 0x06, 0x23, 0x69, + 0x3E, 0x30, 0xFD, 0x7B, 0x34, 0x83, 0x07, 0xD0, + 0xF0, 0x0F, 0x6C, 0x9A, 0x13, 0x5D, 0xC2, 0x7B, + 0xDF, 0x6F, 0xDD, 0x8E, 0xF4, 0x30, 0x82, 0x05, + 0x41, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x05, 0x32, + 0x04, 0x82, 0x05, 0x2E, 0x30, 0x82, 0x05, 0x2A, + 0x30, 0x82, 0x05, 0x26, 0x06, 0x0B, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, + 0x02, 0xA0, 0x82, 0x04, 0xEE, 0x30, 0x82, 0x04, + 0xEA, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, + 0x0E, 0x04, 0x08, 0x74, 0xC0, 0x84, 0x8F, 0xC7, + 0x74, 0x5E, 0x21, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xC8, 0x1E, 0xF4, 0xE9, 0x07, 0x27, + 0x9E, 0x5A, 0xC9, 0x39, 0x1D, 0x37, 0x2C, 0x06, + 0x4B, 0x57, 0xEA, 0xC5, 0x42, 0x9A, 0x60, 0xD5, + 0x42, 0xB2, 0x34, 0x2D, 0xD3, 0x88, 0x7C, 0x78, + 0x87, 0xB6, 0xE9, 0x42, 0x44, 0x1F, 0x67, 0x32, + 0x92, 0x54, 0x22, 0xDA, 0xB2, 0x43, 0xE7, 0x40, + 0xBE, 0x1F, 0xAF, 0x3A, 0xCD, 0x2A, 0x9F, 0xD7, + 0x44, 0x5B, 0x37, 0x69, 0x85, 0xDF, 0xEB, 0x2A, + 0xB9, 0xE2, 0x92, 0x3B, 0xEA, 0xD5, 0x42, 0x53, + 0x95, 0x4A, 0xB0, 0x1B, 0xA5, 0xEF, 0xA6, 0x0D, + 0x29, 0xF4, 0x33, 0xFE, 0xD7, 0x49, 0x04, 0x1E, + 0x8C, 0xAD, 0x63, 0x1E, 0x79, 0x63, 0x74, 0x0C, + 0xE5, 0x5E, 0xA2, 0x2C, 0xBE, 0xB8, 0x90, 0xCE, + 0x06, 0x25, 0xBF, 0xD1, 0x5A, 0x50, 0xCF, 0x3B, + 0x52, 0xE2, 0xA7, 0xFF, 0x19, 0x02, 0xCF, 0xD0, + 0x9B, 0xD9, 0xF7, 0x28, 0x07, 0x38, 0x1F, 0xF2, + 0xAF, 0x44, 0x91, 0x3F, 0x0F, 0xB6, 0x6E, 0x8C, + 0xC0, 0x32, 0x92, 0xC0, 0xCD, 0x25, 0x98, 0x67, + 0xF1, 0x47, 0x52, 0x50, 0xF0, 0xA3, 0x7B, 0xE6, + 0x74, 0xDC, 0x72, 0x28, 0xC8, 0xAB, 0xB3, 0x31, + 0x7D, 0xA3, 0xF7, 0xC7, 0xD1, 0xE6, 0x99, 0xB4, + 0xB6, 0x5A, 0x3A, 0x4D, 0x83, 0x4F, 0xB8, 0xB5, + 0x86, 0xF8, 0x37, 0x7F, 0xA0, 0x16, 0x2F, 0x3C, + 0x62, 0x7A, 0xD4, 0x3A, 0xEB, 0xC2, 0xE8, 0x03, + 0x49, 0x17, 0x9E, 0xFB, 0xD7, 0xAF, 0x91, 0x32, + 0xFD, 0xEA, 0x4F, 0x64, 0xC6, 0x6E, 0x02, 0xEA, + 0xC4, 0xC8, 0x1F, 0x16, 0xC5, 0x4C, 0xFB, 0xC5, + 0x42, 0xF5, 0x85, 0x05, 0x92, 0x59, 0x4B, 0x31, + 0xE5, 0xE9, 0x69, 0xE7, 0x02, 0x98, 0x33, 0xBA, + 0x4C, 0x17, 0x09, 0xEF, 0x89, 0x20, 0xFA, 0x83, + 0x9F, 0xAE, 0x0E, 0x1B, 0x7D, 0x98, 0xB9, 0xF2, + 0x3C, 0x0F, 0xB7, 0x1C, 0x72, 0xDF, 0x17, 0x84, + 0x7F, 0x0A, 0xFD, 0x12, 0x3C, 0x6F, 0x68, 0x5D, + 0x45, 0xEB, 0xB8, 0xD6, 0x24, 0x65, 0x42, 0x75, + 0x5C, 0xC2, 0xF3, 0x3A, 0x6A, 0x4E, 0x51, 0x34, + 0x1B, 0xB6, 0x81, 0xB2, 0x8A, 0xEF, 0x28, 0xA4, + 0xC5, 0x88, 0x9A, 0x97, 0xE0, 0xEF, 0x31, 0x12, + 0x01, 0x7E, 0x1B, 0x43, 0x0F, 0x27, 0x80, 0x87, + 0x98, 0xC5, 0xD5, 0x83, 0xCB, 0x4B, 0xB7, 0x01, + 0x79, 0x60, 0xA1, 0x1A, 0x03, 0x05, 0xC6, 0x36, + 0x04, 0x31, 0x3C, 0x06, 0xDB, 0x08, 0xA8, 0xDA, + 0x8E, 0x32, 0x19, 0x91, 0xF1, 0x0D, 0x61, 0x6F, + 0xE4, 0xB2, 0x79, 0x8A, 0xDE, 0xF4, 0xF7, 0xFB, + 0x2C, 0x23, 0x5B, 0xD9, 0x64, 0x2F, 0xB7, 0xB3, + 0x8B, 0xCA, 0xB8, 0x8C, 0x1D, 0x3B, 0x49, 0x05, + 0x38, 0xA1, 0xE5, 0x8C, 0x1A, 0xDC, 0xA5, 0x61, + 0xFE, 0xF4, 0x2B, 0xDC, 0x77, 0x28, 0xF6, 0x19, + 0xE7, 0xB7, 0x8F, 0x4D, 0x27, 0x2D, 0xED, 0x8A, + 0x3F, 0x3D, 0xDC, 0x9F, 0xD1, 0x30, 0xFF, 0xD6, + 0xC3, 0xBE, 0x41, 0x25, 0xE3, 0xA5, 0x9B, 0x73, + 0xDF, 0x6A, 0xD9, 0xF9, 0x70, 0x84, 0x02, 0x4C, + 0x35, 0xD4, 0x3E, 0x05, 0x76, 0x3A, 0xDC, 0x6D, + 0x5A, 0x81, 0xB3, 0x94, 0xF7, 0x22, 0xF7, 0xDC, + 0xC1, 0x43, 0x31, 0x57, 0x5B, 0x42, 0x9A, 0x0B, + 0xF4, 0x95, 0x30, 0xA9, 0xBB, 0xD8, 0x06, 0xFB, + 0x1D, 0x6F, 0x9B, 0xC3, 0xBB, 0xF3, 0xBF, 0xFB, + 0xB4, 0x9F, 0x35, 0x64, 0x0A, 0x69, 0xB7, 0xD1, + 0x3E, 0xCA, 0x78, 0x07, 0x04, 0x03, 0x79, 0xD4, + 0xF3, 0xA8, 0xEC, 0x18, 0xDB, 0x03, 0x5E, 0x47, + 0xD7, 0xD0, 0x56, 0x2C, 0x74, 0x94, 0x86, 0x04, + 0x46, 0xB8, 0xD4, 0x35, 0x0A, 0x7B, 0xE6, 0x78, + 0xC4, 0x43, 0x3C, 0x56, 0xCC, 0x37, 0x8B, 0xFD, + 0xE8, 0xF4, 0x57, 0xEA, 0xAE, 0xCF, 0x36, 0x97, + 0x12, 0xAC, 0x39, 0xCF, 0x7C, 0xEF, 0x22, 0x67, + 0x01, 0xEC, 0xD8, 0x09, 0x49, 0x4E, 0xE3, 0x74, + 0xDD, 0x39, 0xE1, 0x39, 0xD7, 0x0C, 0x5F, 0x1B, + 0xCE, 0x69, 0xBC, 0x72, 0x44, 0x87, 0x64, 0x1C, + 0x08, 0x05, 0x93, 0x69, 0x6D, 0x7F, 0x90, 0x0A, + 0x2C, 0xCB, 0x8A, 0xBB, 0x7F, 0xE3, 0xE0, 0x80, + 0x31, 0xD0, 0x0A, 0x3A, 0x95, 0xFF, 0xF7, 0xB4, + 0x36, 0x38, 0x93, 0xE0, 0x0C, 0x11, 0x37, 0x12, + 0x06, 0xF6, 0xAD, 0xE9, 0xB1, 0x7A, 0x00, 0xF5, + 0xD2, 0x32, 0x6B, 0xD0, 0x27, 0xA5, 0x1B, 0x3D, + 0xE8, 0xDB, 0xCC, 0xA9, 0x1F, 0x1F, 0xB1, 0x99, + 0x3D, 0x7C, 0xB7, 0xCA, 0xDA, 0x27, 0x2C, 0x64, + 0x1C, 0x49, 0xB6, 0x87, 0x44, 0x06, 0x94, 0x9D, + 0xBC, 0x6B, 0x20, 0xA2, 0x68, 0x15, 0x1F, 0xE2, + 0xF2, 0xAD, 0x6D, 0x23, 0x2E, 0x2B, 0x74, 0xE2, + 0x5D, 0xE4, 0xB0, 0xC7, 0x84, 0xCB, 0x64, 0xBF, + 0xE0, 0xA8, 0x18, 0x83, 0xB4, 0xC9, 0xD9, 0x73, + 0xA8, 0xE6, 0xA9, 0x36, 0xD5, 0x63, 0x1E, 0x2C, + 0x2A, 0x55, 0x09, 0x77, 0x5E, 0xB3, 0x4B, 0xEA, + 0xB5, 0xD0, 0x14, 0x5F, 0xEB, 0x50, 0x7B, 0xAA, + 0xEF, 0x94, 0xBA, 0x2B, 0xD7, 0x8A, 0x07, 0xF1, + 0xF9, 0x5E, 0x12, 0x12, 0x21, 0x52, 0xE5, 0x0A, + 0x3E, 0xC0, 0xBC, 0x5D, 0x4C, 0xE2, 0x12, 0x7C, + 0x39, 0xF9, 0x16, 0x9D, 0xBD, 0x96, 0x83, 0x3B, + 0x7F, 0x3D, 0x6A, 0xEC, 0xF1, 0x25, 0xD2, 0xB0, + 0xB0, 0xEB, 0x20, 0x06, 0x07, 0xD6, 0xD9, 0x4C, + 0x07, 0x9A, 0x82, 0xC1, 0xFC, 0xF7, 0x66, 0x15, + 0xBD, 0x62, 0x65, 0xD8, 0x6C, 0xF6, 0x33, 0x7B, + 0x5A, 0x28, 0xEC, 0x90, 0xA1, 0x26, 0x9F, 0xC3, + 0x28, 0x4A, 0x64, 0x50, 0x5F, 0xCA, 0xE2, 0x6D, + 0xB8, 0x0F, 0xE2, 0x94, 0xB5, 0x8E, 0x1F, 0x8A, + 0x8F, 0x6B, 0xA6, 0x86, 0x1F, 0xEE, 0xDC, 0x24, + 0xB4, 0xB8, 0x25, 0xEC, 0x28, 0x2D, 0xF9, 0xCB, + 0x7D, 0x38, 0xFF, 0xC7, 0x74, 0x2E, 0xD3, 0x10, + 0xEC, 0x03, 0x31, 0xEE, 0x83, 0xE7, 0xA4, 0xF7, + 0xBA, 0x28, 0x21, 0xE0, 0x7F, 0xB4, 0xB7, 0xE1, + 0x7A, 0xF9, 0x2B, 0xB0, 0x2C, 0x3B, 0x80, 0x5F, + 0xE0, 0x5D, 0xB2, 0x7E, 0x59, 0xFF, 0x59, 0x07, + 0x58, 0x42, 0x57, 0xEE, 0x44, 0xF1, 0xB1, 0xAD, + 0xBA, 0xDE, 0xCB, 0x1D, 0x8A, 0x36, 0x67, 0xE8, + 0x45, 0xFF, 0x07, 0x8D, 0xEE, 0xA4, 0x51, 0x9C, + 0x4C, 0x83, 0x5D, 0x2E, 0x2F, 0xE1, 0x5B, 0x75, + 0xE8, 0x29, 0xCD, 0x0B, 0x07, 0x62, 0xE0, 0xC3, + 0x0D, 0x1D, 0xEA, 0xCF, 0xF0, 0x8A, 0x65, 0x27, + 0x70, 0x42, 0x9F, 0x26, 0x00, 0x15, 0x70, 0xC5, + 0x4A, 0xF6, 0x25, 0xD0, 0x40, 0x72, 0xE9, 0xC1, + 0x73, 0xFD, 0x48, 0x94, 0xA3, 0x8D, 0x66, 0x63, + 0x96, 0x4F, 0xF7, 0xEE, 0xFB, 0x4C, 0xC7, 0xB8, + 0x6B, 0xE9, 0x90, 0xE1, 0x2A, 0x66, 0x80, 0x99, + 0x3B, 0xB0, 0x1A, 0x6C, 0xF9, 0x0E, 0x72, 0xDA, + 0x8E, 0x4F, 0x46, 0xC2, 0x6A, 0x4B, 0x7A, 0x16, + 0xE5, 0x26, 0x0B, 0x5C, 0xD4, 0x47, 0x34, 0xE5, + 0x37, 0xBE, 0x68, 0x6C, 0xDA, 0xD3, 0x9B, 0x6F, + 0xAE, 0x51, 0x9C, 0x99, 0x0A, 0x5B, 0xF8, 0x37, + 0xBC, 0xDE, 0xFC, 0x93, 0xC5, 0xE7, 0x0F, 0xEF, + 0x0B, 0xA6, 0x07, 0xC2, 0xA6, 0xE6, 0xDA, 0x2D, + 0x1B, 0x49, 0xC9, 0xDE, 0x6B, 0x27, 0xDC, 0x00, + 0xEF, 0x23, 0x87, 0x0E, 0xEB, 0xD1, 0x48, 0x7D, + 0xB4, 0xF2, 0x58, 0xC6, 0x3C, 0xE2, 0x89, 0xBA, + 0xB0, 0x05, 0xAC, 0x94, 0x41, 0x9A, 0xA8, 0xFF, + 0x3E, 0xBC, 0x3A, 0x52, 0x9C, 0xF9, 0x7F, 0x07, + 0x8B, 0xB0, 0x2C, 0x71, 0x83, 0x7B, 0xCF, 0x2E, + 0x7F, 0x7C, 0x96, 0x65, 0xD9, 0x08, 0x17, 0xEC, + 0xFA, 0xDE, 0x4E, 0x40, 0x12, 0x26, 0x70, 0x71, + 0x65, 0xA5, 0xDC, 0x98, 0x47, 0xA3, 0xFC, 0xE0, + 0x9A, 0x16, 0xED, 0x45, 0x56, 0x72, 0x50, 0x05, + 0x28, 0x2C, 0x99, 0xEC, 0x20, 0x2E, 0x40, 0xC0, + 0x26, 0x69, 0xCD, 0x49, 0x45, 0x17, 0xA4, 0xA3, + 0x42, 0x0D, 0x14, 0x65, 0x87, 0x33, 0x8C, 0x92, + 0xC5, 0xC4, 0x61, 0xFD, 0xE8, 0x68, 0x56, 0x20, + 0x57, 0xF5, 0x8E, 0x5F, 0xCF, 0x7E, 0x97, 0xF6, + 0x49, 0x97, 0x0A, 0xFE, 0xD3, 0x60, 0x1A, 0x5B, + 0x0C, 0x75, 0xDD, 0x8E, 0x31, 0x78, 0x29, 0xA6, + 0xB1, 0x4D, 0xAA, 0xDF, 0x8A, 0xD1, 0xE6, 0x91, + 0xE3, 0x32, 0x3F, 0xEC, 0x8A, 0x1F, 0x0E, 0x35, + 0x07, 0x6E, 0x4B, 0x83, 0x3B, 0xE5, 0x67, 0x34, + 0x1F, 0x0C, 0x81, 0xD8, 0xD5, 0x25, 0x68, 0xE5, + 0x28, 0x1B, 0x5C, 0x81, 0x3E, 0xE3, 0x5C, 0xB4, + 0xB6, 0xBD, 0x62, 0x6A, 0x70, 0x33, 0xC2, 0xC5, + 0x75, 0x27, 0xF4, 0x30, 0xE1, 0x1D, 0xC1, 0x4C, + 0xC5, 0x02, 0x12, 0x46, 0xAC, 0xEC, 0xF9, 0xE8, + 0xE7, 0x58, 0x24, 0x11, 0xB1, 0xF3, 0xB7, 0x8C, + 0x3C, 0xA4, 0x0A, 0x94, 0xA6, 0x7C, 0x68, 0x54, + 0x5B, 0xB9, 0x4D, 0x57, 0x9C, 0xE7, 0x28, 0x09, + 0x6B, 0x89, 0x26, 0x5D, 0xE7, 0x50, 0xA9, 0x95, + 0x90, 0x91, 0x8E, 0x00, 0x59, 0xF8, 0x3A, 0x70, + 0xAF, 0x48, 0x2E, 0xE8, 0xC4, 0x34, 0x8C, 0xF4, + 0x5F, 0x7F, 0xCB, 0x07, 0xAA, 0xF0, 0xD9, 0xFB, + 0x5C, 0x32, 0x90, 0x22, 0x1A, 0xD2, 0x1A, 0xCF, + 0x92, 0x06, 0x02, 0xCF, 0x10, 0x18, 0x7B, 0x93, + 0xCC, 0x07, 0x4A, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xD1, 0xDE, + 0x23, 0x16, 0x9F, 0x6E, 0xF4, 0x42, 0x21, 0x23, + 0xE1, 0x11, 0xAA, 0xC8, 0x7C, 0x60, 0x4A, 0x78, + 0x9D, 0x24, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, + 0x00, 0x04, 0x14, 0xD6, 0x4A, 0xBB, 0x75, 0xB1, + 0xF9, 0x9E, 0xD3, 0x58, 0x6D, 0xD1, 0x74, 0x9F, + 0x00, 0x8A, 0xF2, 0xC8, 0xAA, 0x52, 0x4D, 0x04, + 0x08, 0x77, 0x46, 0xE7, 0xBA, 0x25, 0x4B, 0xDA, + 0x41, 0x02, 0x02, 0x08, 0x00] +}; + +const WPA_EAP_CLIENT_LIST = [ + { + ssid: 'WPA-EAP-PEAP', + keyManagement: 'WPA-EAP', + eap: 'PEAP', + identity: EAP_USERNAME, + password: EAP_PASSWORD, + serverCertificate: CLIENT_PKCS12_CERT.nickname, + phase2: 'MSCHAPV2' + } +]; + +/** + * Convert the given MozWifiNetwork object array to testAssociate chain. + * + * @param aNetworks + * An array of MozWifiNetwork which we want to convert. + * + * @return A promise chain which "then"s testAssociate accordingly. + */ +function convertToTestAssociateChain(aNetworks) { + let chain = Promise.resolve(); + + aNetworks.forEach(function (aNetwork) { + network = new window.MozWifiNetwork(aNetwork); + chain = chain.then(() => gTestSuite.testAssociate(network)); + }); + + return chain; +} + +gTestSuite.doTestWithCertificate( + new Blob([new Uint8Array(CLIENT_PKCS12_CERT.content)]), + CLIENT_PKCS12_CERT.password, + CLIENT_PKCS12_CERT.nickname, + CLIENT_PKCS12_CERT.usage, + function() { + return gTestSuite.ensureWifiEnabled(true) + // Load required server files. + .then(() => gTestSuite.writeFile(SERVER_EAP_USER_CONF.path, SERVER_EAP_USER_CONF.content)) + .then(() => gTestSuite.writeFile(CA_CERT.path, CA_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_CERT.path, SERVER_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_KEY.path, SERVER_KEY.content)) + // Start AP. + .then(() => gTestSuite.startHostapds(WPA_EAP_AP_LIST)) + // Scan test. + .then(() => gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, WPA_EAP_AP_LIST)) + // Associate test. + .then(() => convertToTestAssociateChain(WPA_EAP_CLIENT_LIST)) + // Tear down. + .then(gTestSuite.killAllHostapd) +}); diff --git a/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TLS.js b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TLS.js new file mode 100644 index 0000000000..35b942f8e2 --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TLS.js @@ -0,0 +1,622 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +const SCAN_RETRY_CNT = 5; + +const EAP_USERNAME = 'username'; +const EAP_PASSWORD = 'password'; + +const SERVER_EAP_USER_CONF = { + path: HOSTAPD_CONFIG_PATH + 'hostapd.eap_user', + content: '* PEAP,TTLS,TLS\n' + + '"' + EAP_USERNAME + '" MSCHAPV2,TTLS-MSCHAPV2 "' + EAP_PASSWORD + '" [2]\n' +}; +const CA_CERT = { + path: HOSTAPD_CONFIG_PATH + 'ca.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIIDsTCCApmgAwIBAgIJAKxTf+8X8qngMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\n' + + 'BAYTAlRXMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTER\n' + + 'MA8GA1UEAwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdt\n' + + 'YWlsLmNvbTAgFw0xNDEyMjQxMTI4NTBaGA8yMjg4MTAwNzExMjg1MFowbjELMAkG\n' + + 'A1UEBhMCVFcxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCGNodWNrbGVl\n' + + 'MREwDwYDVQQDDAhjaHVja2xlZTEkMCIGCSqGSIb3DQEJARYVY2h1Y2tsaTA3MDZA\n' + + 'Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo3c2yFxY\n' + + 'o6gGg0I83jy00ME+MAfzCd+4ShL45ZLqysQP93jRBfPzU9ZuZ29ysVwgWIdqkZao\n' + + 'XTuV/NAW2GMGd8W1jQJ3J81fjb9wvhlny3rrACwvUn1N1S1BnM+BAAiDLGxEmvAQ\n' + + 'onp2aaa6HsHsYS8ONX+d2Qh4LEA4vupeSGAqJychCZv/l+aq/ErFZhFYB3CPUQEt\n' + + 'cClO24ucsIYP95lA0zhscnmAj06qplFD4Bv6IVrdDqujy1zNwCQwsJq/8OQdaTN/\n' + + 'h3y9pWvNKMBMM2niOUAjtuNpqsSK/lTS1WAT3PdtVECX9fYBi0Bg+HM92xs/6gt6\n' + + 'kh9jPV8keXHvSwIDAQABo1AwTjAdBgNVHQ4EFgQU7hBqhuG04xeCzrQ3ngx18ZJ3\n' + + 'lUswHwYDVR0jBBgwFoAU7hBqhuG04xeCzrQ3ngx18ZJ3lUswDAYDVR0TBAUwAwEB\n' + + '/zANBgkqhkiG9w0BAQsFAAOCAQEAFYX2iy680GAnBTttk0gyX6gk+8pYr3D22k/G\n' + + '6rvcjefzS7ELQPRKr6mfmwXq3mMf/4jiS2zI5zmXsestPYzHYxf2viQ6t7vr9XiJ\n' + + '3WfFjNw4ERlRisAvg0aqqTNNQq5v2VME4sdFZagy217f73C7azwCHl0bqOLH05rl\n' + + '8RubOxiHEj7ZybJqnRciK/bht4D+rZkwf4bBBmoloqH7xT0+rFQclpYXDGGjNUQB\n' + + 'LcHLF10xcr7g3ZVVu82fe6+d85gIGOIMR9+TKhdw6gO3CNcnDAj6gxksghgtcxmh\n' + + 'OzOggCn7nlIwImtsg2sZkpWB4lEi9hdv4lkNuyFjOL3bnuc+NA==\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_CERT = { + path: HOSTAPD_CONFIG_PATH + 'server.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIID1DCCArygAwIBAgIBADANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJUVzET\n' + + 'MBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIY2h1Y2tsZWUxETAPBgNVBAMM\n' + + 'CGNodWNrbGVlMSQwIgYJKoZIhvcNAQkBFhVjaHVja2xpMDcwNkBnbWFpbC5jb20w\n' + + 'IBcNMTQxMjI0MTEyOTQ5WhgPMjI4ODEwMDcxMTI5NDlaMG4xCzAJBgNVBAYTAlRX\n' + + 'MRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTERMA8GA1UE\n' + + 'AwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdtYWlsLmNv\n' + + 'bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdhQmKilTJbWZRxTiSV\n' + + 'rqIU+LYW1RKghx5o+0JpNRJVLuz5kBMaNskbbfUSNuHbEq0QA9BDKAZWIc4LSotk\n' + + 'lCo8TbcO9CJvJPQGGjGdHcohWX5vy6BE/OVE46CUteMFyZF6F8R2fNUww08iR/u1\n' + + 'YZebL5pWO1j43sPpAzEy6Tij2ACPt6EZcFaZG3SF2mVJWkCQnBqrojP65WUvZQqp\n' + + 'seUhW2YAS8Nu0Yrohgxz6VYk+cNDuDZVGs6qWRStZzJfYrfc76DtkHof5B14M+xp\n' + + 'XJaBLxN+whvnYkDTfinaCxnW1O7eXUltr87fLc5zmeBkgwaiaQuIdcfZm7vDUiz8\n' + + 'vnUCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH\n' + + 'ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFKK4f9/YavTHOfEiAB83Deac\n' + + '6gT5MB8GA1UdIwQYMBaAFO4QaobhtOMXgs60N54MdfGSd5VLMA0GCSqGSIb3DQEB\n' + + 'CwUAA4IBAQBWnO9o9KSJIqjoz5Nwll63ULOdcvgGdOeJIw1fcKQ817Rsp+TVcjcH\n' + + 'IrIADsT/QZGXRO/l6p1750e2iFtJEo1hsRaxtA1wWn2I9HO3+av2spQhr3jpYGPf\n' + + 'zpsMTp4RNYV7Q8+q1kZIz9PY4V1T0p6lveK8+fUj2hSLnxSj0QiGSJJtnEC3w4Rv\n' + + 'C9T6oUwIeToULmi+8FXQFdEqwKRU98DPq3eLzN28ZxUgoPE1C8+42D2UW8uyp/Gm\n' + + 'tGOa/k7nzkCdVqZI7lX7f0AjEvQgjtAMQ/k7Mhxx7TzW2HO+1YPMoKji6Z4WkNwt\n' + + 'JEj9ZUBSNt8B26UksJMBDkcvSegF3a7o\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_KEY = { + path: HOSTAPD_CONFIG_PATH + 'server.key', + content: '-----BEGIN RSA PRIVATE KEY-----\n' + + 'MIIEpAIBAAKCAQEAx2FCYqKVMltZlHFOJJWuohT4thbVEqCHHmj7Qmk1ElUu7PmQ\n' + + 'Exo2yRtt9RI24dsSrRAD0EMoBlYhzgtKi2SUKjxNtw70Im8k9AYaMZ0dyiFZfm/L\n' + + 'oET85UTjoJS14wXJkXoXxHZ81TDDTyJH+7Vhl5svmlY7WPjew+kDMTLpOKPYAI+3\n' + + 'oRlwVpkbdIXaZUlaQJCcGquiM/rlZS9lCqmx5SFbZgBLw27RiuiGDHPpViT5w0O4\n' + + 'NlUazqpZFK1nMl9it9zvoO2Qeh/kHXgz7GlcloEvE37CG+diQNN+KdoLGdbU7t5d\n' + + 'SW2vzt8tznOZ4GSDBqJpC4h1x9mbu8NSLPy+dQIDAQABAoIBAASG4Mr8hgaurEoC\n' + + 'iJOsElr7vunjetMBcg/uskW/vcS8ymP3Bp5oafYG+WgnEbfvEW18f5mq7K24JuxW\n' + + 'tUqU7ghHdjxByqk9fMlNmiqmNpbwSufkAeuRpWxPNBvhRH/zEbCL5R5A0nTEtqqF\n' + + 'TL0aUSzwCRSoAJD0lZo9ICVt0n3GsDyM9rqQg/uZmh1qsRdwPsRuYORND9g48rKq\n' + + '6WN9leskSxhhsYE2D9ocOFd9bNt8Zxejh9ppVSnG/KsIdt18iBzcabatgAQ046fb\n' + + 'Z3vprcZJLg93Sg2gSuVqlSTs3M2W8VQnm22/EBMb1y0M48MSRCgnbPLG/CcCLLfF\n' + + 'LwxCOgECgYEA/eYt67xyJ6JeAdxdwOZuT1WWGbFpLiG9+2OgiHumyRQ5969XMTWo\n' + + 'fIhMKchDdjoy9RR236\/\/EFCs7UEyB7+a7ODRzNiK2zCD8Smjp+21fUPSthEeQesk\n' + + 'eiMYICIu5Ay35x9sxIX+XOUVvRhPOGcD29GVeRnKh1inTHOz2dje8LkCgYEAyQeY\n' + + 'STi9jjCEcHkM1E/UeDiLfHHepLXi8wS41JNRHl5Jacp7XB5djAjKu/jf367/VpFy\n' + + 'GDDMetE7n8eWkrnAvovxOwZ000YDMtL1sUYSjL+XtBS5s6VY1p4qaSAY9nUUGrJh\n' + + 'JvtvsuI7SKTtL+60vjBOH7zDnvOdBgAp0utLhZ0CgYEAuLzzqrPKB8afShFSchn4\n' + + 'J2dpuLYahsNsXW7HDqeR2nsKFosRETAusLXnXPtnAq4kB6jlOarwFqnsuRCX24Vx\n' + + 'r2uBm9/vYL7zMdUPTA+s30ErHuhjsKjsOKYyVqcooSwT32pBFNk+E89nutfmRG7I\n' + + 'IvhjHuNCNqqtx/Xj5d1jkZkCgYBQicppC2Jl5OoqZVTOem0U/RJk+PnJ41TZJ7sk\n' + + '7yBAmmWvDH\/\/l+rCf4M5a6vFYcbKV9rt9h711X2dtciNX/3oWQh8LUoAmrwNUJc+\n' + + 'PmSQHvIYI3WCk2vUD+nN1B4sHxu+1lg11eYaNKiroeeknG2tBI1ICcgVlmQCU25u\n' + + 'IfZPwQKBgQCdO6QHhPLtcHUDNFA6FQ1jKL1iEd7G0JLVRz4Xkpkn1Vrr5MD6JFDa\n' + + '5ccabADyl0lpFqDIVJQIzLku2hOD2i9aBNCY0pL391HeOS7CkZX+TdOY1tquoBq5\n' + + 'MnmixZjDCVd2VcrVyTA6ntOBoharKFW0rH1PqU+qu7dZF7CBPbAdEw==\n' + + '-----END RSA PRIVATE KEY-----\n' +}; + +const WPA_EAP_AP_LIST = [ + { + ssid: 'WPA-EAP-TLS', + ieee8021x: 1, + eapol_version: 1, + eap_server: 1, + eapol_key_index_workaround: 0, + eap_user_file: SERVER_EAP_USER_CONF.path, + ca_cert: CA_CERT.path, + server_cert: SERVER_CERT.path, + private_key: SERVER_KEY.path, + wpa: 2, + wpa_key_mgmt: 'WPA-EAP' + } +]; + +const CLIENT_PKCS12_CERT = { + nickname: 'client', + password: 'password', + usage: ['UserCert', 'ServerCert'], + content: [0x30, 0x82, 0x0E, 0x01, 0x02, 0x01, 0x03, 0x30, + 0x82, 0x0D, 0xC7, 0x06, 0x09, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, + 0x0D, 0xB8, 0x04, 0x82, 0x0D, 0xB4, 0x30, 0x82, + 0x0D, 0xB0, 0x30, 0x82, 0x08, 0x67, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, + 0x06, 0xA0, 0x82, 0x08, 0x58, 0x30, 0x82, 0x08, + 0x54, 0x02, 0x01, 0x00, 0x30, 0x82, 0x08, 0x4D, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x01, 0x30, 0x1C, 0x06, 0x0A, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, + 0x06, 0x30, 0x0E, 0x04, 0x08, 0x67, 0x7A, 0xF3, + 0x61, 0xBE, 0xE0, 0x51, 0xC1, 0x02, 0x02, 0x08, + 0x00, 0x80, 0x82, 0x08, 0x20, 0xFC, 0x6A, 0x79, + 0xA1, 0x6C, 0xAF, 0xBE, 0xEE, 0x62, 0x45, 0x33, + 0xB8, 0x48, 0xE1, 0x68, 0xA1, 0x15, 0x11, 0x4B, + 0x95, 0xCB, 0x77, 0xC0, 0x5D, 0xA2, 0xCB, 0xDB, + 0xD1, 0x83, 0x74, 0x60, 0xD7, 0xEC, 0x42, 0xA6, + 0x3A, 0x23, 0xF7, 0x85, 0xEB, 0xC1, 0xFE, 0x6A, + 0x57, 0x8E, 0xC1, 0x44, 0xF3, 0x1F, 0xFE, 0xB8, + 0x2D, 0x8C, 0x4D, 0xC9, 0x5B, 0xAE, 0x21, 0x2E, + 0x4C, 0x1A, 0xEB, 0x84, 0x09, 0xF3, 0x40, 0x92, + 0x39, 0x7F, 0x56, 0x02, 0x46, 0x61, 0x16, 0xDE, + 0x5C, 0x48, 0xB6, 0x0C, 0x1D, 0xD3, 0x5F, 0x10, + 0x9A, 0x39, 0xB8, 0x66, 0x31, 0xFC, 0x39, 0x71, + 0x87, 0x23, 0x46, 0x9D, 0xE8, 0x3C, 0x2B, 0xA1, + 0x39, 0x8A, 0xD3, 0xFF, 0xD9, 0x43, 0xB6, 0x61, + 0xC6, 0x67, 0x70, 0x40, 0xBD, 0xFE, 0xD3, 0xC1, + 0x68, 0xF5, 0xF7, 0xC8, 0x89, 0xD8, 0x17, 0xC5, + 0xE8, 0x3D, 0x29, 0xD5, 0x91, 0xDF, 0x1F, 0x56, + 0x74, 0x5A, 0xC4, 0xA8, 0x14, 0xBA, 0xD4, 0xFA, + 0x13, 0x49, 0x2A, 0x9F, 0x63, 0xF1, 0xB2, 0x45, + 0xF1, 0xF0, 0x2A, 0xDD, 0x75, 0x66, 0x8A, 0xF7, + 0xAB, 0x73, 0x86, 0x26, 0x9D, 0x1F, 0x07, 0xAD, + 0xD3, 0xFE, 0xE0, 0xA3, 0xED, 0xA0, 0x96, 0x3E, + 0x1E, 0x89, 0x86, 0x02, 0x4C, 0x28, 0xFD, 0x57, + 0xA1, 0x67, 0x55, 0xF0, 0x82, 0x3B, 0x7F, 0xCC, + 0x2A, 0x32, 0x01, 0x93, 0x1D, 0x8B, 0x66, 0x8A, + 0x20, 0x52, 0x84, 0xDD, 0x2C, 0xFD, 0xEE, 0x72, + 0xF3, 0x8C, 0x58, 0xB9, 0x99, 0xE5, 0xC1, 0x22, + 0x63, 0x59, 0x00, 0xE2, 0x76, 0xC5, 0x3A, 0x17, + 0x7F, 0x93, 0xE9, 0x67, 0x61, 0xAA, 0x10, 0xC3, + 0xD9, 0xC8, 0x24, 0x46, 0x5B, 0xBE, 0x8C, 0x1F, + 0x2D, 0x66, 0x48, 0xD2, 0x02, 0x11, 0xFB, 0x74, + 0x14, 0x76, 0x76, 0x5A, 0x98, 0x54, 0x35, 0xA7, + 0x85, 0x66, 0x20, 0x26, 0x8B, 0x13, 0x6F, 0x68, + 0xE3, 0xC9, 0x58, 0x7D, 0x1C, 0x3E, 0x01, 0x8D, + 0xF8, 0xD6, 0x7F, 0xCF, 0xA2, 0x07, 0xB7, 0x95, + 0xFD, 0xF0, 0x02, 0x34, 0x32, 0x30, 0xE8, 0xD4, + 0x57, 0x5E, 0x53, 0xFB, 0x54, 0xE2, 0x03, 0x32, + 0xCC, 0x52, 0x2E, 0xD2, 0x35, 0xD9, 0x58, 0x85, + 0x2D, 0xEC, 0x2D, 0x71, 0xD1, 0x8A, 0x29, 0xD0, + 0xB0, 0x24, 0xBD, 0x24, 0xDC, 0x1A, 0x28, 0x3F, + 0xA0, 0x12, 0x81, 0x15, 0x24, 0xC9, 0xB5, 0x4A, + 0x23, 0xB6, 0xA3, 0x45, 0x50, 0x2D, 0x73, 0x99, + 0x6B, 0x1C, 0xFB, 0xA4, 0x53, 0xD7, 0x5C, 0xF4, + 0x6C, 0xB0, 0xE5, 0x74, 0xB3, 0x76, 0xF8, 0xB1, + 0x0D, 0x59, 0x70, 0x9F, 0xCA, 0xDE, 0xF2, 0xAA, + 0x4C, 0x7D, 0x11, 0x54, 0xC4, 0x19, 0x0F, 0x36, + 0x4A, 0x62, 0xFF, 0x8B, 0x10, 0xCB, 0x93, 0x50, + 0xDA, 0x79, 0x5E, 0x4E, 0x09, 0x1F, 0x22, 0xC8, + 0x19, 0x85, 0xE9, 0xEE, 0xB7, 0x71, 0x65, 0xB9, + 0x10, 0xD2, 0x0A, 0x73, 0x5B, 0xA6, 0xDA, 0x37, + 0x46, 0x02, 0x00, 0x98, 0x9E, 0x20, 0x6C, 0x7D, + 0xC7, 0x69, 0xBB, 0xC2, 0x00, 0x40, 0x9C, 0x57, + 0x00, 0xC2, 0x36, 0x76, 0xE8, 0x2A, 0x8D, 0xAD, + 0x62, 0x57, 0xC8, 0xD0, 0x9D, 0x66, 0x27, 0x5A, + 0xD8, 0x0D, 0x35, 0x60, 0x28, 0x38, 0x62, 0x94, + 0x78, 0x36, 0x25, 0x58, 0xFD, 0xF8, 0x66, 0x1F, + 0x68, 0x04, 0x0F, 0xD8, 0x00, 0xDF, 0xA0, 0x6C, + 0x25, 0x42, 0x9A, 0x4C, 0xEB, 0x80, 0x13, 0x51, + 0x7D, 0x2D, 0xA8, 0x89, 0xD6, 0x1B, 0x67, 0x72, + 0x01, 0xF3, 0x2D, 0x16, 0x77, 0xFE, 0x22, 0xBC, + 0x8A, 0x45, 0x09, 0x1F, 0x9C, 0x2F, 0x2A, 0xA9, + 0x61, 0x5B, 0x4A, 0xE6, 0x64, 0x2C, 0x62, 0x1A, + 0x3A, 0x96, 0xE6, 0x0A, 0xAE, 0x05, 0x1A, 0xC8, + 0xCB, 0xD6, 0x8F, 0x3A, 0x4B, 0xE0, 0x7F, 0x82, + 0xB4, 0x98, 0xF1, 0x9D, 0xD7, 0x14, 0x76, 0x5E, + 0x77, 0x85, 0x87, 0xEC, 0x13, 0xDA, 0xFD, 0xAF, + 0xCB, 0xA3, 0x1C, 0x99, 0xC1, 0xFE, 0x17, 0x0C, + 0x40, 0x4D, 0x3C, 0x8F, 0x70, 0x86, 0x63, 0x64, + 0xB7, 0x75, 0xA8, 0x71, 0x36, 0xDC, 0x54, 0x10, + 0x57, 0x0C, 0xA8, 0xF2, 0xA1, 0xBB, 0xED, 0x03, + 0x41, 0x57, 0x34, 0x2C, 0x8F, 0x7C, 0xA0, 0x09, + 0xF3, 0x9E, 0x41, 0xB7, 0xA8, 0xD4, 0x66, 0x0D, + 0x0D, 0xC0, 0x6A, 0xFC, 0x6A, 0xA2, 0xAC, 0xE2, + 0x60, 0x00, 0xE3, 0xF7, 0x75, 0x43, 0x23, 0xEB, + 0xC8, 0x61, 0xFA, 0xB3, 0xB8, 0x28, 0xCE, 0xCA, + 0xF4, 0x47, 0x7F, 0x30, 0x6D, 0x61, 0x89, 0x47, + 0xA1, 0x4A, 0xFE, 0xD1, 0x21, 0x0B, 0x6D, 0xF4, + 0x3F, 0x00, 0x86, 0x30, 0x8E, 0x33, 0x21, 0x6F, + 0xDA, 0x15, 0xFD, 0x5F, 0xEC, 0x8E, 0xF1, 0x12, + 0x3F, 0xC9, 0x83, 0x0C, 0xCA, 0x22, 0x01, 0xF1, + 0x70, 0x5F, 0x1F, 0x66, 0xB5, 0xF8, 0x3E, 0x7A, + 0x6F, 0xDE, 0xDB, 0xA7, 0x8D, 0x18, 0x9E, 0xBE, + 0xDB, 0xAD, 0x3D, 0x66, 0x30, 0xC1, 0x6C, 0x0C, + 0x87, 0xB4, 0x65, 0x75, 0xE0, 0x9D, 0xEA, 0x16, + 0x0D, 0x07, 0x37, 0x33, 0xC5, 0xEC, 0x97, 0x93, + 0x37, 0xEB, 0x8E, 0x65, 0x9C, 0x40, 0x63, 0x6C, + 0x43, 0x60, 0xB0, 0x40, 0x4D, 0x85, 0xEF, 0xC2, + 0x47, 0x5F, 0xE7, 0x6B, 0xCB, 0x40, 0xE8, 0xEA, + 0xD8, 0xAB, 0xB1, 0x9A, 0x72, 0xDC, 0x4C, 0x14, + 0xFA, 0x43, 0x61, 0x5F, 0xA6, 0x5C, 0x3A, 0x05, + 0x17, 0x2E, 0x74, 0xF3, 0x5E, 0x45, 0xD9, 0x47, + 0xAA, 0x59, 0xB6, 0x8F, 0x42, 0x66, 0x42, 0x29, + 0x90, 0x95, 0x48, 0x46, 0x91, 0x88, 0x3C, 0x8C, + 0xDE, 0xCC, 0xED, 0xB3, 0xAA, 0x62, 0xEA, 0xBC, + 0xB4, 0x0C, 0x48, 0x4C, 0x53, 0x23, 0x5E, 0x24, + 0x85, 0xBF, 0x92, 0xDA, 0x14, 0xDB, 0x1A, 0x3D, + 0xEF, 0x30, 0xD9, 0x49, 0x64, 0x4D, 0xE5, 0x01, + 0xFC, 0xA4, 0x4B, 0xD1, 0x9F, 0xDE, 0x96, 0x7F, + 0x50, 0xBC, 0x4D, 0x38, 0x44, 0xE9, 0x23, 0x5F, + 0x37, 0x57, 0x1A, 0xA6, 0x52, 0x5A, 0x0F, 0x4F, + 0x87, 0x33, 0x4A, 0x7B, 0x66, 0xEE, 0x3D, 0x66, + 0x0A, 0x63, 0x39, 0x1F, 0x23, 0x38, 0x35, 0x73, + 0x60, 0x5E, 0x47, 0x20, 0x4F, 0xC0, 0xC8, 0x3C, + 0x09, 0xF9, 0x29, 0x4F, 0x5E, 0x55, 0x69, 0xC4, + 0x6B, 0xE8, 0xF8, 0x91, 0xC0, 0x22, 0x65, 0x15, + 0x1E, 0xFB, 0xB9, 0x61, 0xCE, 0x45, 0xBE, 0x2B, + 0xEE, 0xB9, 0x04, 0x2B, 0xFD, 0xAE, 0x61, 0x1C, + 0x3D, 0x3D, 0x7C, 0xBF, 0xC1, 0xF7, 0x3C, 0x4E, + 0x9E, 0x0E, 0x54, 0xC8, 0xAD, 0xA9, 0xDF, 0x43, + 0x49, 0xB9, 0x41, 0x05, 0xE5, 0xF1, 0x49, 0xAA, + 0x77, 0x6C, 0x34, 0x5B, 0x93, 0x24, 0x24, 0x23, + 0x74, 0x68, 0x11, 0xCE, 0x15, 0x80, 0xA1, 0xA4, + 0x1F, 0x8D, 0x81, 0xCD, 0xB2, 0x98, 0xCA, 0x14, + 0x0B, 0x0C, 0x61, 0x50, 0x69, 0x72, 0xAE, 0xFA, + 0x8B, 0xC0, 0x3F, 0x0D, 0xE7, 0xF2, 0x0F, 0xEB, + 0xC1, 0x11, 0xB9, 0x10, 0x03, 0x6A, 0xF5, 0x97, + 0x3C, 0x53, 0x2F, 0x67, 0x86, 0x09, 0x6A, 0xE3, + 0x28, 0xC0, 0x78, 0xC8, 0xB4, 0x39, 0x8E, 0xD1, + 0xCE, 0x25, 0xE8, 0x66, 0xF7, 0x09, 0x40, 0x7D, + 0x81, 0xFB, 0xAF, 0xFA, 0x59, 0xC4, 0x9B, 0x2B, + 0x83, 0x45, 0x5B, 0xA8, 0x66, 0x9E, 0x38, 0xC8, + 0xFD, 0xAC, 0xF2, 0x2D, 0x21, 0xDE, 0x50, 0x4C, + 0x03, 0xCB, 0x88, 0x42, 0xDD, 0x84, 0x09, 0x99, + 0x8E, 0x8B, 0x40, 0x97, 0x1B, 0x14, 0x85, 0x37, + 0x11, 0x01, 0xE0, 0x74, 0x6B, 0x33, 0x52, 0x8C, + 0x68, 0x3A, 0x89, 0xB2, 0xAF, 0x35, 0xE6, 0x65, + 0xC3, 0x58, 0x70, 0xD2, 0xE7, 0x1F, 0x1F, 0xF6, + 0xE5, 0x0A, 0xB1, 0xFE, 0xD0, 0xC9, 0x51, 0x50, + 0xE7, 0xFD, 0x58, 0xF5, 0xC4, 0x58, 0x65, 0x94, + 0xD1, 0x57, 0x55, 0x5E, 0xD2, 0x27, 0x98, 0xAF, + 0xE7, 0x55, 0x0B, 0x87, 0x50, 0x9B, 0xEF, 0xE8, + 0x2B, 0xFC, 0xE7, 0x3B, 0x4E, 0xD7, 0xB7, 0x4D, + 0xF4, 0xBC, 0xF4, 0x88, 0x63, 0xE4, 0x8A, 0x20, + 0x4B, 0x22, 0xB0, 0xA0, 0x53, 0x7F, 0xA8, 0xC9, + 0x0C, 0xF8, 0xD7, 0xBD, 0x46, 0x39, 0xA7, 0x7D, + 0xDD, 0x10, 0x91, 0x50, 0x54, 0x06, 0x47, 0xF0, + 0x3C, 0xAA, 0x43, 0x40, 0xF8, 0x54, 0xDD, 0x8A, + 0xEA, 0x8A, 0x0B, 0xA5, 0x7F, 0xCD, 0x5E, 0xAA, + 0x02, 0x2E, 0x1F, 0xC6, 0x50, 0x15, 0xF8, 0x0A, + 0x0C, 0x1B, 0x3C, 0x55, 0x3A, 0xC3, 0x6F, 0x88, + 0xD7, 0xBF, 0xB1, 0x02, 0xCC, 0xE0, 0x08, 0x29, + 0x97, 0xD2, 0xAA, 0x23, 0xC4, 0x6D, 0xE3, 0xE3, + 0x76, 0x39, 0x92, 0xC3, 0x2E, 0x7A, 0xE2, 0x98, + 0xD1, 0xFC, 0xAE, 0xCC, 0x95, 0xD8, 0xB4, 0xDC, + 0x92, 0xEA, 0x6A, 0x5F, 0xF2, 0x92, 0x17, 0x0B, + 0x8D, 0xC3, 0xFA, 0x9C, 0x62, 0xCE, 0x44, 0x8D, + 0xC3, 0x1E, 0xC3, 0xB2, 0xD5, 0x00, 0xCD, 0xB4, + 0x9E, 0x2D, 0x7B, 0xF2, 0x98, 0xA3, 0x00, 0x8B, + 0x81, 0x30, 0x77, 0x5B, 0x02, 0x99, 0xB1, 0xCD, + 0xC3, 0x1D, 0x74, 0x74, 0xEF, 0x41, 0xCB, 0x69, + 0x63, 0x8E, 0xA6, 0xD3, 0x2D, 0x3E, 0x1F, 0x1D, + 0x12, 0x9E, 0xD9, 0x18, 0x67, 0x06, 0xAF, 0x37, + 0x29, 0xAD, 0x65, 0xD8, 0xEB, 0x71, 0xC4, 0x7D, + 0x94, 0x3D, 0xEA, 0xCC, 0xDF, 0x72, 0x41, 0x51, + 0x3C, 0xA1, 0x66, 0x98, 0x32, 0x32, 0x40, 0x54, + 0xB0, 0x2F, 0xEB, 0xCE, 0xDF, 0x4A, 0x64, 0xFB, + 0x9A, 0x90, 0xDC, 0xF6, 0x6F, 0xA9, 0xD4, 0xCA, + 0xCB, 0x91, 0xC4, 0xFE, 0xEE, 0x9C, 0x01, 0x50, + 0x2E, 0xAC, 0xCC, 0x5F, 0x89, 0xD0, 0x91, 0xA3, + 0xD9, 0xF9, 0x4B, 0x8D, 0xDE, 0x6C, 0x60, 0x21, + 0x19, 0xB1, 0xD3, 0x4D, 0x75, 0x56, 0x6F, 0xB8, + 0x25, 0xA4, 0x92, 0x4F, 0x12, 0xF5, 0x8F, 0xC1, + 0x17, 0x4B, 0xB3, 0x34, 0x21, 0x22, 0xAC, 0x52, + 0xD2, 0x64, 0xC9, 0x9A, 0x7D, 0xFC, 0xC0, 0x0A, + 0x89, 0x34, 0xFF, 0x08, 0xD3, 0x04, 0xDC, 0xFE, + 0x7C, 0xB3, 0xB8, 0xFD, 0x85, 0xDD, 0x79, 0x51, + 0xA7, 0x89, 0xE8, 0xF1, 0x23, 0xB1, 0xDF, 0xD7, + 0x1F, 0x7B, 0xB1, 0x5D, 0x42, 0xF9, 0x61, 0xF8, + 0xDC, 0x81, 0x04, 0xF1, 0xCC, 0xFA, 0xD7, 0xED, + 0xBF, 0x47, 0xAC, 0xBD, 0xE5, 0xFA, 0xAC, 0xB3, + 0x1C, 0xD9, 0xA1, 0xB3, 0x60, 0xEE, 0x9C, 0x8A, + 0x36, 0x57, 0xB4, 0x2F, 0xA1, 0xA2, 0xF3, 0xE2, + 0x09, 0x9A, 0x6E, 0x43, 0x9B, 0xE5, 0x93, 0xB8, + 0x3D, 0x9E, 0x9F, 0xC1, 0xC6, 0x0D, 0x02, 0xEB, + 0x4D, 0x38, 0xE9, 0xB4, 0x9F, 0xEA, 0x33, 0x8C, + 0x07, 0xD8, 0xB4, 0x71, 0xAD, 0xE5, 0x43, 0xB2, + 0xCC, 0x55, 0x93, 0x6A, 0xDB, 0x1E, 0x80, 0xDB, + 0xC2, 0xEA, 0x42, 0x8E, 0xFC, 0x86, 0x44, 0xC9, + 0x8A, 0xC4, 0xF2, 0x46, 0xA7, 0x39, 0x50, 0x0D, + 0x1A, 0xAA, 0x07, 0x04, 0xBE, 0xD4, 0xCE, 0x62, + 0x4D, 0x0F, 0x91, 0x7D, 0x29, 0x88, 0x9C, 0x4C, + 0xAF, 0xF7, 0xD8, 0x40, 0x93, 0x88, 0xC7, 0x20, + 0xD2, 0x17, 0x2A, 0xC4, 0x92, 0x72, 0xD0, 0xC0, + 0x4E, 0x56, 0x47, 0xB1, 0x27, 0x02, 0xE6, 0x61, + 0x82, 0x5E, 0xC8, 0x2E, 0x90, 0xD2, 0x31, 0x22, + 0xE2, 0xA9, 0x4A, 0x91, 0x45, 0x69, 0xB1, 0xA5, + 0x0F, 0x66, 0x2C, 0x30, 0xAD, 0x7F, 0x1B, 0x0E, + 0x22, 0x17, 0x60, 0x2E, 0x3D, 0x7F, 0x7F, 0x8C, + 0x33, 0x51, 0xA0, 0x25, 0xDE, 0xFD, 0x75, 0xBC, + 0xEF, 0xE6, 0xE7, 0x20, 0x04, 0x5A, 0xEC, 0x50, + 0x21, 0x48, 0x56, 0x98, 0xE2, 0x33, 0x6D, 0x22, + 0x5C, 0xC3, 0xFB, 0xFC, 0x6F, 0xB3, 0xA7, 0x8E, + 0x6F, 0x67, 0x70, 0x9D, 0xDA, 0x02, 0x01, 0x59, + 0x7B, 0x3D, 0x2B, 0x38, 0xCC, 0x0F, 0x44, 0x3D, + 0xFB, 0x9A, 0xB3, 0x23, 0x15, 0x50, 0x6E, 0xBF, + 0x8B, 0xA1, 0x94, 0x33, 0xE5, 0x7B, 0x88, 0x4E, + 0xCB, 0x6D, 0x9F, 0xBF, 0xBC, 0x7A, 0xA8, 0x1E, + 0x68, 0x25, 0xED, 0x8E, 0x53, 0x21, 0x72, 0xC5, + 0x70, 0xB3, 0xE4, 0xA6, 0xA1, 0x5A, 0x2D, 0xC8, + 0x43, 0x9D, 0x60, 0x77, 0x78, 0xE0, 0xC4, 0xAF, + 0xC8, 0x29, 0xBA, 0xD0, 0x4D, 0x39, 0x83, 0x51, + 0xA7, 0x10, 0x7F, 0x0C, 0x34, 0x0E, 0x6C, 0x75, + 0x26, 0xD7, 0xD6, 0xC7, 0x32, 0x53, 0xAF, 0x4E, + 0xBE, 0xF2, 0xC2, 0x0F, 0x99, 0x23, 0xB9, 0xE1, + 0xC8, 0xB4, 0xBC, 0x5A, 0xC6, 0xCB, 0xEB, 0x4D, + 0x28, 0x56, 0x72, 0xFE, 0x1B, 0x2C, 0x5D, 0xE3, + 0xBC, 0xC7, 0xA3, 0xC0, 0x7D, 0x27, 0xF0, 0xD0, + 0x4F, 0x3F, 0x1F, 0xF7, 0x87, 0x15, 0xF2, 0xEA, + 0xD4, 0x03, 0x6D, 0x2F, 0xD4, 0x8E, 0x50, 0x4B, + 0x05, 0xBF, 0xF7, 0x8C, 0x67, 0x5A, 0xDC, 0x4D, + 0xCD, 0xCF, 0x9D, 0x02, 0xB6, 0xE7, 0xAE, 0x49, + 0xD1, 0x7C, 0x00, 0xE7, 0x3B, 0xEA, 0xFB, 0x0D, + 0x2A, 0x7B, 0x41, 0x33, 0x66, 0xD0, 0x29, 0x9F, + 0xB3, 0x8A, 0x71, 0xB0, 0xE2, 0x76, 0xA9, 0xDB, + 0xFD, 0x64, 0x04, 0x69, 0xDF, 0x89, 0x1F, 0x56, + 0x86, 0x92, 0xD9, 0xD9, 0xB9, 0xF3, 0x4F, 0xAC, + 0xAE, 0x61, 0x48, 0x20, 0xCE, 0x3C, 0x2B, 0x44, + 0xAB, 0x42, 0xFA, 0xAB, 0x2E, 0x94, 0x82, 0xC8, + 0xD9, 0x97, 0xCF, 0x27, 0xDF, 0xAC, 0xAC, 0xE7, + 0xCA, 0xB2, 0x84, 0xAB, 0xF2, 0x5D, 0xDF, 0x56, + 0x0C, 0x8C, 0x07, 0x3C, 0x3D, 0xA8, 0xDD, 0xBE, + 0xFF, 0x4E, 0x28, 0x0D, 0xB2, 0x2D, 0xE6, 0x9D, + 0x44, 0x21, 0xCB, 0xE7, 0x33, 0x63, 0x22, 0x8F, + 0x4C, 0xFF, 0xB6, 0x1D, 0x9A, 0x71, 0x3F, 0xB1, + 0x29, 0xAE, 0x3A, 0x35, 0xEE, 0x9C, 0x97, 0x68, + 0xA7, 0x52, 0x66, 0x01, 0xD8, 0x9A, 0x5D, 0xF4, + 0xB3, 0x2F, 0x5C, 0xD4, 0x0E, 0xF9, 0xCF, 0x07, + 0xF6, 0x8C, 0xBA, 0xA6, 0x8D, 0x6B, 0xC6, 0x01, + 0xC2, 0x69, 0xAE, 0x60, 0x08, 0x1A, 0x0E, 0x3F, + 0xAE, 0x60, 0x29, 0xF3, 0x48, 0x0D, 0xE0, 0xD0, + 0xAE, 0x52, 0x44, 0xE9, 0x7F, 0x1F, 0x92, 0x5F, + 0x71, 0xAD, 0xEC, 0x6B, 0x47, 0x66, 0x92, 0x22, + 0x27, 0xAE, 0x6E, 0x25, 0xCD, 0xF3, 0x5F, 0x55, + 0x59, 0xBD, 0x73, 0xCE, 0x2B, 0x7E, 0x99, 0x44, + 0x56, 0x70, 0xA3, 0xE7, 0x7A, 0x59, 0x75, 0xD8, + 0x48, 0x0C, 0x39, 0x2B, 0xD7, 0x53, 0xC6, 0xAD, + 0x4A, 0x6F, 0xB4, 0x14, 0x96, 0xDF, 0xF2, 0x4A, + 0x0C, 0xA2, 0xD5, 0x29, 0x98, 0x7C, 0x42, 0x87, + 0xD9, 0x1F, 0x97, 0x61, 0xD9, 0xBF, 0x99, 0x4F, + 0x2C, 0x4C, 0x75, 0xAC, 0xB8, 0x06, 0x75, 0xD6, + 0x87, 0x76, 0x7E, 0xE3, 0x23, 0x4B, 0xEA, 0x1A, + 0x1A, 0xF4, 0xB7, 0x09, 0xAF, 0x53, 0xEB, 0xA6, + 0x39, 0x10, 0xFE, 0xD4, 0xEB, 0x1B, 0xAE, 0x38, + 0x31, 0x33, 0xBA, 0x68, 0xEE, 0xC7, 0x65, 0x76, + 0xFB, 0x49, 0x77, 0xD4, 0x19, 0xC4, 0xE6, 0xA7, + 0x05, 0xFE, 0x2A, 0xDA, 0x39, 0x99, 0x1A, 0x92, + 0xD2, 0xF0, 0x61, 0x97, 0xF6, 0x06, 0x6C, 0x88, + 0x7B, 0x6F, 0x60, 0xE6, 0x70, 0x08, 0xF0, 0xB4, + 0x6B, 0x39, 0x6F, 0x05, 0x41, 0x81, 0xF9, 0xBE, + 0x7A, 0x51, 0xC4, 0x75, 0xB0, 0x6A, 0x89, 0xA0, + 0xA6, 0x9A, 0x5B, 0xEE, 0x7D, 0x78, 0x17, 0x5F, + 0x9F, 0x3B, 0x7D, 0xDD, 0x8A, 0x9E, 0xAA, 0x1A, + 0xDA, 0x49, 0x08, 0xE9, 0xFD, 0x91, 0xA6, 0xFA, + 0xCE, 0xCF, 0x67, 0xDF, 0x0F, 0xC9, 0xD6, 0x38, + 0xD9, 0xD5, 0xD1, 0xC0, 0x76, 0x59, 0x42, 0x53, + 0xBF, 0x48, 0xE9, 0x11, 0x74, 0xC7, 0x11, 0xD8, + 0xE7, 0x8E, 0xD3, 0xC8, 0x25, 0xA1, 0x26, 0x50, + 0xBB, 0xB4, 0x35, 0xAF, 0xAF, 0x06, 0x23, 0x69, + 0x3E, 0x30, 0xFD, 0x7B, 0x34, 0x83, 0x07, 0xD0, + 0xF0, 0x0F, 0x6C, 0x9A, 0x13, 0x5D, 0xC2, 0x7B, + 0xDF, 0x6F, 0xDD, 0x8E, 0xF4, 0x30, 0x82, 0x05, + 0x41, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x05, 0x32, + 0x04, 0x82, 0x05, 0x2E, 0x30, 0x82, 0x05, 0x2A, + 0x30, 0x82, 0x05, 0x26, 0x06, 0x0B, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, + 0x02, 0xA0, 0x82, 0x04, 0xEE, 0x30, 0x82, 0x04, + 0xEA, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, + 0x0E, 0x04, 0x08, 0x74, 0xC0, 0x84, 0x8F, 0xC7, + 0x74, 0x5E, 0x21, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xC8, 0x1E, 0xF4, 0xE9, 0x07, 0x27, + 0x9E, 0x5A, 0xC9, 0x39, 0x1D, 0x37, 0x2C, 0x06, + 0x4B, 0x57, 0xEA, 0xC5, 0x42, 0x9A, 0x60, 0xD5, + 0x42, 0xB2, 0x34, 0x2D, 0xD3, 0x88, 0x7C, 0x78, + 0x87, 0xB6, 0xE9, 0x42, 0x44, 0x1F, 0x67, 0x32, + 0x92, 0x54, 0x22, 0xDA, 0xB2, 0x43, 0xE7, 0x40, + 0xBE, 0x1F, 0xAF, 0x3A, 0xCD, 0x2A, 0x9F, 0xD7, + 0x44, 0x5B, 0x37, 0x69, 0x85, 0xDF, 0xEB, 0x2A, + 0xB9, 0xE2, 0x92, 0x3B, 0xEA, 0xD5, 0x42, 0x53, + 0x95, 0x4A, 0xB0, 0x1B, 0xA5, 0xEF, 0xA6, 0x0D, + 0x29, 0xF4, 0x33, 0xFE, 0xD7, 0x49, 0x04, 0x1E, + 0x8C, 0xAD, 0x63, 0x1E, 0x79, 0x63, 0x74, 0x0C, + 0xE5, 0x5E, 0xA2, 0x2C, 0xBE, 0xB8, 0x90, 0xCE, + 0x06, 0x25, 0xBF, 0xD1, 0x5A, 0x50, 0xCF, 0x3B, + 0x52, 0xE2, 0xA7, 0xFF, 0x19, 0x02, 0xCF, 0xD0, + 0x9B, 0xD9, 0xF7, 0x28, 0x07, 0x38, 0x1F, 0xF2, + 0xAF, 0x44, 0x91, 0x3F, 0x0F, 0xB6, 0x6E, 0x8C, + 0xC0, 0x32, 0x92, 0xC0, 0xCD, 0x25, 0x98, 0x67, + 0xF1, 0x47, 0x52, 0x50, 0xF0, 0xA3, 0x7B, 0xE6, + 0x74, 0xDC, 0x72, 0x28, 0xC8, 0xAB, 0xB3, 0x31, + 0x7D, 0xA3, 0xF7, 0xC7, 0xD1, 0xE6, 0x99, 0xB4, + 0xB6, 0x5A, 0x3A, 0x4D, 0x83, 0x4F, 0xB8, 0xB5, + 0x86, 0xF8, 0x37, 0x7F, 0xA0, 0x16, 0x2F, 0x3C, + 0x62, 0x7A, 0xD4, 0x3A, 0xEB, 0xC2, 0xE8, 0x03, + 0x49, 0x17, 0x9E, 0xFB, 0xD7, 0xAF, 0x91, 0x32, + 0xFD, 0xEA, 0x4F, 0x64, 0xC6, 0x6E, 0x02, 0xEA, + 0xC4, 0xC8, 0x1F, 0x16, 0xC5, 0x4C, 0xFB, 0xC5, + 0x42, 0xF5, 0x85, 0x05, 0x92, 0x59, 0x4B, 0x31, + 0xE5, 0xE9, 0x69, 0xE7, 0x02, 0x98, 0x33, 0xBA, + 0x4C, 0x17, 0x09, 0xEF, 0x89, 0x20, 0xFA, 0x83, + 0x9F, 0xAE, 0x0E, 0x1B, 0x7D, 0x98, 0xB9, 0xF2, + 0x3C, 0x0F, 0xB7, 0x1C, 0x72, 0xDF, 0x17, 0x84, + 0x7F, 0x0A, 0xFD, 0x12, 0x3C, 0x6F, 0x68, 0x5D, + 0x45, 0xEB, 0xB8, 0xD6, 0x24, 0x65, 0x42, 0x75, + 0x5C, 0xC2, 0xF3, 0x3A, 0x6A, 0x4E, 0x51, 0x34, + 0x1B, 0xB6, 0x81, 0xB2, 0x8A, 0xEF, 0x28, 0xA4, + 0xC5, 0x88, 0x9A, 0x97, 0xE0, 0xEF, 0x31, 0x12, + 0x01, 0x7E, 0x1B, 0x43, 0x0F, 0x27, 0x80, 0x87, + 0x98, 0xC5, 0xD5, 0x83, 0xCB, 0x4B, 0xB7, 0x01, + 0x79, 0x60, 0xA1, 0x1A, 0x03, 0x05, 0xC6, 0x36, + 0x04, 0x31, 0x3C, 0x06, 0xDB, 0x08, 0xA8, 0xDA, + 0x8E, 0x32, 0x19, 0x91, 0xF1, 0x0D, 0x61, 0x6F, + 0xE4, 0xB2, 0x79, 0x8A, 0xDE, 0xF4, 0xF7, 0xFB, + 0x2C, 0x23, 0x5B, 0xD9, 0x64, 0x2F, 0xB7, 0xB3, + 0x8B, 0xCA, 0xB8, 0x8C, 0x1D, 0x3B, 0x49, 0x05, + 0x38, 0xA1, 0xE5, 0x8C, 0x1A, 0xDC, 0xA5, 0x61, + 0xFE, 0xF4, 0x2B, 0xDC, 0x77, 0x28, 0xF6, 0x19, + 0xE7, 0xB7, 0x8F, 0x4D, 0x27, 0x2D, 0xED, 0x8A, + 0x3F, 0x3D, 0xDC, 0x9F, 0xD1, 0x30, 0xFF, 0xD6, + 0xC3, 0xBE, 0x41, 0x25, 0xE3, 0xA5, 0x9B, 0x73, + 0xDF, 0x6A, 0xD9, 0xF9, 0x70, 0x84, 0x02, 0x4C, + 0x35, 0xD4, 0x3E, 0x05, 0x76, 0x3A, 0xDC, 0x6D, + 0x5A, 0x81, 0xB3, 0x94, 0xF7, 0x22, 0xF7, 0xDC, + 0xC1, 0x43, 0x31, 0x57, 0x5B, 0x42, 0x9A, 0x0B, + 0xF4, 0x95, 0x30, 0xA9, 0xBB, 0xD8, 0x06, 0xFB, + 0x1D, 0x6F, 0x9B, 0xC3, 0xBB, 0xF3, 0xBF, 0xFB, + 0xB4, 0x9F, 0x35, 0x64, 0x0A, 0x69, 0xB7, 0xD1, + 0x3E, 0xCA, 0x78, 0x07, 0x04, 0x03, 0x79, 0xD4, + 0xF3, 0xA8, 0xEC, 0x18, 0xDB, 0x03, 0x5E, 0x47, + 0xD7, 0xD0, 0x56, 0x2C, 0x74, 0x94, 0x86, 0x04, + 0x46, 0xB8, 0xD4, 0x35, 0x0A, 0x7B, 0xE6, 0x78, + 0xC4, 0x43, 0x3C, 0x56, 0xCC, 0x37, 0x8B, 0xFD, + 0xE8, 0xF4, 0x57, 0xEA, 0xAE, 0xCF, 0x36, 0x97, + 0x12, 0xAC, 0x39, 0xCF, 0x7C, 0xEF, 0x22, 0x67, + 0x01, 0xEC, 0xD8, 0x09, 0x49, 0x4E, 0xE3, 0x74, + 0xDD, 0x39, 0xE1, 0x39, 0xD7, 0x0C, 0x5F, 0x1B, + 0xCE, 0x69, 0xBC, 0x72, 0x44, 0x87, 0x64, 0x1C, + 0x08, 0x05, 0x93, 0x69, 0x6D, 0x7F, 0x90, 0x0A, + 0x2C, 0xCB, 0x8A, 0xBB, 0x7F, 0xE3, 0xE0, 0x80, + 0x31, 0xD0, 0x0A, 0x3A, 0x95, 0xFF, 0xF7, 0xB4, + 0x36, 0x38, 0x93, 0xE0, 0x0C, 0x11, 0x37, 0x12, + 0x06, 0xF6, 0xAD, 0xE9, 0xB1, 0x7A, 0x00, 0xF5, + 0xD2, 0x32, 0x6B, 0xD0, 0x27, 0xA5, 0x1B, 0x3D, + 0xE8, 0xDB, 0xCC, 0xA9, 0x1F, 0x1F, 0xB1, 0x99, + 0x3D, 0x7C, 0xB7, 0xCA, 0xDA, 0x27, 0x2C, 0x64, + 0x1C, 0x49, 0xB6, 0x87, 0x44, 0x06, 0x94, 0x9D, + 0xBC, 0x6B, 0x20, 0xA2, 0x68, 0x15, 0x1F, 0xE2, + 0xF2, 0xAD, 0x6D, 0x23, 0x2E, 0x2B, 0x74, 0xE2, + 0x5D, 0xE4, 0xB0, 0xC7, 0x84, 0xCB, 0x64, 0xBF, + 0xE0, 0xA8, 0x18, 0x83, 0xB4, 0xC9, 0xD9, 0x73, + 0xA8, 0xE6, 0xA9, 0x36, 0xD5, 0x63, 0x1E, 0x2C, + 0x2A, 0x55, 0x09, 0x77, 0x5E, 0xB3, 0x4B, 0xEA, + 0xB5, 0xD0, 0x14, 0x5F, 0xEB, 0x50, 0x7B, 0xAA, + 0xEF, 0x94, 0xBA, 0x2B, 0xD7, 0x8A, 0x07, 0xF1, + 0xF9, 0x5E, 0x12, 0x12, 0x21, 0x52, 0xE5, 0x0A, + 0x3E, 0xC0, 0xBC, 0x5D, 0x4C, 0xE2, 0x12, 0x7C, + 0x39, 0xF9, 0x16, 0x9D, 0xBD, 0x96, 0x83, 0x3B, + 0x7F, 0x3D, 0x6A, 0xEC, 0xF1, 0x25, 0xD2, 0xB0, + 0xB0, 0xEB, 0x20, 0x06, 0x07, 0xD6, 0xD9, 0x4C, + 0x07, 0x9A, 0x82, 0xC1, 0xFC, 0xF7, 0x66, 0x15, + 0xBD, 0x62, 0x65, 0xD8, 0x6C, 0xF6, 0x33, 0x7B, + 0x5A, 0x28, 0xEC, 0x90, 0xA1, 0x26, 0x9F, 0xC3, + 0x28, 0x4A, 0x64, 0x50, 0x5F, 0xCA, 0xE2, 0x6D, + 0xB8, 0x0F, 0xE2, 0x94, 0xB5, 0x8E, 0x1F, 0x8A, + 0x8F, 0x6B, 0xA6, 0x86, 0x1F, 0xEE, 0xDC, 0x24, + 0xB4, 0xB8, 0x25, 0xEC, 0x28, 0x2D, 0xF9, 0xCB, + 0x7D, 0x38, 0xFF, 0xC7, 0x74, 0x2E, 0xD3, 0x10, + 0xEC, 0x03, 0x31, 0xEE, 0x83, 0xE7, 0xA4, 0xF7, + 0xBA, 0x28, 0x21, 0xE0, 0x7F, 0xB4, 0xB7, 0xE1, + 0x7A, 0xF9, 0x2B, 0xB0, 0x2C, 0x3B, 0x80, 0x5F, + 0xE0, 0x5D, 0xB2, 0x7E, 0x59, 0xFF, 0x59, 0x07, + 0x58, 0x42, 0x57, 0xEE, 0x44, 0xF1, 0xB1, 0xAD, + 0xBA, 0xDE, 0xCB, 0x1D, 0x8A, 0x36, 0x67, 0xE8, + 0x45, 0xFF, 0x07, 0x8D, 0xEE, 0xA4, 0x51, 0x9C, + 0x4C, 0x83, 0x5D, 0x2E, 0x2F, 0xE1, 0x5B, 0x75, + 0xE8, 0x29, 0xCD, 0x0B, 0x07, 0x62, 0xE0, 0xC3, + 0x0D, 0x1D, 0xEA, 0xCF, 0xF0, 0x8A, 0x65, 0x27, + 0x70, 0x42, 0x9F, 0x26, 0x00, 0x15, 0x70, 0xC5, + 0x4A, 0xF6, 0x25, 0xD0, 0x40, 0x72, 0xE9, 0xC1, + 0x73, 0xFD, 0x48, 0x94, 0xA3, 0x8D, 0x66, 0x63, + 0x96, 0x4F, 0xF7, 0xEE, 0xFB, 0x4C, 0xC7, 0xB8, + 0x6B, 0xE9, 0x90, 0xE1, 0x2A, 0x66, 0x80, 0x99, + 0x3B, 0xB0, 0x1A, 0x6C, 0xF9, 0x0E, 0x72, 0xDA, + 0x8E, 0x4F, 0x46, 0xC2, 0x6A, 0x4B, 0x7A, 0x16, + 0xE5, 0x26, 0x0B, 0x5C, 0xD4, 0x47, 0x34, 0xE5, + 0x37, 0xBE, 0x68, 0x6C, 0xDA, 0xD3, 0x9B, 0x6F, + 0xAE, 0x51, 0x9C, 0x99, 0x0A, 0x5B, 0xF8, 0x37, + 0xBC, 0xDE, 0xFC, 0x93, 0xC5, 0xE7, 0x0F, 0xEF, + 0x0B, 0xA6, 0x07, 0xC2, 0xA6, 0xE6, 0xDA, 0x2D, + 0x1B, 0x49, 0xC9, 0xDE, 0x6B, 0x27, 0xDC, 0x00, + 0xEF, 0x23, 0x87, 0x0E, 0xEB, 0xD1, 0x48, 0x7D, + 0xB4, 0xF2, 0x58, 0xC6, 0x3C, 0xE2, 0x89, 0xBA, + 0xB0, 0x05, 0xAC, 0x94, 0x41, 0x9A, 0xA8, 0xFF, + 0x3E, 0xBC, 0x3A, 0x52, 0x9C, 0xF9, 0x7F, 0x07, + 0x8B, 0xB0, 0x2C, 0x71, 0x83, 0x7B, 0xCF, 0x2E, + 0x7F, 0x7C, 0x96, 0x65, 0xD9, 0x08, 0x17, 0xEC, + 0xFA, 0xDE, 0x4E, 0x40, 0x12, 0x26, 0x70, 0x71, + 0x65, 0xA5, 0xDC, 0x98, 0x47, 0xA3, 0xFC, 0xE0, + 0x9A, 0x16, 0xED, 0x45, 0x56, 0x72, 0x50, 0x05, + 0x28, 0x2C, 0x99, 0xEC, 0x20, 0x2E, 0x40, 0xC0, + 0x26, 0x69, 0xCD, 0x49, 0x45, 0x17, 0xA4, 0xA3, + 0x42, 0x0D, 0x14, 0x65, 0x87, 0x33, 0x8C, 0x92, + 0xC5, 0xC4, 0x61, 0xFD, 0xE8, 0x68, 0x56, 0x20, + 0x57, 0xF5, 0x8E, 0x5F, 0xCF, 0x7E, 0x97, 0xF6, + 0x49, 0x97, 0x0A, 0xFE, 0xD3, 0x60, 0x1A, 0x5B, + 0x0C, 0x75, 0xDD, 0x8E, 0x31, 0x78, 0x29, 0xA6, + 0xB1, 0x4D, 0xAA, 0xDF, 0x8A, 0xD1, 0xE6, 0x91, + 0xE3, 0x32, 0x3F, 0xEC, 0x8A, 0x1F, 0x0E, 0x35, + 0x07, 0x6E, 0x4B, 0x83, 0x3B, 0xE5, 0x67, 0x34, + 0x1F, 0x0C, 0x81, 0xD8, 0xD5, 0x25, 0x68, 0xE5, + 0x28, 0x1B, 0x5C, 0x81, 0x3E, 0xE3, 0x5C, 0xB4, + 0xB6, 0xBD, 0x62, 0x6A, 0x70, 0x33, 0xC2, 0xC5, + 0x75, 0x27, 0xF4, 0x30, 0xE1, 0x1D, 0xC1, 0x4C, + 0xC5, 0x02, 0x12, 0x46, 0xAC, 0xEC, 0xF9, 0xE8, + 0xE7, 0x58, 0x24, 0x11, 0xB1, 0xF3, 0xB7, 0x8C, + 0x3C, 0xA4, 0x0A, 0x94, 0xA6, 0x7C, 0x68, 0x54, + 0x5B, 0xB9, 0x4D, 0x57, 0x9C, 0xE7, 0x28, 0x09, + 0x6B, 0x89, 0x26, 0x5D, 0xE7, 0x50, 0xA9, 0x95, + 0x90, 0x91, 0x8E, 0x00, 0x59, 0xF8, 0x3A, 0x70, + 0xAF, 0x48, 0x2E, 0xE8, 0xC4, 0x34, 0x8C, 0xF4, + 0x5F, 0x7F, 0xCB, 0x07, 0xAA, 0xF0, 0xD9, 0xFB, + 0x5C, 0x32, 0x90, 0x22, 0x1A, 0xD2, 0x1A, 0xCF, + 0x92, 0x06, 0x02, 0xCF, 0x10, 0x18, 0x7B, 0x93, + 0xCC, 0x07, 0x4A, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xD1, 0xDE, + 0x23, 0x16, 0x9F, 0x6E, 0xF4, 0x42, 0x21, 0x23, + 0xE1, 0x11, 0xAA, 0xC8, 0x7C, 0x60, 0x4A, 0x78, + 0x9D, 0x24, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, + 0x00, 0x04, 0x14, 0xD6, 0x4A, 0xBB, 0x75, 0xB1, + 0xF9, 0x9E, 0xD3, 0x58, 0x6D, 0xD1, 0x74, 0x9F, + 0x00, 0x8A, 0xF2, 0xC8, 0xAA, 0x52, 0x4D, 0x04, + 0x08, 0x77, 0x46, 0xE7, 0xBA, 0x25, 0x4B, 0xDA, + 0x41, 0x02, 0x02, 0x08, 0x00] +}; + +const WPA_EAP_CLIENT_LIST = [ + { + ssid: 'WPA-EAP-TLS', + keyManagement: 'WPA-EAP', + eap: 'TLS', + identity: EAP_USERNAME, + serverCertificate: CLIENT_PKCS12_CERT.nickname, + userCertificate: CLIENT_PKCS12_CERT.nickname + } +]; + +/** + * Convert the given MozWifiNetwork object array to testAssociate chain. + * + * @param aNetworks + * An array of MozWifiNetwork which we want to convert. + * + * @return A promise chain which "then"s testAssociate accordingly. + */ +function convertToTestAssociateChain(aNetworks) { + let chain = Promise.resolve(); + + aNetworks.forEach(function (aNetwork) { + network = new window.MozWifiNetwork(aNetwork); + chain = chain.then(() => gTestSuite.testAssociate(network)); + }); + + return chain; +} + +gTestSuite.doTestWithCertificate( + new Blob([new Uint8Array(CLIENT_PKCS12_CERT.content)]), + CLIENT_PKCS12_CERT.password, + CLIENT_PKCS12_CERT.nickname, + CLIENT_PKCS12_CERT.usage, + function() { + return gTestSuite.ensureWifiEnabled(true) + // Load required server files. + .then(() => gTestSuite.writeFile(SERVER_EAP_USER_CONF.path, SERVER_EAP_USER_CONF.content)) + .then(() => gTestSuite.writeFile(CA_CERT.path, CA_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_CERT.path, SERVER_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_KEY.path, SERVER_KEY.content)) + // Start AP. + .then(() => gTestSuite.startHostapds(WPA_EAP_AP_LIST)) + // Scan test. + .then(() => gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, WPA_EAP_AP_LIST)) + // Associate test. + .then(() => convertToTestAssociateChain(WPA_EAP_CLIENT_LIST)) + // Tear down. + .then(gTestSuite.killAllHostapd) +}); diff --git a/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TTLS.js b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TTLS.js new file mode 100644 index 0000000000..06e0529099 --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_associate_WPA_EAP_TTLS.js @@ -0,0 +1,623 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +const SCAN_RETRY_CNT = 5; + +const EAP_USERNAME = 'username'; +const EAP_PASSWORD = 'password'; + +const SERVER_EAP_USER_CONF = { + path: HOSTAPD_CONFIG_PATH + 'hostapd.eap_user', + content: '* PEAP,TTLS,TLS\n' + + '"' + EAP_USERNAME + '" MSCHAPV2,TTLS-MSCHAPV2 "' + EAP_PASSWORD + '" [2]\n' +}; +const CA_CERT = { + path: HOSTAPD_CONFIG_PATH + 'ca.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIIDsTCCApmgAwIBAgIJAKxTf+8X8qngMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\n' + + 'BAYTAlRXMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTER\n' + + 'MA8GA1UEAwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdt\n' + + 'YWlsLmNvbTAgFw0xNDEyMjQxMTI4NTBaGA8yMjg4MTAwNzExMjg1MFowbjELMAkG\n' + + 'A1UEBhMCVFcxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoMCGNodWNrbGVl\n' + + 'MREwDwYDVQQDDAhjaHVja2xlZTEkMCIGCSqGSIb3DQEJARYVY2h1Y2tsaTA3MDZA\n' + + 'Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo3c2yFxY\n' + + 'o6gGg0I83jy00ME+MAfzCd+4ShL45ZLqysQP93jRBfPzU9ZuZ29ysVwgWIdqkZao\n' + + 'XTuV/NAW2GMGd8W1jQJ3J81fjb9wvhlny3rrACwvUn1N1S1BnM+BAAiDLGxEmvAQ\n' + + 'onp2aaa6HsHsYS8ONX+d2Qh4LEA4vupeSGAqJychCZv/l+aq/ErFZhFYB3CPUQEt\n' + + 'cClO24ucsIYP95lA0zhscnmAj06qplFD4Bv6IVrdDqujy1zNwCQwsJq/8OQdaTN/\n' + + 'h3y9pWvNKMBMM2niOUAjtuNpqsSK/lTS1WAT3PdtVECX9fYBi0Bg+HM92xs/6gt6\n' + + 'kh9jPV8keXHvSwIDAQABo1AwTjAdBgNVHQ4EFgQU7hBqhuG04xeCzrQ3ngx18ZJ3\n' + + 'lUswHwYDVR0jBBgwFoAU7hBqhuG04xeCzrQ3ngx18ZJ3lUswDAYDVR0TBAUwAwEB\n' + + '/zANBgkqhkiG9w0BAQsFAAOCAQEAFYX2iy680GAnBTttk0gyX6gk+8pYr3D22k/G\n' + + '6rvcjefzS7ELQPRKr6mfmwXq3mMf/4jiS2zI5zmXsestPYzHYxf2viQ6t7vr9XiJ\n' + + '3WfFjNw4ERlRisAvg0aqqTNNQq5v2VME4sdFZagy217f73C7azwCHl0bqOLH05rl\n' + + '8RubOxiHEj7ZybJqnRciK/bht4D+rZkwf4bBBmoloqH7xT0+rFQclpYXDGGjNUQB\n' + + 'LcHLF10xcr7g3ZVVu82fe6+d85gIGOIMR9+TKhdw6gO3CNcnDAj6gxksghgtcxmh\n' + + 'OzOggCn7nlIwImtsg2sZkpWB4lEi9hdv4lkNuyFjOL3bnuc+NA==\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_CERT = { + path: HOSTAPD_CONFIG_PATH + 'server.pem', + content: '-----BEGIN CERTIFICATE-----\n' + + 'MIID1DCCArygAwIBAgIBADANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJUVzET\n' + + 'MBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIY2h1Y2tsZWUxETAPBgNVBAMM\n' + + 'CGNodWNrbGVlMSQwIgYJKoZIhvcNAQkBFhVjaHVja2xpMDcwNkBnbWFpbC5jb20w\n' + + 'IBcNMTQxMjI0MTEyOTQ5WhgPMjI4ODEwMDcxMTI5NDlaMG4xCzAJBgNVBAYTAlRX\n' + + 'MRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhjaHVja2xlZTERMA8GA1UE\n' + + 'AwwIY2h1Y2tsZWUxJDAiBgkqhkiG9w0BCQEWFWNodWNrbGkwNzA2QGdtYWlsLmNv\n' + + 'bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdhQmKilTJbWZRxTiSV\n' + + 'rqIU+LYW1RKghx5o+0JpNRJVLuz5kBMaNskbbfUSNuHbEq0QA9BDKAZWIc4LSotk\n' + + 'lCo8TbcO9CJvJPQGGjGdHcohWX5vy6BE/OVE46CUteMFyZF6F8R2fNUww08iR/u1\n' + + 'YZebL5pWO1j43sPpAzEy6Tij2ACPt6EZcFaZG3SF2mVJWkCQnBqrojP65WUvZQqp\n' + + 'seUhW2YAS8Nu0Yrohgxz6VYk+cNDuDZVGs6qWRStZzJfYrfc76DtkHof5B14M+xp\n' + + 'XJaBLxN+whvnYkDTfinaCxnW1O7eXUltr87fLc5zmeBkgwaiaQuIdcfZm7vDUiz8\n' + + 'vnUCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH\n' + + 'ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFKK4f9/YavTHOfEiAB83Deac\n' + + '6gT5MB8GA1UdIwQYMBaAFO4QaobhtOMXgs60N54MdfGSd5VLMA0GCSqGSIb3DQEB\n' + + 'CwUAA4IBAQBWnO9o9KSJIqjoz5Nwll63ULOdcvgGdOeJIw1fcKQ817Rsp+TVcjcH\n' + + 'IrIADsT/QZGXRO/l6p1750e2iFtJEo1hsRaxtA1wWn2I9HO3+av2spQhr3jpYGPf\n' + + 'zpsMTp4RNYV7Q8+q1kZIz9PY4V1T0p6lveK8+fUj2hSLnxSj0QiGSJJtnEC3w4Rv\n' + + 'C9T6oUwIeToULmi+8FXQFdEqwKRU98DPq3eLzN28ZxUgoPE1C8+42D2UW8uyp/Gm\n' + + 'tGOa/k7nzkCdVqZI7lX7f0AjEvQgjtAMQ/k7Mhxx7TzW2HO+1YPMoKji6Z4WkNwt\n' + + 'JEj9ZUBSNt8B26UksJMBDkcvSegF3a7o\n' + + '-----END CERTIFICATE-----\n' +}; + +const SERVER_KEY = { + path: HOSTAPD_CONFIG_PATH + 'server.key', + content: '-----BEGIN RSA PRIVATE KEY-----\n' + + 'MIIEpAIBAAKCAQEAx2FCYqKVMltZlHFOJJWuohT4thbVEqCHHmj7Qmk1ElUu7PmQ\n' + + 'Exo2yRtt9RI24dsSrRAD0EMoBlYhzgtKi2SUKjxNtw70Im8k9AYaMZ0dyiFZfm/L\n' + + 'oET85UTjoJS14wXJkXoXxHZ81TDDTyJH+7Vhl5svmlY7WPjew+kDMTLpOKPYAI+3\n' + + 'oRlwVpkbdIXaZUlaQJCcGquiM/rlZS9lCqmx5SFbZgBLw27RiuiGDHPpViT5w0O4\n' + + 'NlUazqpZFK1nMl9it9zvoO2Qeh/kHXgz7GlcloEvE37CG+diQNN+KdoLGdbU7t5d\n' + + 'SW2vzt8tznOZ4GSDBqJpC4h1x9mbu8NSLPy+dQIDAQABAoIBAASG4Mr8hgaurEoC\n' + + 'iJOsElr7vunjetMBcg/uskW/vcS8ymP3Bp5oafYG+WgnEbfvEW18f5mq7K24JuxW\n' + + 'tUqU7ghHdjxByqk9fMlNmiqmNpbwSufkAeuRpWxPNBvhRH/zEbCL5R5A0nTEtqqF\n' + + 'TL0aUSzwCRSoAJD0lZo9ICVt0n3GsDyM9rqQg/uZmh1qsRdwPsRuYORND9g48rKq\n' + + '6WN9leskSxhhsYE2D9ocOFd9bNt8Zxejh9ppVSnG/KsIdt18iBzcabatgAQ046fb\n' + + 'Z3vprcZJLg93Sg2gSuVqlSTs3M2W8VQnm22/EBMb1y0M48MSRCgnbPLG/CcCLLfF\n' + + 'LwxCOgECgYEA/eYt67xyJ6JeAdxdwOZuT1WWGbFpLiG9+2OgiHumyRQ5969XMTWo\n' + + 'fIhMKchDdjoy9RR236\/\/EFCs7UEyB7+a7ODRzNiK2zCD8Smjp+21fUPSthEeQesk\n' + + 'eiMYICIu5Ay35x9sxIX+XOUVvRhPOGcD29GVeRnKh1inTHOz2dje8LkCgYEAyQeY\n' + + 'STi9jjCEcHkM1E/UeDiLfHHepLXi8wS41JNRHl5Jacp7XB5djAjKu/jf367/VpFy\n' + + 'GDDMetE7n8eWkrnAvovxOwZ000YDMtL1sUYSjL+XtBS5s6VY1p4qaSAY9nUUGrJh\n' + + 'JvtvsuI7SKTtL+60vjBOH7zDnvOdBgAp0utLhZ0CgYEAuLzzqrPKB8afShFSchn4\n' + + 'J2dpuLYahsNsXW7HDqeR2nsKFosRETAusLXnXPtnAq4kB6jlOarwFqnsuRCX24Vx\n' + + 'r2uBm9/vYL7zMdUPTA+s30ErHuhjsKjsOKYyVqcooSwT32pBFNk+E89nutfmRG7I\n' + + 'IvhjHuNCNqqtx/Xj5d1jkZkCgYBQicppC2Jl5OoqZVTOem0U/RJk+PnJ41TZJ7sk\n' + + '7yBAmmWvDH\/\/l+rCf4M5a6vFYcbKV9rt9h711X2dtciNX/3oWQh8LUoAmrwNUJc+\n' + + 'PmSQHvIYI3WCk2vUD+nN1B4sHxu+1lg11eYaNKiroeeknG2tBI1ICcgVlmQCU25u\n' + + 'IfZPwQKBgQCdO6QHhPLtcHUDNFA6FQ1jKL1iEd7G0JLVRz4Xkpkn1Vrr5MD6JFDa\n' + + '5ccabADyl0lpFqDIVJQIzLku2hOD2i9aBNCY0pL391HeOS7CkZX+TdOY1tquoBq5\n' + + 'MnmixZjDCVd2VcrVyTA6ntOBoharKFW0rH1PqU+qu7dZF7CBPbAdEw==\n' + + '-----END RSA PRIVATE KEY-----\n' +}; + +const WPA_EAP_AP_LIST = [ + { + ssid: 'WPA-EAP-TTLS', + ieee8021x: 1, + eapol_version: 1, + eap_server: 1, + eapol_key_index_workaround: 0, + eap_user_file: SERVER_EAP_USER_CONF.path, + ca_cert: CA_CERT.path, + server_cert: SERVER_CERT.path, + private_key: SERVER_KEY.path, + wpa: 3, + wpa_key_mgmt: 'WPA-EAP' + } +]; + +const CLIENT_PKCS12_CERT = { + nickname: 'client', + password: 'password', + usage: ['UserCert', 'ServerCert'], + content: [0x30, 0x82, 0x0E, 0x01, 0x02, 0x01, 0x03, 0x30, + 0x82, 0x0D, 0xC7, 0x06, 0x09, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, + 0x0D, 0xB8, 0x04, 0x82, 0x0D, 0xB4, 0x30, 0x82, + 0x0D, 0xB0, 0x30, 0x82, 0x08, 0x67, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, + 0x06, 0xA0, 0x82, 0x08, 0x58, 0x30, 0x82, 0x08, + 0x54, 0x02, 0x01, 0x00, 0x30, 0x82, 0x08, 0x4D, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x01, 0x30, 0x1C, 0x06, 0x0A, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, + 0x06, 0x30, 0x0E, 0x04, 0x08, 0x67, 0x7A, 0xF3, + 0x61, 0xBE, 0xE0, 0x51, 0xC1, 0x02, 0x02, 0x08, + 0x00, 0x80, 0x82, 0x08, 0x20, 0xFC, 0x6A, 0x79, + 0xA1, 0x6C, 0xAF, 0xBE, 0xEE, 0x62, 0x45, 0x33, + 0xB8, 0x48, 0xE1, 0x68, 0xA1, 0x15, 0x11, 0x4B, + 0x95, 0xCB, 0x77, 0xC0, 0x5D, 0xA2, 0xCB, 0xDB, + 0xD1, 0x83, 0x74, 0x60, 0xD7, 0xEC, 0x42, 0xA6, + 0x3A, 0x23, 0xF7, 0x85, 0xEB, 0xC1, 0xFE, 0x6A, + 0x57, 0x8E, 0xC1, 0x44, 0xF3, 0x1F, 0xFE, 0xB8, + 0x2D, 0x8C, 0x4D, 0xC9, 0x5B, 0xAE, 0x21, 0x2E, + 0x4C, 0x1A, 0xEB, 0x84, 0x09, 0xF3, 0x40, 0x92, + 0x39, 0x7F, 0x56, 0x02, 0x46, 0x61, 0x16, 0xDE, + 0x5C, 0x48, 0xB6, 0x0C, 0x1D, 0xD3, 0x5F, 0x10, + 0x9A, 0x39, 0xB8, 0x66, 0x31, 0xFC, 0x39, 0x71, + 0x87, 0x23, 0x46, 0x9D, 0xE8, 0x3C, 0x2B, 0xA1, + 0x39, 0x8A, 0xD3, 0xFF, 0xD9, 0x43, 0xB6, 0x61, + 0xC6, 0x67, 0x70, 0x40, 0xBD, 0xFE, 0xD3, 0xC1, + 0x68, 0xF5, 0xF7, 0xC8, 0x89, 0xD8, 0x17, 0xC5, + 0xE8, 0x3D, 0x29, 0xD5, 0x91, 0xDF, 0x1F, 0x56, + 0x74, 0x5A, 0xC4, 0xA8, 0x14, 0xBA, 0xD4, 0xFA, + 0x13, 0x49, 0x2A, 0x9F, 0x63, 0xF1, 0xB2, 0x45, + 0xF1, 0xF0, 0x2A, 0xDD, 0x75, 0x66, 0x8A, 0xF7, + 0xAB, 0x73, 0x86, 0x26, 0x9D, 0x1F, 0x07, 0xAD, + 0xD3, 0xFE, 0xE0, 0xA3, 0xED, 0xA0, 0x96, 0x3E, + 0x1E, 0x89, 0x86, 0x02, 0x4C, 0x28, 0xFD, 0x57, + 0xA1, 0x67, 0x55, 0xF0, 0x82, 0x3B, 0x7F, 0xCC, + 0x2A, 0x32, 0x01, 0x93, 0x1D, 0x8B, 0x66, 0x8A, + 0x20, 0x52, 0x84, 0xDD, 0x2C, 0xFD, 0xEE, 0x72, + 0xF3, 0x8C, 0x58, 0xB9, 0x99, 0xE5, 0xC1, 0x22, + 0x63, 0x59, 0x00, 0xE2, 0x76, 0xC5, 0x3A, 0x17, + 0x7F, 0x93, 0xE9, 0x67, 0x61, 0xAA, 0x10, 0xC3, + 0xD9, 0xC8, 0x24, 0x46, 0x5B, 0xBE, 0x8C, 0x1F, + 0x2D, 0x66, 0x48, 0xD2, 0x02, 0x11, 0xFB, 0x74, + 0x14, 0x76, 0x76, 0x5A, 0x98, 0x54, 0x35, 0xA7, + 0x85, 0x66, 0x20, 0x26, 0x8B, 0x13, 0x6F, 0x68, + 0xE3, 0xC9, 0x58, 0x7D, 0x1C, 0x3E, 0x01, 0x8D, + 0xF8, 0xD6, 0x7F, 0xCF, 0xA2, 0x07, 0xB7, 0x95, + 0xFD, 0xF0, 0x02, 0x34, 0x32, 0x30, 0xE8, 0xD4, + 0x57, 0x5E, 0x53, 0xFB, 0x54, 0xE2, 0x03, 0x32, + 0xCC, 0x52, 0x2E, 0xD2, 0x35, 0xD9, 0x58, 0x85, + 0x2D, 0xEC, 0x2D, 0x71, 0xD1, 0x8A, 0x29, 0xD0, + 0xB0, 0x24, 0xBD, 0x24, 0xDC, 0x1A, 0x28, 0x3F, + 0xA0, 0x12, 0x81, 0x15, 0x24, 0xC9, 0xB5, 0x4A, + 0x23, 0xB6, 0xA3, 0x45, 0x50, 0x2D, 0x73, 0x99, + 0x6B, 0x1C, 0xFB, 0xA4, 0x53, 0xD7, 0x5C, 0xF4, + 0x6C, 0xB0, 0xE5, 0x74, 0xB3, 0x76, 0xF8, 0xB1, + 0x0D, 0x59, 0x70, 0x9F, 0xCA, 0xDE, 0xF2, 0xAA, + 0x4C, 0x7D, 0x11, 0x54, 0xC4, 0x19, 0x0F, 0x36, + 0x4A, 0x62, 0xFF, 0x8B, 0x10, 0xCB, 0x93, 0x50, + 0xDA, 0x79, 0x5E, 0x4E, 0x09, 0x1F, 0x22, 0xC8, + 0x19, 0x85, 0xE9, 0xEE, 0xB7, 0x71, 0x65, 0xB9, + 0x10, 0xD2, 0x0A, 0x73, 0x5B, 0xA6, 0xDA, 0x37, + 0x46, 0x02, 0x00, 0x98, 0x9E, 0x20, 0x6C, 0x7D, + 0xC7, 0x69, 0xBB, 0xC2, 0x00, 0x40, 0x9C, 0x57, + 0x00, 0xC2, 0x36, 0x76, 0xE8, 0x2A, 0x8D, 0xAD, + 0x62, 0x57, 0xC8, 0xD0, 0x9D, 0x66, 0x27, 0x5A, + 0xD8, 0x0D, 0x35, 0x60, 0x28, 0x38, 0x62, 0x94, + 0x78, 0x36, 0x25, 0x58, 0xFD, 0xF8, 0x66, 0x1F, + 0x68, 0x04, 0x0F, 0xD8, 0x00, 0xDF, 0xA0, 0x6C, + 0x25, 0x42, 0x9A, 0x4C, 0xEB, 0x80, 0x13, 0x51, + 0x7D, 0x2D, 0xA8, 0x89, 0xD6, 0x1B, 0x67, 0x72, + 0x01, 0xF3, 0x2D, 0x16, 0x77, 0xFE, 0x22, 0xBC, + 0x8A, 0x45, 0x09, 0x1F, 0x9C, 0x2F, 0x2A, 0xA9, + 0x61, 0x5B, 0x4A, 0xE6, 0x64, 0x2C, 0x62, 0x1A, + 0x3A, 0x96, 0xE6, 0x0A, 0xAE, 0x05, 0x1A, 0xC8, + 0xCB, 0xD6, 0x8F, 0x3A, 0x4B, 0xE0, 0x7F, 0x82, + 0xB4, 0x98, 0xF1, 0x9D, 0xD7, 0x14, 0x76, 0x5E, + 0x77, 0x85, 0x87, 0xEC, 0x13, 0xDA, 0xFD, 0xAF, + 0xCB, 0xA3, 0x1C, 0x99, 0xC1, 0xFE, 0x17, 0x0C, + 0x40, 0x4D, 0x3C, 0x8F, 0x70, 0x86, 0x63, 0x64, + 0xB7, 0x75, 0xA8, 0x71, 0x36, 0xDC, 0x54, 0x10, + 0x57, 0x0C, 0xA8, 0xF2, 0xA1, 0xBB, 0xED, 0x03, + 0x41, 0x57, 0x34, 0x2C, 0x8F, 0x7C, 0xA0, 0x09, + 0xF3, 0x9E, 0x41, 0xB7, 0xA8, 0xD4, 0x66, 0x0D, + 0x0D, 0xC0, 0x6A, 0xFC, 0x6A, 0xA2, 0xAC, 0xE2, + 0x60, 0x00, 0xE3, 0xF7, 0x75, 0x43, 0x23, 0xEB, + 0xC8, 0x61, 0xFA, 0xB3, 0xB8, 0x28, 0xCE, 0xCA, + 0xF4, 0x47, 0x7F, 0x30, 0x6D, 0x61, 0x89, 0x47, + 0xA1, 0x4A, 0xFE, 0xD1, 0x21, 0x0B, 0x6D, 0xF4, + 0x3F, 0x00, 0x86, 0x30, 0x8E, 0x33, 0x21, 0x6F, + 0xDA, 0x15, 0xFD, 0x5F, 0xEC, 0x8E, 0xF1, 0x12, + 0x3F, 0xC9, 0x83, 0x0C, 0xCA, 0x22, 0x01, 0xF1, + 0x70, 0x5F, 0x1F, 0x66, 0xB5, 0xF8, 0x3E, 0x7A, + 0x6F, 0xDE, 0xDB, 0xA7, 0x8D, 0x18, 0x9E, 0xBE, + 0xDB, 0xAD, 0x3D, 0x66, 0x30, 0xC1, 0x6C, 0x0C, + 0x87, 0xB4, 0x65, 0x75, 0xE0, 0x9D, 0xEA, 0x16, + 0x0D, 0x07, 0x37, 0x33, 0xC5, 0xEC, 0x97, 0x93, + 0x37, 0xEB, 0x8E, 0x65, 0x9C, 0x40, 0x63, 0x6C, + 0x43, 0x60, 0xB0, 0x40, 0x4D, 0x85, 0xEF, 0xC2, + 0x47, 0x5F, 0xE7, 0x6B, 0xCB, 0x40, 0xE8, 0xEA, + 0xD8, 0xAB, 0xB1, 0x9A, 0x72, 0xDC, 0x4C, 0x14, + 0xFA, 0x43, 0x61, 0x5F, 0xA6, 0x5C, 0x3A, 0x05, + 0x17, 0x2E, 0x74, 0xF3, 0x5E, 0x45, 0xD9, 0x47, + 0xAA, 0x59, 0xB6, 0x8F, 0x42, 0x66, 0x42, 0x29, + 0x90, 0x95, 0x48, 0x46, 0x91, 0x88, 0x3C, 0x8C, + 0xDE, 0xCC, 0xED, 0xB3, 0xAA, 0x62, 0xEA, 0xBC, + 0xB4, 0x0C, 0x48, 0x4C, 0x53, 0x23, 0x5E, 0x24, + 0x85, 0xBF, 0x92, 0xDA, 0x14, 0xDB, 0x1A, 0x3D, + 0xEF, 0x30, 0xD9, 0x49, 0x64, 0x4D, 0xE5, 0x01, + 0xFC, 0xA4, 0x4B, 0xD1, 0x9F, 0xDE, 0x96, 0x7F, + 0x50, 0xBC, 0x4D, 0x38, 0x44, 0xE9, 0x23, 0x5F, + 0x37, 0x57, 0x1A, 0xA6, 0x52, 0x5A, 0x0F, 0x4F, + 0x87, 0x33, 0x4A, 0x7B, 0x66, 0xEE, 0x3D, 0x66, + 0x0A, 0x63, 0x39, 0x1F, 0x23, 0x38, 0x35, 0x73, + 0x60, 0x5E, 0x47, 0x20, 0x4F, 0xC0, 0xC8, 0x3C, + 0x09, 0xF9, 0x29, 0x4F, 0x5E, 0x55, 0x69, 0xC4, + 0x6B, 0xE8, 0xF8, 0x91, 0xC0, 0x22, 0x65, 0x15, + 0x1E, 0xFB, 0xB9, 0x61, 0xCE, 0x45, 0xBE, 0x2B, + 0xEE, 0xB9, 0x04, 0x2B, 0xFD, 0xAE, 0x61, 0x1C, + 0x3D, 0x3D, 0x7C, 0xBF, 0xC1, 0xF7, 0x3C, 0x4E, + 0x9E, 0x0E, 0x54, 0xC8, 0xAD, 0xA9, 0xDF, 0x43, + 0x49, 0xB9, 0x41, 0x05, 0xE5, 0xF1, 0x49, 0xAA, + 0x77, 0x6C, 0x34, 0x5B, 0x93, 0x24, 0x24, 0x23, + 0x74, 0x68, 0x11, 0xCE, 0x15, 0x80, 0xA1, 0xA4, + 0x1F, 0x8D, 0x81, 0xCD, 0xB2, 0x98, 0xCA, 0x14, + 0x0B, 0x0C, 0x61, 0x50, 0x69, 0x72, 0xAE, 0xFA, + 0x8B, 0xC0, 0x3F, 0x0D, 0xE7, 0xF2, 0x0F, 0xEB, + 0xC1, 0x11, 0xB9, 0x10, 0x03, 0x6A, 0xF5, 0x97, + 0x3C, 0x53, 0x2F, 0x67, 0x86, 0x09, 0x6A, 0xE3, + 0x28, 0xC0, 0x78, 0xC8, 0xB4, 0x39, 0x8E, 0xD1, + 0xCE, 0x25, 0xE8, 0x66, 0xF7, 0x09, 0x40, 0x7D, + 0x81, 0xFB, 0xAF, 0xFA, 0x59, 0xC4, 0x9B, 0x2B, + 0x83, 0x45, 0x5B, 0xA8, 0x66, 0x9E, 0x38, 0xC8, + 0xFD, 0xAC, 0xF2, 0x2D, 0x21, 0xDE, 0x50, 0x4C, + 0x03, 0xCB, 0x88, 0x42, 0xDD, 0x84, 0x09, 0x99, + 0x8E, 0x8B, 0x40, 0x97, 0x1B, 0x14, 0x85, 0x37, + 0x11, 0x01, 0xE0, 0x74, 0x6B, 0x33, 0x52, 0x8C, + 0x68, 0x3A, 0x89, 0xB2, 0xAF, 0x35, 0xE6, 0x65, + 0xC3, 0x58, 0x70, 0xD2, 0xE7, 0x1F, 0x1F, 0xF6, + 0xE5, 0x0A, 0xB1, 0xFE, 0xD0, 0xC9, 0x51, 0x50, + 0xE7, 0xFD, 0x58, 0xF5, 0xC4, 0x58, 0x65, 0x94, + 0xD1, 0x57, 0x55, 0x5E, 0xD2, 0x27, 0x98, 0xAF, + 0xE7, 0x55, 0x0B, 0x87, 0x50, 0x9B, 0xEF, 0xE8, + 0x2B, 0xFC, 0xE7, 0x3B, 0x4E, 0xD7, 0xB7, 0x4D, + 0xF4, 0xBC, 0xF4, 0x88, 0x63, 0xE4, 0x8A, 0x20, + 0x4B, 0x22, 0xB0, 0xA0, 0x53, 0x7F, 0xA8, 0xC9, + 0x0C, 0xF8, 0xD7, 0xBD, 0x46, 0x39, 0xA7, 0x7D, + 0xDD, 0x10, 0x91, 0x50, 0x54, 0x06, 0x47, 0xF0, + 0x3C, 0xAA, 0x43, 0x40, 0xF8, 0x54, 0xDD, 0x8A, + 0xEA, 0x8A, 0x0B, 0xA5, 0x7F, 0xCD, 0x5E, 0xAA, + 0x02, 0x2E, 0x1F, 0xC6, 0x50, 0x15, 0xF8, 0x0A, + 0x0C, 0x1B, 0x3C, 0x55, 0x3A, 0xC3, 0x6F, 0x88, + 0xD7, 0xBF, 0xB1, 0x02, 0xCC, 0xE0, 0x08, 0x29, + 0x97, 0xD2, 0xAA, 0x23, 0xC4, 0x6D, 0xE3, 0xE3, + 0x76, 0x39, 0x92, 0xC3, 0x2E, 0x7A, 0xE2, 0x98, + 0xD1, 0xFC, 0xAE, 0xCC, 0x95, 0xD8, 0xB4, 0xDC, + 0x92, 0xEA, 0x6A, 0x5F, 0xF2, 0x92, 0x17, 0x0B, + 0x8D, 0xC3, 0xFA, 0x9C, 0x62, 0xCE, 0x44, 0x8D, + 0xC3, 0x1E, 0xC3, 0xB2, 0xD5, 0x00, 0xCD, 0xB4, + 0x9E, 0x2D, 0x7B, 0xF2, 0x98, 0xA3, 0x00, 0x8B, + 0x81, 0x30, 0x77, 0x5B, 0x02, 0x99, 0xB1, 0xCD, + 0xC3, 0x1D, 0x74, 0x74, 0xEF, 0x41, 0xCB, 0x69, + 0x63, 0x8E, 0xA6, 0xD3, 0x2D, 0x3E, 0x1F, 0x1D, + 0x12, 0x9E, 0xD9, 0x18, 0x67, 0x06, 0xAF, 0x37, + 0x29, 0xAD, 0x65, 0xD8, 0xEB, 0x71, 0xC4, 0x7D, + 0x94, 0x3D, 0xEA, 0xCC, 0xDF, 0x72, 0x41, 0x51, + 0x3C, 0xA1, 0x66, 0x98, 0x32, 0x32, 0x40, 0x54, + 0xB0, 0x2F, 0xEB, 0xCE, 0xDF, 0x4A, 0x64, 0xFB, + 0x9A, 0x90, 0xDC, 0xF6, 0x6F, 0xA9, 0xD4, 0xCA, + 0xCB, 0x91, 0xC4, 0xFE, 0xEE, 0x9C, 0x01, 0x50, + 0x2E, 0xAC, 0xCC, 0x5F, 0x89, 0xD0, 0x91, 0xA3, + 0xD9, 0xF9, 0x4B, 0x8D, 0xDE, 0x6C, 0x60, 0x21, + 0x19, 0xB1, 0xD3, 0x4D, 0x75, 0x56, 0x6F, 0xB8, + 0x25, 0xA4, 0x92, 0x4F, 0x12, 0xF5, 0x8F, 0xC1, + 0x17, 0x4B, 0xB3, 0x34, 0x21, 0x22, 0xAC, 0x52, + 0xD2, 0x64, 0xC9, 0x9A, 0x7D, 0xFC, 0xC0, 0x0A, + 0x89, 0x34, 0xFF, 0x08, 0xD3, 0x04, 0xDC, 0xFE, + 0x7C, 0xB3, 0xB8, 0xFD, 0x85, 0xDD, 0x79, 0x51, + 0xA7, 0x89, 0xE8, 0xF1, 0x23, 0xB1, 0xDF, 0xD7, + 0x1F, 0x7B, 0xB1, 0x5D, 0x42, 0xF9, 0x61, 0xF8, + 0xDC, 0x81, 0x04, 0xF1, 0xCC, 0xFA, 0xD7, 0xED, + 0xBF, 0x47, 0xAC, 0xBD, 0xE5, 0xFA, 0xAC, 0xB3, + 0x1C, 0xD9, 0xA1, 0xB3, 0x60, 0xEE, 0x9C, 0x8A, + 0x36, 0x57, 0xB4, 0x2F, 0xA1, 0xA2, 0xF3, 0xE2, + 0x09, 0x9A, 0x6E, 0x43, 0x9B, 0xE5, 0x93, 0xB8, + 0x3D, 0x9E, 0x9F, 0xC1, 0xC6, 0x0D, 0x02, 0xEB, + 0x4D, 0x38, 0xE9, 0xB4, 0x9F, 0xEA, 0x33, 0x8C, + 0x07, 0xD8, 0xB4, 0x71, 0xAD, 0xE5, 0x43, 0xB2, + 0xCC, 0x55, 0x93, 0x6A, 0xDB, 0x1E, 0x80, 0xDB, + 0xC2, 0xEA, 0x42, 0x8E, 0xFC, 0x86, 0x44, 0xC9, + 0x8A, 0xC4, 0xF2, 0x46, 0xA7, 0x39, 0x50, 0x0D, + 0x1A, 0xAA, 0x07, 0x04, 0xBE, 0xD4, 0xCE, 0x62, + 0x4D, 0x0F, 0x91, 0x7D, 0x29, 0x88, 0x9C, 0x4C, + 0xAF, 0xF7, 0xD8, 0x40, 0x93, 0x88, 0xC7, 0x20, + 0xD2, 0x17, 0x2A, 0xC4, 0x92, 0x72, 0xD0, 0xC0, + 0x4E, 0x56, 0x47, 0xB1, 0x27, 0x02, 0xE6, 0x61, + 0x82, 0x5E, 0xC8, 0x2E, 0x90, 0xD2, 0x31, 0x22, + 0xE2, 0xA9, 0x4A, 0x91, 0x45, 0x69, 0xB1, 0xA5, + 0x0F, 0x66, 0x2C, 0x30, 0xAD, 0x7F, 0x1B, 0x0E, + 0x22, 0x17, 0x60, 0x2E, 0x3D, 0x7F, 0x7F, 0x8C, + 0x33, 0x51, 0xA0, 0x25, 0xDE, 0xFD, 0x75, 0xBC, + 0xEF, 0xE6, 0xE7, 0x20, 0x04, 0x5A, 0xEC, 0x50, + 0x21, 0x48, 0x56, 0x98, 0xE2, 0x33, 0x6D, 0x22, + 0x5C, 0xC3, 0xFB, 0xFC, 0x6F, 0xB3, 0xA7, 0x8E, + 0x6F, 0x67, 0x70, 0x9D, 0xDA, 0x02, 0x01, 0x59, + 0x7B, 0x3D, 0x2B, 0x38, 0xCC, 0x0F, 0x44, 0x3D, + 0xFB, 0x9A, 0xB3, 0x23, 0x15, 0x50, 0x6E, 0xBF, + 0x8B, 0xA1, 0x94, 0x33, 0xE5, 0x7B, 0x88, 0x4E, + 0xCB, 0x6D, 0x9F, 0xBF, 0xBC, 0x7A, 0xA8, 0x1E, + 0x68, 0x25, 0xED, 0x8E, 0x53, 0x21, 0x72, 0xC5, + 0x70, 0xB3, 0xE4, 0xA6, 0xA1, 0x5A, 0x2D, 0xC8, + 0x43, 0x9D, 0x60, 0x77, 0x78, 0xE0, 0xC4, 0xAF, + 0xC8, 0x29, 0xBA, 0xD0, 0x4D, 0x39, 0x83, 0x51, + 0xA7, 0x10, 0x7F, 0x0C, 0x34, 0x0E, 0x6C, 0x75, + 0x26, 0xD7, 0xD6, 0xC7, 0x32, 0x53, 0xAF, 0x4E, + 0xBE, 0xF2, 0xC2, 0x0F, 0x99, 0x23, 0xB9, 0xE1, + 0xC8, 0xB4, 0xBC, 0x5A, 0xC6, 0xCB, 0xEB, 0x4D, + 0x28, 0x56, 0x72, 0xFE, 0x1B, 0x2C, 0x5D, 0xE3, + 0xBC, 0xC7, 0xA3, 0xC0, 0x7D, 0x27, 0xF0, 0xD0, + 0x4F, 0x3F, 0x1F, 0xF7, 0x87, 0x15, 0xF2, 0xEA, + 0xD4, 0x03, 0x6D, 0x2F, 0xD4, 0x8E, 0x50, 0x4B, + 0x05, 0xBF, 0xF7, 0x8C, 0x67, 0x5A, 0xDC, 0x4D, + 0xCD, 0xCF, 0x9D, 0x02, 0xB6, 0xE7, 0xAE, 0x49, + 0xD1, 0x7C, 0x00, 0xE7, 0x3B, 0xEA, 0xFB, 0x0D, + 0x2A, 0x7B, 0x41, 0x33, 0x66, 0xD0, 0x29, 0x9F, + 0xB3, 0x8A, 0x71, 0xB0, 0xE2, 0x76, 0xA9, 0xDB, + 0xFD, 0x64, 0x04, 0x69, 0xDF, 0x89, 0x1F, 0x56, + 0x86, 0x92, 0xD9, 0xD9, 0xB9, 0xF3, 0x4F, 0xAC, + 0xAE, 0x61, 0x48, 0x20, 0xCE, 0x3C, 0x2B, 0x44, + 0xAB, 0x42, 0xFA, 0xAB, 0x2E, 0x94, 0x82, 0xC8, + 0xD9, 0x97, 0xCF, 0x27, 0xDF, 0xAC, 0xAC, 0xE7, + 0xCA, 0xB2, 0x84, 0xAB, 0xF2, 0x5D, 0xDF, 0x56, + 0x0C, 0x8C, 0x07, 0x3C, 0x3D, 0xA8, 0xDD, 0xBE, + 0xFF, 0x4E, 0x28, 0x0D, 0xB2, 0x2D, 0xE6, 0x9D, + 0x44, 0x21, 0xCB, 0xE7, 0x33, 0x63, 0x22, 0x8F, + 0x4C, 0xFF, 0xB6, 0x1D, 0x9A, 0x71, 0x3F, 0xB1, + 0x29, 0xAE, 0x3A, 0x35, 0xEE, 0x9C, 0x97, 0x68, + 0xA7, 0x52, 0x66, 0x01, 0xD8, 0x9A, 0x5D, 0xF4, + 0xB3, 0x2F, 0x5C, 0xD4, 0x0E, 0xF9, 0xCF, 0x07, + 0xF6, 0x8C, 0xBA, 0xA6, 0x8D, 0x6B, 0xC6, 0x01, + 0xC2, 0x69, 0xAE, 0x60, 0x08, 0x1A, 0x0E, 0x3F, + 0xAE, 0x60, 0x29, 0xF3, 0x48, 0x0D, 0xE0, 0xD0, + 0xAE, 0x52, 0x44, 0xE9, 0x7F, 0x1F, 0x92, 0x5F, + 0x71, 0xAD, 0xEC, 0x6B, 0x47, 0x66, 0x92, 0x22, + 0x27, 0xAE, 0x6E, 0x25, 0xCD, 0xF3, 0x5F, 0x55, + 0x59, 0xBD, 0x73, 0xCE, 0x2B, 0x7E, 0x99, 0x44, + 0x56, 0x70, 0xA3, 0xE7, 0x7A, 0x59, 0x75, 0xD8, + 0x48, 0x0C, 0x39, 0x2B, 0xD7, 0x53, 0xC6, 0xAD, + 0x4A, 0x6F, 0xB4, 0x14, 0x96, 0xDF, 0xF2, 0x4A, + 0x0C, 0xA2, 0xD5, 0x29, 0x98, 0x7C, 0x42, 0x87, + 0xD9, 0x1F, 0x97, 0x61, 0xD9, 0xBF, 0x99, 0x4F, + 0x2C, 0x4C, 0x75, 0xAC, 0xB8, 0x06, 0x75, 0xD6, + 0x87, 0x76, 0x7E, 0xE3, 0x23, 0x4B, 0xEA, 0x1A, + 0x1A, 0xF4, 0xB7, 0x09, 0xAF, 0x53, 0xEB, 0xA6, + 0x39, 0x10, 0xFE, 0xD4, 0xEB, 0x1B, 0xAE, 0x38, + 0x31, 0x33, 0xBA, 0x68, 0xEE, 0xC7, 0x65, 0x76, + 0xFB, 0x49, 0x77, 0xD4, 0x19, 0xC4, 0xE6, 0xA7, + 0x05, 0xFE, 0x2A, 0xDA, 0x39, 0x99, 0x1A, 0x92, + 0xD2, 0xF0, 0x61, 0x97, 0xF6, 0x06, 0x6C, 0x88, + 0x7B, 0x6F, 0x60, 0xE6, 0x70, 0x08, 0xF0, 0xB4, + 0x6B, 0x39, 0x6F, 0x05, 0x41, 0x81, 0xF9, 0xBE, + 0x7A, 0x51, 0xC4, 0x75, 0xB0, 0x6A, 0x89, 0xA0, + 0xA6, 0x9A, 0x5B, 0xEE, 0x7D, 0x78, 0x17, 0x5F, + 0x9F, 0x3B, 0x7D, 0xDD, 0x8A, 0x9E, 0xAA, 0x1A, + 0xDA, 0x49, 0x08, 0xE9, 0xFD, 0x91, 0xA6, 0xFA, + 0xCE, 0xCF, 0x67, 0xDF, 0x0F, 0xC9, 0xD6, 0x38, + 0xD9, 0xD5, 0xD1, 0xC0, 0x76, 0x59, 0x42, 0x53, + 0xBF, 0x48, 0xE9, 0x11, 0x74, 0xC7, 0x11, 0xD8, + 0xE7, 0x8E, 0xD3, 0xC8, 0x25, 0xA1, 0x26, 0x50, + 0xBB, 0xB4, 0x35, 0xAF, 0xAF, 0x06, 0x23, 0x69, + 0x3E, 0x30, 0xFD, 0x7B, 0x34, 0x83, 0x07, 0xD0, + 0xF0, 0x0F, 0x6C, 0x9A, 0x13, 0x5D, 0xC2, 0x7B, + 0xDF, 0x6F, 0xDD, 0x8E, 0xF4, 0x30, 0x82, 0x05, + 0x41, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x05, 0x32, + 0x04, 0x82, 0x05, 0x2E, 0x30, 0x82, 0x05, 0x2A, + 0x30, 0x82, 0x05, 0x26, 0x06, 0x0B, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, + 0x02, 0xA0, 0x82, 0x04, 0xEE, 0x30, 0x82, 0x04, + 0xEA, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, + 0x0E, 0x04, 0x08, 0x74, 0xC0, 0x84, 0x8F, 0xC7, + 0x74, 0x5E, 0x21, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xC8, 0x1E, 0xF4, 0xE9, 0x07, 0x27, + 0x9E, 0x5A, 0xC9, 0x39, 0x1D, 0x37, 0x2C, 0x06, + 0x4B, 0x57, 0xEA, 0xC5, 0x42, 0x9A, 0x60, 0xD5, + 0x42, 0xB2, 0x34, 0x2D, 0xD3, 0x88, 0x7C, 0x78, + 0x87, 0xB6, 0xE9, 0x42, 0x44, 0x1F, 0x67, 0x32, + 0x92, 0x54, 0x22, 0xDA, 0xB2, 0x43, 0xE7, 0x40, + 0xBE, 0x1F, 0xAF, 0x3A, 0xCD, 0x2A, 0x9F, 0xD7, + 0x44, 0x5B, 0x37, 0x69, 0x85, 0xDF, 0xEB, 0x2A, + 0xB9, 0xE2, 0x92, 0x3B, 0xEA, 0xD5, 0x42, 0x53, + 0x95, 0x4A, 0xB0, 0x1B, 0xA5, 0xEF, 0xA6, 0x0D, + 0x29, 0xF4, 0x33, 0xFE, 0xD7, 0x49, 0x04, 0x1E, + 0x8C, 0xAD, 0x63, 0x1E, 0x79, 0x63, 0x74, 0x0C, + 0xE5, 0x5E, 0xA2, 0x2C, 0xBE, 0xB8, 0x90, 0xCE, + 0x06, 0x25, 0xBF, 0xD1, 0x5A, 0x50, 0xCF, 0x3B, + 0x52, 0xE2, 0xA7, 0xFF, 0x19, 0x02, 0xCF, 0xD0, + 0x9B, 0xD9, 0xF7, 0x28, 0x07, 0x38, 0x1F, 0xF2, + 0xAF, 0x44, 0x91, 0x3F, 0x0F, 0xB6, 0x6E, 0x8C, + 0xC0, 0x32, 0x92, 0xC0, 0xCD, 0x25, 0x98, 0x67, + 0xF1, 0x47, 0x52, 0x50, 0xF0, 0xA3, 0x7B, 0xE6, + 0x74, 0xDC, 0x72, 0x28, 0xC8, 0xAB, 0xB3, 0x31, + 0x7D, 0xA3, 0xF7, 0xC7, 0xD1, 0xE6, 0x99, 0xB4, + 0xB6, 0x5A, 0x3A, 0x4D, 0x83, 0x4F, 0xB8, 0xB5, + 0x86, 0xF8, 0x37, 0x7F, 0xA0, 0x16, 0x2F, 0x3C, + 0x62, 0x7A, 0xD4, 0x3A, 0xEB, 0xC2, 0xE8, 0x03, + 0x49, 0x17, 0x9E, 0xFB, 0xD7, 0xAF, 0x91, 0x32, + 0xFD, 0xEA, 0x4F, 0x64, 0xC6, 0x6E, 0x02, 0xEA, + 0xC4, 0xC8, 0x1F, 0x16, 0xC5, 0x4C, 0xFB, 0xC5, + 0x42, 0xF5, 0x85, 0x05, 0x92, 0x59, 0x4B, 0x31, + 0xE5, 0xE9, 0x69, 0xE7, 0x02, 0x98, 0x33, 0xBA, + 0x4C, 0x17, 0x09, 0xEF, 0x89, 0x20, 0xFA, 0x83, + 0x9F, 0xAE, 0x0E, 0x1B, 0x7D, 0x98, 0xB9, 0xF2, + 0x3C, 0x0F, 0xB7, 0x1C, 0x72, 0xDF, 0x17, 0x84, + 0x7F, 0x0A, 0xFD, 0x12, 0x3C, 0x6F, 0x68, 0x5D, + 0x45, 0xEB, 0xB8, 0xD6, 0x24, 0x65, 0x42, 0x75, + 0x5C, 0xC2, 0xF3, 0x3A, 0x6A, 0x4E, 0x51, 0x34, + 0x1B, 0xB6, 0x81, 0xB2, 0x8A, 0xEF, 0x28, 0xA4, + 0xC5, 0x88, 0x9A, 0x97, 0xE0, 0xEF, 0x31, 0x12, + 0x01, 0x7E, 0x1B, 0x43, 0x0F, 0x27, 0x80, 0x87, + 0x98, 0xC5, 0xD5, 0x83, 0xCB, 0x4B, 0xB7, 0x01, + 0x79, 0x60, 0xA1, 0x1A, 0x03, 0x05, 0xC6, 0x36, + 0x04, 0x31, 0x3C, 0x06, 0xDB, 0x08, 0xA8, 0xDA, + 0x8E, 0x32, 0x19, 0x91, 0xF1, 0x0D, 0x61, 0x6F, + 0xE4, 0xB2, 0x79, 0x8A, 0xDE, 0xF4, 0xF7, 0xFB, + 0x2C, 0x23, 0x5B, 0xD9, 0x64, 0x2F, 0xB7, 0xB3, + 0x8B, 0xCA, 0xB8, 0x8C, 0x1D, 0x3B, 0x49, 0x05, + 0x38, 0xA1, 0xE5, 0x8C, 0x1A, 0xDC, 0xA5, 0x61, + 0xFE, 0xF4, 0x2B, 0xDC, 0x77, 0x28, 0xF6, 0x19, + 0xE7, 0xB7, 0x8F, 0x4D, 0x27, 0x2D, 0xED, 0x8A, + 0x3F, 0x3D, 0xDC, 0x9F, 0xD1, 0x30, 0xFF, 0xD6, + 0xC3, 0xBE, 0x41, 0x25, 0xE3, 0xA5, 0x9B, 0x73, + 0xDF, 0x6A, 0xD9, 0xF9, 0x70, 0x84, 0x02, 0x4C, + 0x35, 0xD4, 0x3E, 0x05, 0x76, 0x3A, 0xDC, 0x6D, + 0x5A, 0x81, 0xB3, 0x94, 0xF7, 0x22, 0xF7, 0xDC, + 0xC1, 0x43, 0x31, 0x57, 0x5B, 0x42, 0x9A, 0x0B, + 0xF4, 0x95, 0x30, 0xA9, 0xBB, 0xD8, 0x06, 0xFB, + 0x1D, 0x6F, 0x9B, 0xC3, 0xBB, 0xF3, 0xBF, 0xFB, + 0xB4, 0x9F, 0x35, 0x64, 0x0A, 0x69, 0xB7, 0xD1, + 0x3E, 0xCA, 0x78, 0x07, 0x04, 0x03, 0x79, 0xD4, + 0xF3, 0xA8, 0xEC, 0x18, 0xDB, 0x03, 0x5E, 0x47, + 0xD7, 0xD0, 0x56, 0x2C, 0x74, 0x94, 0x86, 0x04, + 0x46, 0xB8, 0xD4, 0x35, 0x0A, 0x7B, 0xE6, 0x78, + 0xC4, 0x43, 0x3C, 0x56, 0xCC, 0x37, 0x8B, 0xFD, + 0xE8, 0xF4, 0x57, 0xEA, 0xAE, 0xCF, 0x36, 0x97, + 0x12, 0xAC, 0x39, 0xCF, 0x7C, 0xEF, 0x22, 0x67, + 0x01, 0xEC, 0xD8, 0x09, 0x49, 0x4E, 0xE3, 0x74, + 0xDD, 0x39, 0xE1, 0x39, 0xD7, 0x0C, 0x5F, 0x1B, + 0xCE, 0x69, 0xBC, 0x72, 0x44, 0x87, 0x64, 0x1C, + 0x08, 0x05, 0x93, 0x69, 0x6D, 0x7F, 0x90, 0x0A, + 0x2C, 0xCB, 0x8A, 0xBB, 0x7F, 0xE3, 0xE0, 0x80, + 0x31, 0xD0, 0x0A, 0x3A, 0x95, 0xFF, 0xF7, 0xB4, + 0x36, 0x38, 0x93, 0xE0, 0x0C, 0x11, 0x37, 0x12, + 0x06, 0xF6, 0xAD, 0xE9, 0xB1, 0x7A, 0x00, 0xF5, + 0xD2, 0x32, 0x6B, 0xD0, 0x27, 0xA5, 0x1B, 0x3D, + 0xE8, 0xDB, 0xCC, 0xA9, 0x1F, 0x1F, 0xB1, 0x99, + 0x3D, 0x7C, 0xB7, 0xCA, 0xDA, 0x27, 0x2C, 0x64, + 0x1C, 0x49, 0xB6, 0x87, 0x44, 0x06, 0x94, 0x9D, + 0xBC, 0x6B, 0x20, 0xA2, 0x68, 0x15, 0x1F, 0xE2, + 0xF2, 0xAD, 0x6D, 0x23, 0x2E, 0x2B, 0x74, 0xE2, + 0x5D, 0xE4, 0xB0, 0xC7, 0x84, 0xCB, 0x64, 0xBF, + 0xE0, 0xA8, 0x18, 0x83, 0xB4, 0xC9, 0xD9, 0x73, + 0xA8, 0xE6, 0xA9, 0x36, 0xD5, 0x63, 0x1E, 0x2C, + 0x2A, 0x55, 0x09, 0x77, 0x5E, 0xB3, 0x4B, 0xEA, + 0xB5, 0xD0, 0x14, 0x5F, 0xEB, 0x50, 0x7B, 0xAA, + 0xEF, 0x94, 0xBA, 0x2B, 0xD7, 0x8A, 0x07, 0xF1, + 0xF9, 0x5E, 0x12, 0x12, 0x21, 0x52, 0xE5, 0x0A, + 0x3E, 0xC0, 0xBC, 0x5D, 0x4C, 0xE2, 0x12, 0x7C, + 0x39, 0xF9, 0x16, 0x9D, 0xBD, 0x96, 0x83, 0x3B, + 0x7F, 0x3D, 0x6A, 0xEC, 0xF1, 0x25, 0xD2, 0xB0, + 0xB0, 0xEB, 0x20, 0x06, 0x07, 0xD6, 0xD9, 0x4C, + 0x07, 0x9A, 0x82, 0xC1, 0xFC, 0xF7, 0x66, 0x15, + 0xBD, 0x62, 0x65, 0xD8, 0x6C, 0xF6, 0x33, 0x7B, + 0x5A, 0x28, 0xEC, 0x90, 0xA1, 0x26, 0x9F, 0xC3, + 0x28, 0x4A, 0x64, 0x50, 0x5F, 0xCA, 0xE2, 0x6D, + 0xB8, 0x0F, 0xE2, 0x94, 0xB5, 0x8E, 0x1F, 0x8A, + 0x8F, 0x6B, 0xA6, 0x86, 0x1F, 0xEE, 0xDC, 0x24, + 0xB4, 0xB8, 0x25, 0xEC, 0x28, 0x2D, 0xF9, 0xCB, + 0x7D, 0x38, 0xFF, 0xC7, 0x74, 0x2E, 0xD3, 0x10, + 0xEC, 0x03, 0x31, 0xEE, 0x83, 0xE7, 0xA4, 0xF7, + 0xBA, 0x28, 0x21, 0xE0, 0x7F, 0xB4, 0xB7, 0xE1, + 0x7A, 0xF9, 0x2B, 0xB0, 0x2C, 0x3B, 0x80, 0x5F, + 0xE0, 0x5D, 0xB2, 0x7E, 0x59, 0xFF, 0x59, 0x07, + 0x58, 0x42, 0x57, 0xEE, 0x44, 0xF1, 0xB1, 0xAD, + 0xBA, 0xDE, 0xCB, 0x1D, 0x8A, 0x36, 0x67, 0xE8, + 0x45, 0xFF, 0x07, 0x8D, 0xEE, 0xA4, 0x51, 0x9C, + 0x4C, 0x83, 0x5D, 0x2E, 0x2F, 0xE1, 0x5B, 0x75, + 0xE8, 0x29, 0xCD, 0x0B, 0x07, 0x62, 0xE0, 0xC3, + 0x0D, 0x1D, 0xEA, 0xCF, 0xF0, 0x8A, 0x65, 0x27, + 0x70, 0x42, 0x9F, 0x26, 0x00, 0x15, 0x70, 0xC5, + 0x4A, 0xF6, 0x25, 0xD0, 0x40, 0x72, 0xE9, 0xC1, + 0x73, 0xFD, 0x48, 0x94, 0xA3, 0x8D, 0x66, 0x63, + 0x96, 0x4F, 0xF7, 0xEE, 0xFB, 0x4C, 0xC7, 0xB8, + 0x6B, 0xE9, 0x90, 0xE1, 0x2A, 0x66, 0x80, 0x99, + 0x3B, 0xB0, 0x1A, 0x6C, 0xF9, 0x0E, 0x72, 0xDA, + 0x8E, 0x4F, 0x46, 0xC2, 0x6A, 0x4B, 0x7A, 0x16, + 0xE5, 0x26, 0x0B, 0x5C, 0xD4, 0x47, 0x34, 0xE5, + 0x37, 0xBE, 0x68, 0x6C, 0xDA, 0xD3, 0x9B, 0x6F, + 0xAE, 0x51, 0x9C, 0x99, 0x0A, 0x5B, 0xF8, 0x37, + 0xBC, 0xDE, 0xFC, 0x93, 0xC5, 0xE7, 0x0F, 0xEF, + 0x0B, 0xA6, 0x07, 0xC2, 0xA6, 0xE6, 0xDA, 0x2D, + 0x1B, 0x49, 0xC9, 0xDE, 0x6B, 0x27, 0xDC, 0x00, + 0xEF, 0x23, 0x87, 0x0E, 0xEB, 0xD1, 0x48, 0x7D, + 0xB4, 0xF2, 0x58, 0xC6, 0x3C, 0xE2, 0x89, 0xBA, + 0xB0, 0x05, 0xAC, 0x94, 0x41, 0x9A, 0xA8, 0xFF, + 0x3E, 0xBC, 0x3A, 0x52, 0x9C, 0xF9, 0x7F, 0x07, + 0x8B, 0xB0, 0x2C, 0x71, 0x83, 0x7B, 0xCF, 0x2E, + 0x7F, 0x7C, 0x96, 0x65, 0xD9, 0x08, 0x17, 0xEC, + 0xFA, 0xDE, 0x4E, 0x40, 0x12, 0x26, 0x70, 0x71, + 0x65, 0xA5, 0xDC, 0x98, 0x47, 0xA3, 0xFC, 0xE0, + 0x9A, 0x16, 0xED, 0x45, 0x56, 0x72, 0x50, 0x05, + 0x28, 0x2C, 0x99, 0xEC, 0x20, 0x2E, 0x40, 0xC0, + 0x26, 0x69, 0xCD, 0x49, 0x45, 0x17, 0xA4, 0xA3, + 0x42, 0x0D, 0x14, 0x65, 0x87, 0x33, 0x8C, 0x92, + 0xC5, 0xC4, 0x61, 0xFD, 0xE8, 0x68, 0x56, 0x20, + 0x57, 0xF5, 0x8E, 0x5F, 0xCF, 0x7E, 0x97, 0xF6, + 0x49, 0x97, 0x0A, 0xFE, 0xD3, 0x60, 0x1A, 0x5B, + 0x0C, 0x75, 0xDD, 0x8E, 0x31, 0x78, 0x29, 0xA6, + 0xB1, 0x4D, 0xAA, 0xDF, 0x8A, 0xD1, 0xE6, 0x91, + 0xE3, 0x32, 0x3F, 0xEC, 0x8A, 0x1F, 0x0E, 0x35, + 0x07, 0x6E, 0x4B, 0x83, 0x3B, 0xE5, 0x67, 0x34, + 0x1F, 0x0C, 0x81, 0xD8, 0xD5, 0x25, 0x68, 0xE5, + 0x28, 0x1B, 0x5C, 0x81, 0x3E, 0xE3, 0x5C, 0xB4, + 0xB6, 0xBD, 0x62, 0x6A, 0x70, 0x33, 0xC2, 0xC5, + 0x75, 0x27, 0xF4, 0x30, 0xE1, 0x1D, 0xC1, 0x4C, + 0xC5, 0x02, 0x12, 0x46, 0xAC, 0xEC, 0xF9, 0xE8, + 0xE7, 0x58, 0x24, 0x11, 0xB1, 0xF3, 0xB7, 0x8C, + 0x3C, 0xA4, 0x0A, 0x94, 0xA6, 0x7C, 0x68, 0x54, + 0x5B, 0xB9, 0x4D, 0x57, 0x9C, 0xE7, 0x28, 0x09, + 0x6B, 0x89, 0x26, 0x5D, 0xE7, 0x50, 0xA9, 0x95, + 0x90, 0x91, 0x8E, 0x00, 0x59, 0xF8, 0x3A, 0x70, + 0xAF, 0x48, 0x2E, 0xE8, 0xC4, 0x34, 0x8C, 0xF4, + 0x5F, 0x7F, 0xCB, 0x07, 0xAA, 0xF0, 0xD9, 0xFB, + 0x5C, 0x32, 0x90, 0x22, 0x1A, 0xD2, 0x1A, 0xCF, + 0x92, 0x06, 0x02, 0xCF, 0x10, 0x18, 0x7B, 0x93, + 0xCC, 0x07, 0x4A, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xD1, 0xDE, + 0x23, 0x16, 0x9F, 0x6E, 0xF4, 0x42, 0x21, 0x23, + 0xE1, 0x11, 0xAA, 0xC8, 0x7C, 0x60, 0x4A, 0x78, + 0x9D, 0x24, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, + 0x00, 0x04, 0x14, 0xD6, 0x4A, 0xBB, 0x75, 0xB1, + 0xF9, 0x9E, 0xD3, 0x58, 0x6D, 0xD1, 0x74, 0x9F, + 0x00, 0x8A, 0xF2, 0xC8, 0xAA, 0x52, 0x4D, 0x04, + 0x08, 0x77, 0x46, 0xE7, 0xBA, 0x25, 0x4B, 0xDA, + 0x41, 0x02, 0x02, 0x08, 0x00] +}; + +const WPA_EAP_CLIENT_LIST = [ + { + ssid: 'WPA-EAP-TTLS', + keyManagement: 'WPA-EAP', + eap: 'TTLS', + identity: EAP_USERNAME, + password: EAP_PASSWORD, + serverCertificate: CLIENT_PKCS12_CERT.nickname, + phase2: 'MSCHAPV2' + } +]; + +/** + * Convert the given MozWifiNetwork object array to testAssociate chain. + * + * @param aNetworks + * An array of MozWifiNetwork which we want to convert. + * + * @return A promise chain which "then"s testAssociate accordingly. + */ +function convertToTestAssociateChain(aNetworks) { + let chain = Promise.resolve(); + + aNetworks.forEach(function (aNetwork) { + network = new window.MozWifiNetwork(aNetwork); + chain = chain.then(() => gTestSuite.testAssociate(network)); + }); + + return chain; +} + +gTestSuite.doTestWithCertificate( + new Blob([new Uint8Array(CLIENT_PKCS12_CERT.content)]), + CLIENT_PKCS12_CERT.password, + CLIENT_PKCS12_CERT.nickname, + CLIENT_PKCS12_CERT.usage, + function() { + return gTestSuite.ensureWifiEnabled(true) + // Load required server files. + .then(() => gTestSuite.writeFile(SERVER_EAP_USER_CONF.path, SERVER_EAP_USER_CONF.content)) + .then(() => gTestSuite.writeFile(CA_CERT.path, CA_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_CERT.path, SERVER_CERT.content)) + .then(() => gTestSuite.writeFile(SERVER_KEY.path, SERVER_KEY.content)) + // Start AP. + .then(() => gTestSuite.startHostapds(WPA_EAP_AP_LIST)) + // Scan test. + .then(() => gTestSuite.testWifiScanWithRetry(SCAN_RETRY_CNT, WPA_EAP_AP_LIST)) + // Associate test. + .then(() => convertToTestAssociateChain(WPA_EAP_CLIENT_LIST)) + // Tear down. + .then(gTestSuite.killAllHostapd) +}); diff --git a/dom/wifi/test/marionette/test_wifi_auto_connect.js b/dom/wifi/test/marionette/test_wifi_auto_connect.js index fef0289037..7add9f03dc 100644 --- a/dom/wifi/test/marionette/test_wifi_auto_connect.js +++ b/dom/wifi/test/marionette/test_wifi_auto_connect.js @@ -4,15 +4,41 @@ MARIONETTE_TIMEOUT = 60000; MARIONETTE_HEAD_JS = 'head.js'; -gTestSuite.doTest(function() { +const TESTING_HOSTAPD = [{ ssid: 'ap0' }]; + +gTestSuite.doTestWithoutStockAp(function() { let firstNetwork; return gTestSuite.ensureWifiEnabled(true) + // Start custom hostapd for testing. + .then(() => gTestSuite.startHostapds(TESTING_HOSTAPD)) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', TESTING_HOSTAPD.length)) + + // Request the first scan. .then(gTestSuite.requestWifiScan) .then(function(networks) { firstNetwork = networks[0]; return gTestSuite.testAssociate(firstNetwork); }) + + // Note that due to Bug 1168285, we need to re-start testing hostapd + // after wifi has been re-enabled. + + // Disable wifi and kill running hostapd. .then(() => gTestSuite.requestWifiEnabled(false)) + .then(gTestSuite.killAllHostapd) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0)) + + // Re-enable wifi. .then(() => gTestSuite.requestWifiEnabled(true)) - .then(() => gTestSuite.waitForConnected(firstNetwork)); + + // Restart hostapd. + .then(() => gTestSuite.startHostapds(TESTING_HOSTAPD)) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', TESTING_HOSTAPD.length)) + + // Wait for connection automatically. + .then(() => gTestSuite.waitForConnected(firstNetwork)) + + // Kill running hostapd. + .then(gTestSuite.killAllHostapd) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0)) }); diff --git a/dom/wifi/test/marionette/test_wifi_manage_pkcs12_certificate.js b/dom/wifi/test/marionette/test_wifi_manage_pkcs12_certificate.js new file mode 100644 index 0000000000..f85ef00c94 --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_manage_pkcs12_certificate.js @@ -0,0 +1,338 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +// Binary form of test certificate. +var testCertInfo = { + nickname: 'Test Certificate', + password: '12345678', + usage: ['UserCert', 'ServerCert'], + blob: [0x30, 0x82, 0x09, 0xF1, 0x02, 0x01, 0x03, 0x30, + 0x82, 0x09, 0xB7, 0x06, 0x09, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, + 0x09, 0xA8, 0x04, 0x82, 0x09, 0xA4, 0x30, 0x82, + 0x09, 0xA0, 0x30, 0x82, 0x06, 0x9F, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, + 0x06, 0xA0, 0x82, 0x06, 0x90, 0x30, 0x82, 0x06, + 0x8C, 0x02, 0x01, 0x00, 0x30, 0x82, 0x06, 0x85, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x01, 0x30, 0x1C, 0x06, 0x0A, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, + 0x06, 0x30, 0x0E, 0x04, 0x08, 0x13, 0xB5, 0x2F, + 0x5A, 0xB9, 0x49, 0xE6, 0x0B, 0x02, 0x02, 0x08, + 0x00, 0x80, 0x82, 0x06, 0x58, 0x35, 0x77, 0x6B, + 0xBF, 0x5C, 0x06, 0x09, 0xD8, 0xF0, 0x36, 0x06, + 0x69, 0x8D, 0xA2, 0x86, 0xCF, 0x6B, 0x73, 0x86, + 0x14, 0xFA, 0x51, 0x9A, 0x87, 0x73, 0x29, 0x71, + 0xC5, 0xB1, 0x4F, 0xFB, 0xEC, 0x64, 0x84, 0x20, + 0xFC, 0x06, 0x4A, 0x93, 0x74, 0x01, 0xFB, 0xEB, + 0x1F, 0xDC, 0xF8, 0xF7, 0xBB, 0xDC, 0x42, 0xA1, + 0x4A, 0x71, 0xDE, 0x08, 0x33, 0x7A, 0xCA, 0xD3, + 0xD8, 0x40, 0x24, 0x47, 0xAE, 0x41, 0x42, 0x8E, + 0xC8, 0x4E, 0xBE, 0x8B, 0xB3, 0xE5, 0x77, 0xAC, + 0xBD, 0x98, 0x0C, 0x0E, 0x53, 0xBE, 0x38, 0xB7, + 0xEA, 0xD2, 0x29, 0x35, 0xD2, 0xC4, 0xF4, 0xC7, + 0xD8, 0xB1, 0x73, 0x2A, 0x13, 0x11, 0x65, 0xF7, + 0x0C, 0x8B, 0xC0, 0x43, 0xFB, 0x31, 0x6C, 0xD2, + 0xE4, 0x43, 0x85, 0x51, 0x16, 0xBF, 0x35, 0xB5, + 0x05, 0x6B, 0x86, 0x11, 0xEA, 0x78, 0x64, 0x9F, + 0x42, 0x29, 0xB9, 0x79, 0xAF, 0xB0, 0x7C, 0xBF, + 0xC0, 0x89, 0xAD, 0xC7, 0x37, 0xD2, 0x30, 0x8C, + 0xDC, 0xF6, 0x77, 0x5E, 0x1F, 0x26, 0x28, 0x8F, + 0xAC, 0x19, 0x6C, 0xA0, 0x15, 0xC7, 0x12, 0xA3, + 0x0A, 0xD5, 0xC6, 0x15, 0x60, 0x58, 0x16, 0xB8, + 0x30, 0x12, 0x3C, 0x78, 0x3C, 0x93, 0x23, 0xA1, + 0x56, 0x75, 0x0B, 0x77, 0xAA, 0x0B, 0x0B, 0x2B, + 0x91, 0xB6, 0x41, 0xAB, 0xF5, 0x09, 0x4C, 0x1E, + 0x36, 0xC0, 0x88, 0xC3, 0x08, 0xF2, 0x65, 0xCB, + 0x58, 0x8F, 0x94, 0xB4, 0xB4, 0x05, 0xCC, 0x44, + 0x49, 0x73, 0x1B, 0x25, 0x6F, 0x5D, 0x83, 0xBD, + 0xF0, 0x70, 0xD0, 0xE8, 0x0D, 0x18, 0x2E, 0x44, + 0xD7, 0x89, 0x64, 0x6A, 0xED, 0x23, 0x30, 0xDF, + 0xAD, 0x84, 0x3B, 0x74, 0x2C, 0x0D, 0x2B, 0x51, + 0x84, 0xA2, 0xA4, 0x9E, 0x42, 0xC3, 0x81, 0x69, + 0xFA, 0x56, 0x76, 0x9F, 0xD9, 0x02, 0x64, 0x04, + 0xFE, 0xF0, 0xD9, 0x01, 0xBC, 0xE2, 0xC9, 0xDD, + 0x88, 0xAC, 0xFA, 0x24, 0x7E, 0xB1, 0xF8, 0x39, + 0x27, 0xA2, 0xEB, 0xE4, 0x53, 0xC1, 0xF3, 0xFE, + 0x2D, 0x9A, 0x49, 0x73, 0xFF, 0x7C, 0x8E, 0x39, + 0xF7, 0x15, 0x27, 0xB3, 0x47, 0x48, 0x92, 0x8C, + 0x57, 0x60, 0x9C, 0x97, 0xBA, 0x80, 0xD2, 0x25, + 0x80, 0x94, 0xCE, 0x2C, 0x0C, 0x00, 0x44, 0x8C, + 0x8C, 0x37, 0x82, 0x5D, 0x5F, 0x62, 0x8B, 0x05, + 0x6F, 0xB0, 0x07, 0x34, 0xF9, 0xC3, 0xA1, 0x34, + 0x3D, 0xE4, 0x90, 0xB0, 0x03, 0x59, 0x97, 0x6E, + 0xFB, 0xF2, 0x92, 0xE5, 0xB5, 0x30, 0x7C, 0x0D, + 0x3B, 0x8F, 0x90, 0x8E, 0x04, 0x47, 0x01, 0x0E, + 0x88, 0x50, 0x4A, 0x88, 0xA0, 0xFF, 0xB7, 0x9E, + 0x2B, 0x2C, 0x98, 0xD0, 0x3E, 0x16, 0x35, 0x5B, + 0xD5, 0xEA, 0x54, 0x86, 0xE0, 0xFB, 0x9F, 0x2F, + 0x62, 0x89, 0x36, 0x36, 0x9D, 0x6E, 0x62, 0xCB, + 0xC8, 0x6C, 0x62, 0x34, 0x8F, 0x66, 0x07, 0x62, + 0xA7, 0x00, 0x90, 0x31, 0xFA, 0x5D, 0xDD, 0x12, + 0x33, 0x69, 0xD0, 0x74, 0x0E, 0x0B, 0x42, 0x9A, + 0xF3, 0x40, 0x7E, 0x3E, 0x48, 0x1D, 0xF2, 0x5C, + 0x71, 0x0B, 0x78, 0x7E, 0xD5, 0x15, 0xA4, 0x16, + 0x1E, 0xBD, 0x71, 0x18, 0x87, 0x3A, 0xC9, 0xE3, + 0x45, 0xEE, 0x70, 0xA2, 0x4C, 0x50, 0xF5, 0x16, + 0x5C, 0xF8, 0x76, 0xE6, 0x9F, 0x8D, 0x86, 0x41, + 0x7E, 0xF8, 0x60, 0x3D, 0x75, 0x6D, 0x55, 0x96, + 0x9E, 0x43, 0x48, 0x82, 0xF7, 0xB6, 0xAC, 0x98, + 0x6F, 0x10, 0xAA, 0x20, 0x64, 0xD0, 0x7C, 0x25, + 0x24, 0xF7, 0xD8, 0xA4, 0xCC, 0x2D, 0xBF, 0x85, + 0x62, 0x6C, 0x4F, 0xFF, 0x9D, 0x71, 0x04, 0x98, + 0x61, 0xB0, 0xBC, 0x31, 0xC1, 0xE9, 0xB8, 0x29, + 0xA5, 0xEB, 0xD1, 0x1D, 0x65, 0x8E, 0xAE, 0x38, + 0x55, 0x65, 0x22, 0xC7, 0xFD, 0x7E, 0xF2, 0x6A, + 0xB6, 0xB1, 0x51, 0x37, 0x4B, 0x05, 0x8F, 0xA7, + 0x2D, 0x3F, 0x5C, 0x04, 0x2B, 0xBA, 0x2C, 0x37, + 0xCA, 0xDE, 0xD5, 0x3E, 0xA0, 0xA5, 0x86, 0x59, + 0xA7, 0xD7, 0x38, 0x07, 0xFB, 0x79, 0xF6, 0x2D, + 0xE1, 0xAA, 0x7C, 0xD1, 0x91, 0xBE, 0x39, 0xDF, + 0x53, 0x3C, 0xD1, 0x44, 0x2C, 0xF9, 0x12, 0x7D, + 0xB1, 0xCD, 0xF3, 0x35, 0x1F, 0x85, 0xA6, 0x64, + 0x2F, 0xFD, 0x28, 0xF2, 0x85, 0xA8, 0xA7, 0x1F, + 0x7F, 0xD9, 0x79, 0x30, 0x9B, 0xFC, 0x69, 0x3A, + 0x9B, 0x1F, 0x55, 0x70, 0xC9, 0x60, 0x82, 0x3D, + 0xE9, 0x5A, 0x37, 0x5F, 0x8C, 0xBD, 0x19, 0x5D, + 0xCC, 0x1C, 0xBE, 0x26, 0x4A, 0xEA, 0x8B, 0x39, + 0xCE, 0x0D, 0xBD, 0x63, 0x05, 0x98, 0x75, 0xAB, + 0x08, 0x79, 0x90, 0xC7, 0x20, 0xFF, 0xE4, 0x0D, + 0xB1, 0xA0, 0x92, 0x2B, 0x0C, 0x4B, 0x0C, 0xDC, + 0xB9, 0x72, 0x2A, 0xA4, 0xCC, 0xA6, 0x32, 0xA3, + 0x57, 0x82, 0xB4, 0xB9, 0x0F, 0x81, 0xC5, 0xD9, + 0x7C, 0xB8, 0x0F, 0x7D, 0xEA, 0x5D, 0xD3, 0xC4, + 0x2F, 0x31, 0x79, 0x11, 0xAD, 0x36, 0x56, 0x1F, + 0xFA, 0xE3, 0xCE, 0xD2, 0x29, 0x23, 0xE8, 0x2C, + 0xDF, 0x7D, 0x94, 0x28, 0x28, 0x9A, 0x0E, 0x64, + 0xFC, 0x07, 0x11, 0x96, 0x06, 0x1A, 0x39, 0xCD, + 0x04, 0x37, 0x37, 0xDB, 0xFE, 0x68, 0x37, 0xF5, + 0x59, 0x54, 0xBC, 0xEF, 0xDB, 0x0C, 0x80, 0xCD, + 0xD3, 0x46, 0xA8, 0xA2, 0xBE, 0xE0, 0x63, 0x80, + 0xA1, 0x5F, 0x5D, 0xF1, 0xFB, 0x96, 0x8C, 0x06, + 0x38, 0xB6, 0xCB, 0x70, 0xB0, 0xFB, 0xD3, 0x26, + 0xB3, 0x8B, 0xC6, 0x85, 0x34, 0xB7, 0xAB, 0x5F, + 0x7E, 0xC6, 0xAA, 0x79, 0x5B, 0x48, 0x11, 0x65, + 0x9E, 0x2A, 0xCD, 0x6A, 0xF0, 0xB2, 0x93, 0xF5, + 0x2B, 0x88, 0x45, 0xB7, 0xC9, 0xBE, 0x1A, 0x72, + 0x60, 0x62, 0xA4, 0xA5, 0x3B, 0xC2, 0x1C, 0xC6, + 0x21, 0x09, 0xA9, 0x40, 0xF6, 0x58, 0x2B, 0xE5, + 0x70, 0xDC, 0xFC, 0x47, 0x3B, 0x08, 0xEE, 0xA9, + 0x94, 0x26, 0x43, 0xFE, 0xA7, 0x75, 0xD6, 0x4E, + 0x52, 0xF6, 0x46, 0xD1, 0x80, 0xEB, 0x3B, 0x8E, + 0xBE, 0x54, 0x4F, 0xBD, 0x42, 0x0E, 0x41, 0xF9, + 0x36, 0x7D, 0xB6, 0x7F, 0x99, 0x20, 0xC9, 0x63, + 0xE7, 0x93, 0x02, 0x62, 0x59, 0x94, 0xCB, 0xC6, + 0x62, 0xA9, 0x26, 0xE1, 0x1E, 0x03, 0x5A, 0x41, + 0x2F, 0x43, 0x28, 0x75, 0xB7, 0x0C, 0x02, 0x9C, + 0x1E, 0xE0, 0x40, 0xB3, 0xE2, 0x9A, 0xED, 0xC6, + 0x20, 0x49, 0xEC, 0xDD, 0xC5, 0x64, 0x95, 0x83, + 0x51, 0xAE, 0x46, 0x9D, 0x70, 0x17, 0xC6, 0x47, + 0xD3, 0x82, 0xCC, 0x6A, 0x5D, 0x93, 0xB2, 0x85, + 0x5B, 0x25, 0x05, 0xE7, 0x26, 0x2E, 0xD3, 0xDA, + 0x1C, 0xD9, 0x06, 0xB6, 0x16, 0x69, 0x8C, 0x7F, + 0xC8, 0xCF, 0x95, 0x18, 0xB5, 0x98, 0xC0, 0x42, + 0x61, 0xDE, 0x77, 0x41, 0x3A, 0xF6, 0xE1, 0xB0, + 0xE8, 0x64, 0x4A, 0xC2, 0x58, 0xBE, 0x27, 0xC6, + 0x9B, 0x0D, 0x47, 0x1A, 0x09, 0x56, 0x7D, 0x2B, + 0x19, 0x01, 0x88, 0xC7, 0xFB, 0x1E, 0xCF, 0x5E, + 0xF6, 0xB0, 0x82, 0x87, 0xC0, 0xBE, 0xD6, 0xA5, + 0xC3, 0xAC, 0x3A, 0x97, 0x88, 0x25, 0x81, 0xAA, + 0x3A, 0xCE, 0x66, 0x88, 0x0F, 0xC3, 0x02, 0x50, + 0x1C, 0xC3, 0x2B, 0xBC, 0x53, 0x52, 0xFE, 0xD2, + 0x3F, 0x50, 0xC8, 0xB2, 0x19, 0x0A, 0x14, 0xB1, + 0x73, 0x18, 0xB4, 0xDF, 0xBD, 0xED, 0x43, 0xC5, + 0x91, 0xF4, 0x91, 0xBA, 0x7E, 0xB0, 0x7E, 0xA9, + 0x43, 0x67, 0x06, 0xCF, 0x51, 0xC1, 0xBF, 0x63, + 0x7E, 0x91, 0x76, 0xFF, 0x4F, 0x48, 0x91, 0xCF, + 0xDF, 0x01, 0x4D, 0x7E, 0x81, 0x22, 0xFB, 0x79, + 0xFC, 0x1D, 0xE3, 0xA7, 0x45, 0x16, 0xFB, 0xF2, + 0x83, 0xC7, 0xAE, 0xC6, 0xC5, 0x81, 0xDB, 0xA2, + 0x9F, 0x2F, 0xEA, 0xE6, 0x8E, 0x12, 0x8D, 0x43, + 0x14, 0x26, 0x25, 0x0E, 0xB4, 0x18, 0xE8, 0x41, + 0x84, 0xA3, 0x04, 0xDF, 0x97, 0xFF, 0xAA, 0x45, + 0xEC, 0x18, 0xAA, 0xB1, 0xFC, 0xDC, 0xB9, 0xAB, + 0xEE, 0xD1, 0xC4, 0x9E, 0x42, 0x3F, 0x5B, 0x8F, + 0x9F, 0x22, 0xAF, 0xCC, 0x6F, 0xA0, 0x41, 0x41, + 0xCB, 0xD3, 0xAC, 0x96, 0x20, 0xF1, 0x63, 0x56, + 0x65, 0xCE, 0x83, 0xC6, 0x62, 0x04, 0x85, 0x16, + 0x7F, 0x4E, 0xFB, 0xA0, 0x68, 0x11, 0x85, 0x5B, + 0x51, 0xB6, 0x9F, 0xA2, 0xF5, 0xA1, 0xCF, 0x01, + 0x9A, 0x80, 0x68, 0xC3, 0xE9, 0x7F, 0x9E, 0x2E, + 0x83, 0x84, 0xDC, 0x3C, 0x35, 0xCF, 0x24, 0xBF, + 0xF5, 0x00, 0x91, 0x45, 0x14, 0x65, 0xE0, 0xC5, + 0x75, 0xDA, 0xEF, 0x14, 0xBD, 0xDB, 0x28, 0x8D, + 0x30, 0x96, 0xC9, 0xFE, 0xA8, 0x49, 0x76, 0xC9, + 0xED, 0x90, 0x4C, 0x2E, 0xF1, 0x14, 0x2C, 0xF7, + 0x13, 0x7C, 0xF1, 0xCC, 0x67, 0xA5, 0x11, 0x55, + 0xBD, 0x66, 0x13, 0x8A, 0x76, 0xF9, 0xAC, 0xC9, + 0x51, 0x8A, 0xBB, 0x5D, 0x29, 0xEF, 0xF6, 0x37, + 0xA0, 0x3E, 0x99, 0x77, 0x6B, 0xE5, 0xCD, 0x06, + 0xAC, 0x57, 0x07, 0x37, 0x44, 0x3D, 0x5D, 0xD7, + 0xB6, 0x5C, 0xCB, 0x77, 0xD0, 0x4C, 0x28, 0x9D, + 0x12, 0x69, 0x5A, 0x68, 0xD1, 0x15, 0x30, 0xC4, + 0x30, 0xD2, 0x20, 0xDF, 0xD5, 0x73, 0x9F, 0x83, + 0xE9, 0x4C, 0x55, 0xF5, 0xAF, 0xAA, 0x37, 0xF8, + 0x28, 0xB6, 0x3F, 0x99, 0x4B, 0x15, 0x1E, 0x40, + 0xAB, 0x4F, 0x58, 0x3D, 0x3B, 0x81, 0x7D, 0x62, + 0x28, 0x6E, 0x73, 0x58, 0x50, 0x36, 0x49, 0x01, + 0xF7, 0x04, 0x3A, 0x23, 0x28, 0xDA, 0x15, 0xC5, + 0xE3, 0xF6, 0x6F, 0xE1, 0x79, 0x07, 0xFB, 0xAA, + 0xFF, 0x44, 0x48, 0x53, 0x9E, 0x7F, 0x8D, 0x89, + 0x88, 0x1A, 0x9A, 0xF9, 0x47, 0x58, 0x20, 0xBB, + 0x79, 0x4A, 0x2A, 0x14, 0x03, 0x9B, 0x65, 0x4C, + 0x67, 0x02, 0x02, 0xFE, 0xEB, 0xCD, 0xCB, 0x84, + 0xF5, 0xCE, 0x32, 0x59, 0xBC, 0xEA, 0xEC, 0xB1, + 0x3C, 0x22, 0xCF, 0x9D, 0xB0, 0x34, 0x6D, 0xE6, + 0x5A, 0x37, 0xC0, 0x22, 0xAA, 0xF3, 0xB5, 0x71, + 0x90, 0x21, 0xE0, 0xB6, 0x19, 0xE9, 0xB3, 0x10, + 0xCE, 0x5B, 0xF9, 0xD4, 0x25, 0x30, 0x7D, 0xF6, + 0x7D, 0xB6, 0x16, 0xFC, 0x20, 0x3C, 0x2F, 0x96, + 0xD5, 0x79, 0x90, 0x88, 0x24, 0x5D, 0x46, 0x64, + 0x99, 0xC1, 0xF8, 0x7F, 0x96, 0xA7, 0xB5, 0xA9, + 0x47, 0xA3, 0x14, 0xED, 0x93, 0xED, 0x30, 0x56, + 0x58, 0xA5, 0xD4, 0x54, 0x2A, 0xF3, 0x89, 0x27, + 0x7C, 0x55, 0x41, 0x11, 0x27, 0x9D, 0xF6, 0x4D, + 0xA6, 0xB1, 0x00, 0xE0, 0xB0, 0xF6, 0x1E, 0xAB, + 0x20, 0x1F, 0xAE, 0x8A, 0x82, 0xA7, 0x49, 0xFC, + 0xBB, 0x66, 0xAC, 0x97, 0x95, 0x49, 0x29, 0xCB, + 0x6F, 0xF4, 0xC1, 0xB7, 0x6B, 0xF9, 0x8C, 0x25, + 0xC6, 0xF0, 0xB5, 0x81, 0xB0, 0xA2, 0x4D, 0xCC, + 0x2E, 0xD0, 0x13, 0x5F, 0x96, 0x3F, 0xCD, 0xD0, + 0x52, 0xD1, 0xFE, 0xF9, 0xC2, 0x7E, 0x9D, 0xAB, + 0xCB, 0x95, 0x0F, 0x27, 0x01, 0x9E, 0x23, 0x6B, + 0x19, 0xFF, 0x52, 0x55, 0x71, 0x0A, 0xD4, 0xBB, + 0x43, 0x65, 0x29, 0x66, 0xBE, 0x2D, 0x6C, 0xE3, + 0x2A, 0x7C, 0xB4, 0x02, 0x32, 0x59, 0x94, 0x80, + 0x14, 0xE7, 0x62, 0xE4, 0xCE, 0xB0, 0xCA, 0xCA, + 0x37, 0xD7, 0x0C, 0x68, 0x29, 0xE2, 0x92, 0xE1, + 0xEB, 0x91, 0xE5, 0xA1, 0x0C, 0xFC, 0x55, 0xCB, + 0x56, 0xB3, 0x96, 0xFB, 0x64, 0xD9, 0x53, 0x8E, + 0x82, 0x2B, 0xDF, 0x7F, 0xCB, 0x2A, 0xF6, 0x3C, + 0xA7, 0x89, 0x52, 0x13, 0x2C, 0x6A, 0x93, 0xA2, + 0x74, 0xF5, 0x91, 0x00, 0x17, 0xAA, 0x74, 0x45, + 0x63, 0x5A, 0xE5, 0xC3, 0x16, 0xFC, 0x0E, 0xF7, + 0xF3, 0xA4, 0x55, 0x8A, 0xA2, 0x60, 0x24, 0x57, + 0x25, 0x2C, 0x94, 0xE0, 0xF5, 0x32, 0x54, 0x4A, + 0x2D, 0x63, 0x5F, 0xD8, 0x35, 0x96, 0xBD, 0xFE, + 0x90, 0x33, 0x17, 0xF6, 0xB5, 0x81, 0x02, 0xFA, + 0x5C, 0x94, 0x3A, 0xBE, 0x22, 0xB9, 0xFC, 0x3E, + 0x09, 0xE4, 0x76, 0xD7, 0x03, 0x38, 0x38, 0xC2, + 0xC2, 0x0D, 0x66, 0x3C, 0xD0, 0x91, 0x5C, 0xF4, + 0x0E, 0xC2, 0xDE, 0x46, 0x90, 0x2E, 0xF5, 0x22, + 0xA9, 0x3D, 0x15, 0x20, 0x5F, 0x17, 0x10, 0x5A, + 0x54, 0x63, 0x93, 0x7B, 0xC3, 0x00, 0x3D, 0x42, + 0x73, 0xF1, 0xAD, 0xC1, 0xDE, 0x76, 0x18, 0x9C, + 0x68, 0x17, 0xBF, 0x3B, 0xE0, 0x30, 0x82, 0x02, + 0xF9, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x82, 0x02, 0xEA, + 0x04, 0x82, 0x02, 0xE6, 0x30, 0x82, 0x02, 0xE2, + 0x30, 0x82, 0x02, 0xDE, 0x06, 0x0B, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, + 0x02, 0xA0, 0x82, 0x02, 0xA6, 0x30, 0x82, 0x02, + 0xA2, 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, + 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, + 0x0E, 0x04, 0x08, 0x34, 0x37, 0x27, 0x5F, 0xE8, + 0xD6, 0x00, 0x0D, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x02, 0x80, 0xC0, 0xE6, 0xB1, 0x63, 0x73, + 0xFC, 0xBF, 0x50, 0xFB, 0x54, 0xCF, 0x67, 0x16, + 0xF8, 0x28, 0x48, 0x13, 0x7F, 0xF2, 0xBD, 0x66, + 0x70, 0xC7, 0xF6, 0x01, 0xD0, 0x58, 0xF4, 0xA4, + 0xD9, 0x45, 0xE2, 0x63, 0x92, 0x7F, 0x78, 0x2B, + 0xB6, 0xDB, 0x16, 0x44, 0x1D, 0x11, 0xCB, 0xC3, + 0x20, 0xA9, 0x8A, 0x96, 0x13, 0xB8, 0x6E, 0xF3, + 0xDA, 0x46, 0x05, 0x2C, 0xF9, 0x67, 0xBB, 0x05, + 0x88, 0xC0, 0xC8, 0x60, 0x09, 0xA3, 0x82, 0x27, + 0x33, 0xEB, 0xEE, 0x43, 0x98, 0xE9, 0xE2, 0x24, + 0xA8, 0x06, 0xD5, 0xFF, 0xF5, 0xC0, 0x79, 0x4B, + 0x06, 0x40, 0xE6, 0x28, 0xC6, 0x6E, 0x4E, 0x03, + 0xCC, 0x9B, 0xB6, 0xBD, 0xB6, 0x81, 0x88, 0x5C, + 0x34, 0x6B, 0x8B, 0x15, 0x23, 0x75, 0x21, 0xAC, + 0x79, 0xFD, 0xDB, 0x80, 0x1D, 0x20, 0x84, 0xF1, + 0x47, 0xAF, 0x7B, 0x40, 0x6C, 0xD2, 0x64, 0x52, + 0x11, 0x1B, 0x01, 0x1E, 0xB5, 0xA9, 0x4B, 0xC4, + 0x51, 0x54, 0x40, 0xE2, 0xC8, 0xEB, 0x20, 0x48, + 0x2D, 0x40, 0xF8, 0xC6, 0x58, 0x5A, 0xE3, 0x34, + 0xD8, 0x79, 0x04, 0xD7, 0xD6, 0x07, 0xF2, 0x12, + 0x66, 0xC8, 0x31, 0x37, 0x71, 0x60, 0xF4, 0x75, + 0xDC, 0x60, 0x54, 0x19, 0x6A, 0x75, 0x56, 0xC5, + 0xA9, 0x67, 0x4A, 0x03, 0x7A, 0xFD, 0x12, 0x59, + 0x2B, 0x74, 0xE6, 0xA5, 0xE2, 0xF8, 0xBB, 0x1E, + 0x76, 0x96, 0xD4, 0xD4, 0x3F, 0x8B, 0xAD, 0x90, + 0xAF, 0x04, 0x41, 0xDB, 0xD8, 0xCC, 0x2D, 0x37, + 0x06, 0x20, 0x9B, 0xE7, 0x98, 0x87, 0x12, 0xAC, + 0x70, 0xC9, 0xF4, 0x1C, 0x28, 0xFB, 0x2C, 0x9E, + 0x18, 0xE1, 0x6D, 0x79, 0x34, 0xBC, 0xAC, 0xCB, + 0x75, 0x92, 0x7E, 0x8E, 0x7C, 0xA9, 0x0B, 0x86, + 0x4A, 0x88, 0xFB, 0xE8, 0xBE, 0x6A, 0x32, 0xEF, + 0x58, 0xCC, 0x4C, 0x89, 0x50, 0xEF, 0xDF, 0xE0, + 0xDD, 0x35, 0x07, 0x8C, 0x01, 0x8B, 0x57, 0x38, + 0xB5, 0x64, 0xBB, 0x0A, 0xC2, 0xD8, 0xAB, 0xC5, + 0x45, 0xA6, 0x83, 0xBF, 0xA6, 0xA2, 0xCC, 0x06, + 0x64, 0xBE, 0x84, 0x04, 0x55, 0x8E, 0xF4, 0x4C, + 0xB5, 0xBC, 0xE5, 0x97, 0x2B, 0x3C, 0x42, 0x44, + 0x91, 0x9B, 0xB2, 0x65, 0x70, 0x02, 0xC5, 0xB7, + 0x71, 0xB3, 0xF0, 0xAA, 0x46, 0x4F, 0x42, 0x40, + 0x53, 0x65, 0x89, 0xA5, 0x6C, 0xBC, 0xB5, 0x6C, + 0x0C, 0x3B, 0x50, 0x46, 0x67, 0xFA, 0x14, 0x68, + 0x01, 0xE7, 0xA6, 0xD4, 0xB5, 0xD0, 0x82, 0x44, + 0x92, 0x2C, 0xE3, 0x43, 0x5D, 0x34, 0x7C, 0x04, + 0xA3, 0x4D, 0x2F, 0x5A, 0x75, 0xE7, 0x0B, 0x64, + 0xD0, 0xAE, 0x7F, 0xCB, 0xDD, 0x7D, 0x05, 0x88, + 0x4C, 0x34, 0xBB, 0xF4, 0x00, 0xCE, 0x1C, 0x13, + 0x4E, 0xA3, 0xE3, 0x60, 0x4B, 0x50, 0x4E, 0xE1, + 0x26, 0x22, 0x51, 0xD4, 0x32, 0x60, 0xC6, 0x3E, + 0x7D, 0x4A, 0x3E, 0x56, 0x78, 0xBD, 0x5F, 0x23, + 0x7F, 0x0A, 0xA0, 0xC1, 0x1A, 0x60, 0xA2, 0x7C, + 0x9E, 0x17, 0x6F, 0xD8, 0x73, 0x0F, 0x1A, 0x1F, + 0x47, 0x58, 0x44, 0x20, 0x80, 0xC6, 0x5D, 0x6E, + 0xEC, 0xFF, 0xCA, 0x65, 0xA1, 0xFB, 0xEE, 0xF2, + 0x56, 0x1A, 0x16, 0x9E, 0x4D, 0xCA, 0x67, 0x81, + 0x23, 0xDE, 0xBE, 0x5E, 0x31, 0x56, 0xF0, 0x34, + 0xBA, 0x12, 0xFC, 0x07, 0x03, 0x96, 0xD2, 0x8E, + 0xCE, 0xA6, 0xF6, 0x74, 0x07, 0x4F, 0x63, 0x40, + 0x14, 0x0A, 0xD6, 0x45, 0xB4, 0xF1, 0x72, 0x87, + 0x34, 0x89, 0x5C, 0x06, 0x1B, 0x8C, 0x0E, 0xA2, + 0x84, 0x50, 0x12, 0xAD, 0x26, 0x5B, 0x4F, 0x6B, + 0x23, 0x9D, 0x3C, 0xBB, 0x8A, 0xDA, 0x08, 0x4B, + 0x93, 0x47, 0x02, 0x96, 0x76, 0xD4, 0x87, 0xE9, + 0x4B, 0x69, 0x82, 0xD6, 0xCC, 0x69, 0x02, 0xC0, + 0xA4, 0x75, 0x7A, 0x90, 0xFD, 0xF6, 0xD6, 0x9D, + 0xE2, 0x4C, 0xB6, 0xFA, 0x61, 0xA5, 0x7C, 0x18, + 0xEA, 0x84, 0xA1, 0x74, 0x85, 0x2E, 0xCA, 0xF9, + 0x17, 0x29, 0xFF, 0x67, 0x70, 0xC9, 0x6F, 0xF1, + 0x41, 0xEF, 0xA1, 0x59, 0x54, 0xA0, 0x99, 0x14, + 0x48, 0x74, 0x5D, 0x14, 0x3E, 0x04, 0xCE, 0xF7, + 0x16, 0x9F, 0x8A, 0x41, 0xF4, 0xAE, 0xB3, 0x10, + 0xCE, 0x19, 0xC2, 0x83, 0x7B, 0xD0, 0x26, 0x1E, + 0x75, 0x8A, 0x0A, 0x40, 0x4A, 0xB8, 0xE0, 0x5C, + 0x13, 0x8B, 0xCC, 0x6F, 0xF3, 0x00, 0xB3, 0x64, + 0x1B, 0x3C, 0x3D, 0x08, 0x3B, 0x9F, 0xD0, 0x9B, + 0xE5, 0x72, 0x45, 0x96, 0x95, 0x4D, 0x66, 0xC7, + 0x79, 0x5D, 0x3A, 0x1A, 0x94, 0x64, 0x94, 0x07, + 0x1A, 0xE8, 0x7C, 0xD1, 0x1C, 0xB1, 0x7E, 0x32, + 0x28, 0x1A, 0x90, 0x22, 0xD9, 0x86, 0x9B, 0x9C, + 0x9B, 0x0C, 0x04, 0x31, 0x85, 0x10, 0x42, 0x50, + 0x40, 0x11, 0x72, 0xAB, 0x94, 0x0C, 0xAF, 0xC3, + 0x22, 0x1A, 0xC1, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xFD, 0x78, + 0xA7, 0x70, 0x1F, 0x8A, 0xE9, 0x07, 0xB9, 0xCA, + 0x3C, 0xD1, 0xE8, 0xDC, 0x68, 0xFF, 0x02, 0x61, + 0x29, 0x97, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, + 0x00, 0x04, 0x14, 0x22, 0x7E, 0x99, 0x10, 0xB3, + 0x99, 0x79, 0xE7, 0x14, 0x7F, 0x91, 0x59, 0x24, + 0x4F, 0x2F, 0xCF, 0xE8, 0x53, 0x1D, 0x0F, 0x04, + 0x08, 0x30, 0x1E, 0x5C, 0xE4, 0x3C, 0x66, 0xDF, + 0xB0, 0x02, 0x02, 0x08, 0x00] +}; + +gTestSuite.doTestWithCertificate( + new Blob([new Uint8Array(testCertInfo.blob)]), + testCertInfo.password, + testCertInfo.nickname, + testCertInfo.usage +); diff --git a/dom/wifi/test/marionette/test_wifi_manage_server_certificate.js b/dom/wifi/test/marionette/test_wifi_manage_server_certificate.js new file mode 100644 index 0000000000..dfaf524b21 --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_manage_server_certificate.js @@ -0,0 +1,106 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +// Binary form of test certificate. +var testCertInfo = { + nickname: 'Test Certificate', + password: '', + usage: ['ServerCert'], + blob: [0x30, 0x82, 0x02, 0xae, 0x30, 0x82, 0x02, 0x17, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0x92, 0x49, 0xe2, 0x62, 0x71, 0xf6, 0xc7, 0x92, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, + 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x54, 0x57, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x06, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x07, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, + 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x02, 0x51, 0x41, 0x31, 0x0e, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x05, 0x47, 0x65, 0x72, 0x72, 0x79, 0x31, 0x21, + 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x67, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x40, 0x6d, 0x6f, + 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, + 0x35, 0x32, 0x33, 0x30, 0x39, 0x34, 0x32, 0x33, + 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x35, + 0x32, 0x32, 0x30, 0x39, 0x34, 0x32, 0x33, 0x37, + 0x5a, 0x30, 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x57, + 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x06, 0x54, 0x61, 0x69, 0x70, 0x65, + 0x69, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x6f, 0x7a, 0x69, + 0x6c, 0x6c, 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x51, 0x41, + 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x05, 0x47, 0x65, 0x72, 0x72, 0x79, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, + 0x12, 0x67, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x40, + 0x6d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, + 0xd3, 0xdb, 0x54, 0xcc, 0xca, 0x0b, 0xee, 0xf9, + 0x8a, 0x37, 0x0d, 0x06, 0x8b, 0x20, 0x00, 0x4a, + 0x55, 0x84, 0x90, 0x1a, 0xb7, 0x9c, 0x91, 0xb2, + 0x38, 0x6b, 0x8b, 0x32, 0x7a, 0x89, 0x9e, 0x79, + 0x71, 0x88, 0x43, 0x21, 0x94, 0x18, 0xa8, 0xfc, + 0xe3, 0x7a, 0x8a, 0xb3, 0xa1, 0xf7, 0x23, 0xe7, + 0x1a, 0xe3, 0xe7, 0x0d, 0xf1, 0x66, 0x21, 0x58, + 0x21, 0x85, 0x5b, 0x35, 0xec, 0x68, 0xd2, 0xfd, + 0x44, 0x76, 0x93, 0x05, 0xbb, 0x89, 0x7d, 0x92, + 0xf9, 0xce, 0x75, 0xa3, 0xeb, 0x39, 0xc1, 0x7d, + 0x7e, 0x50, 0xf9, 0xb8, 0x60, 0x61, 0xf7, 0x2f, + 0x54, 0x39, 0xfe, 0x8a, 0x20, 0xb2, 0x0d, 0x48, + 0x7f, 0x18, 0x0d, 0x02, 0xcc, 0x7b, 0x8e, 0x31, + 0xe9, 0xbe, 0xfc, 0x96, 0x2e, 0x63, 0x6f, 0xfa, + 0x4c, 0xc4, 0xcf, 0x8a, 0xe4, 0x13, 0x67, 0xf1, + 0xec, 0x3e, 0xd8, 0x23, 0xa1, 0xbf, 0x67, 0x71, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0x13, 0xe1, 0xac, 0xa4, + 0x75, 0x3d, 0x2c, 0x5f, 0xe5, 0x41, 0x42, 0x90, + 0x5a, 0x48, 0x5c, 0x46, 0xbc, 0x24, 0x8e, 0xa1, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x13, 0xe1, 0xac, + 0xa4, 0x75, 0x3d, 0x2c, 0x5f, 0xe5, 0x41, 0x42, + 0x90, 0x5a, 0x48, 0x5c, 0x46, 0xbc, 0x24, 0x8e, + 0xa1, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0xaa, 0x6b, 0x62, 0x53, 0x74, 0x2a, + 0x20, 0x76, 0xab, 0xd2, 0x60, 0x06, 0xfd, 0x88, + 0xf5, 0x1c, 0x85, 0xe6, 0x57, 0xf1, 0xf0, 0x18, + 0x97, 0x7c, 0x70, 0xb8, 0xb4, 0x7c, 0xcc, 0x58, + 0x8d, 0xf4, 0x7c, 0xb6, 0x34, 0xcc, 0x15, 0x79, + 0xaf, 0x75, 0xa9, 0x0b, 0xd1, 0xea, 0xf8, 0x85, + 0x7c, 0xe8, 0x19, 0xe9, 0x13, 0x90, 0x84, 0x5f, + 0x21, 0x94, 0x0a, 0x4d, 0x15, 0xef, 0xd1, 0x16, + 0xd4, 0xba, 0x2c, 0x59, 0x1b, 0x83, 0x23, 0xf5, + 0xa5, 0xcd, 0xbd, 0xda, 0x32, 0x73, 0x46, 0x49, + 0x98, 0xf3, 0xfb, 0x50, 0x6e, 0x30, 0xd7, 0x3e, + 0x31, 0xd6, 0xe8, 0x65, 0x2f, 0x5a, 0xf1, 0x0f, + 0x7b, 0x0a, 0x21, 0x61, 0x8e, 0x45, 0x29, 0x4f, + 0x7a, 0x04, 0xda, 0x29, 0xfc, 0x6f, 0xc5, 0x5e, + 0xee, 0xe1, 0x0f, 0xd5, 0x4b, 0xb7, 0xc9, 0x6a, + 0x8e, 0x7c, 0x19, 0xef, 0x6e, 0x64, 0x98, 0xfe, + 0xe3, 0x35] +}; + +gTestSuite.doTestWithCertificate( + new Blob([new Uint8Array(testCertInfo.blob)]), + testCertInfo.password, + testCertInfo.nickname, + testCertInfo.usage +); diff --git a/dom/wifi/test/marionette/test_wifi_manage_user_certificate.js b/dom/wifi/test/marionette/test_wifi_manage_user_certificate.js new file mode 100644 index 0000000000..950ceae4ed --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_manage_user_certificate.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +// Binary form of test certificate. +var testCertInfo = { + nickname: 'Test Certificate', + password: '', + usage: ['UserCert'], + blob: '-----BEGIN CERTIFICATE-----\n' + + 'MIICTjCCAbegAwIBAgICNV4wDQYJKoZIhvcNAQEEBQAwgYUxCzAJBgNVBAYTAklU\n' + + 'MRYwFAYDVQQKEw1aZXJvc2hlbGwubmV0MRAwDgYDVQQLEwdFeGFtcGxlMR0wGwYD\n' + + 'VQQDExRaZXJvU2hlbGwgRXhhbXBsZSBDQTEtMCsGCSqGSIb3DQEJARYeRnVsdmlv\n' + + 'LlJpY2NpYXJkaUB6ZXJvc2hlbGwubmV0MB4XDTEzMDMxMTAzMzg1MloXDTE0MDMx\n' + + 'MTAzMzg1MlowIzEOMAwGA1UECxMFVXNlcnMxETAPBgNVBAMTCGNodWNrbGVlMIGf\n' + + 'MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvVzFhQAVqAIHW5DlAhp4FEGEei7k7\n' + + 'uVUeqkH7JAsww6zmDLg9yZlcZAc95N0lkz022gLXehH2M0R1FOR++nkqofzWfc7w\n' + + 'n79ith+dU2GQMeKq7vPGDYXpgIkEKbYfzKj3fY3129MlTxJQt1UD/ejz38V8HKgw\n' + + 'qKSuwo0NVeY66QIDAQABoy4wLDALBgNVHQ8EBAMCBLAwHQYDVR0lBBYwFAYIKwYB\n' + + 'BQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBAUAA4GBAJWgfX5vYSD7MGZk1rTF\n' + + 'DSziWYGqpR+Moo3qQ+9qLG8m+XVM9hckWpY31A5sWAeCZCe1SSNLFbbgsaOyPZE2\n' + + 'NqMyvs61Vszpc2mmWAYT6j2OU2tw8p5pcUZd6eIp7Gc3fLymiX/WoSmilZKmrGUZ\n' + + 'Q15R+TCpclUsaNrUGjybgaw7\n' + + '-----END CERTIFICATE-----' +}; + +gTestSuite.doTestWithCertificate( + new Blob([testCertInfo.blob]), + testCertInfo.password, + testCertInfo.nickname, + testCertInfo.usage +); diff --git a/dom/wifi/test/marionette/test_wifi_static_ip.js b/dom/wifi/test/marionette/test_wifi_static_ip.js new file mode 100644 index 0000000000..90436b6fe0 --- /dev/null +++ b/dom/wifi/test/marionette/test_wifi_static_ip.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; +MARIONETTE_HEAD_JS = 'head.js'; + +const STATIC_IP_CONFIG = { + enabled: true, + ipaddr: "192.168.111.222", + proxy: "", + maskLength: 24, + gateway: "192.168.111.1", + dns1: "8.8.8.8", + dns2: "8.8.4.4", +}; + +const TESTING_HOSTAPD = [{ ssid: 'ap0' }]; + +function testAssociateWithStaticIp(aNetwork, aStaticIpConfig) { + return gTestSuite.setStaticIpMode(aNetwork, aStaticIpConfig) + .then(() => gTestSuite.testAssociate(aNetwork)) + // Check ip address and prefix. + .then(() => gTestSuite.exeAndParseNetcfg()) + .then((aResult) => { + is(aResult["wlan0"].ip, aStaticIpConfig.ipaddr, "Check ip address"); + is(aResult["wlan0"].prefix, aStaticIpConfig.maskLength, "Check prefix"); + }) + // Check routing. + .then(() => gTestSuite.exeAndParseIpRoute()) + .then((aResult) => { + is(aResult["wlan0"].src, aStaticIpConfig.ipaddr, "Check ip address"); + is(aResult["wlan0"].default, true, "Check default route"); + is(aResult["wlan0"].gateway, aStaticIpConfig.gateway, "Check gateway"); + }); +} + +function findDesireNetwork(aNetworks) { + let i = gTestSuite.getFirstIndexBySsid(TESTING_HOSTAPD[0].ssid, aNetworks); + + if (-1 !== i) { + return aNetworks[i]; + } + + return aNetworks[0]; +} + +// Start test. +gTestSuite.doTestWithoutStockAp(function() { + return gTestSuite.ensureWifiEnabled(true) + + // Start custom hostapd for testing. + .then(() => gTestSuite.startHostapds(TESTING_HOSTAPD)) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', + TESTING_HOSTAPD.length)) + + // Perform a wifi scan, and then run the static ip test + .then(() => gTestSuite.requestWifiScan()) + .then((aNetworks) => findDesireNetwork(aNetworks)) + .then((aNetwork) => testAssociateWithStaticIp(aNetwork, + STATIC_IP_CONFIG)) + + // Kill running hostapd. + .then(gTestSuite.killAllHostapd) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0)); +}); diff --git a/dom/wifi/test/marionette/test_wifi_tethering_wifi_active.js b/dom/wifi/test/marionette/test_wifi_tethering_wifi_active.js index 0630c3bcb7..af0df01a09 100644 --- a/dom/wifi/test/marionette/test_wifi_tethering_wifi_active.js +++ b/dom/wifi/test/marionette/test_wifi_tethering_wifi_active.js @@ -4,6 +4,8 @@ MARIONETTE_TIMEOUT = 60000; MARIONETTE_HEAD_JS = 'head.js'; +const TESTING_HOSTAPD = [{ ssid: 'ap0' }]; + function connectToFirstNetwork() { let firstNetwork; return gTestSuite.requestWifiScan() @@ -18,6 +20,11 @@ gTestSuite.doTestTethering(function() { let firstNetwork; return gTestSuite.ensureWifiEnabled(true) + // Start custom hostapd for testing. + .then(() => gTestSuite.startHostapds(TESTING_HOSTAPD)) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', TESTING_HOSTAPD.length)) + + // Connect to the testing AP and wait for data becoming disconnected. .then(function () { return Promise.all([ // 1) Set up the event listener first: @@ -46,8 +53,12 @@ gTestSuite.doTestTethering(function() { // Wifi should be enabled, RIL data should become disconnected and // we should connect to an wifi AP. gTestSuite.waitForWifiManagerEventOnce('enabled'), - gTestSuite.waitForRilDataConnected(false), - gTestSuite.waitForConnected(firstNetwork), + + // Due to Bug 1168285, after re-enablin wifi, the remembered network + // will not be connected automatically. Leave "auto connect test" + // covered by test_wifi_auto_connect.js. + //gTestSuite.waitForRilDataConnected(false), + //gTestSuite.waitForConnected(firstNetwork), // 2) Stop wifi tethering. gTestSuite.requestTetheringEnabled(false) @@ -55,5 +66,9 @@ gTestSuite.doTestTethering(function() { }) // Remove wlan0 from default route by disabling wifi. Otherwise, // it will cause the subsequent test cases loading page error. - .then(() => gTestSuite.requestWifiEnabled(false)); + .then(() => gTestSuite.requestWifiEnabled(false)) + + // Kill running hostapd. + .then(gTestSuite.killAllHostapd) + .then(() => gTestSuite.verifyNumOfProcesses('hostapd', 0)); }); \ No newline at end of file diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index e1c5214af4..a8b03b22f0 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -585,10 +585,8 @@ InterruptCallback(JSContext* aCx) return worker->InterruptCallback(aCx); } -class LogViolationDetailsRunnable final : public Runnable +class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable { - WorkerPrivate* mWorkerPrivate; - nsCOMPtr<nsIEventTarget> mSyncLoopTarget; nsString mFileName; uint32_t mLineNum; @@ -596,32 +594,17 @@ class LogViolationDetailsRunnable final : public Runnable LogViolationDetailsRunnable(WorkerPrivate* aWorker, const nsString& aFileName, uint32_t aLineNum) - : mWorkerPrivate(aWorker), mFileName(aFileName), mLineNum(aLineNum) + : WorkerMainThreadRunnable(aWorker, + NS_LITERAL_CSTRING("RuntimeService :: LogViolationDetails")) + , mFileName(aFileName), mLineNum(aLineNum) { MOZ_ASSERT(aWorker); } - NS_DECL_ISUPPORTS_INHERITED - - bool - Dispatch() - { - AutoSyncLoopHolder syncLoop(mWorkerPrivate); - - mSyncLoopTarget = syncLoop.EventTarget(); - MOZ_ASSERT(mSyncLoopTarget); - - if (NS_FAILED(NS_DispatchToMainThread(this))) { - return false; - } - - return syncLoop.Run(); - } + virtual bool MainThreadRun() override; private: ~LogViolationDetailsRunnable() {} - - NS_DECL_NSIRUNNABLE }; bool @@ -644,7 +627,11 @@ ContentSecurityPolicyAllows(JSContext* aCx) RefPtr<LogViolationDetailsRunnable> runnable = new LogViolationDetailsRunnable(worker, fileName, lineNum); - runnable->Dispatch(); + ErrorResult rv; + runnable->Dispatch(rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } } return worker->IsEvalAllowed(); @@ -1463,17 +1450,13 @@ RuntimeService::RegisterWorker(WorkerPrivate* aWorkerPrivate) if (queued) { domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate); + + // Worker spawn gets queued due to hitting max workers per domain + // limit so let's log a warning. + WorkerPrivate::ReportErrorToConsole("HittingMaxWorkersPerDomain2"); + if (isServiceWorker || isSharedWorker) { - AssertIsOnMainThread(); - // ServiceWorker spawn gets queued due to hitting max workers per domain - // limit so let's log a warning. - // Note: aWorkerPrivate->GetDocument() call might result nullptr due to - // no window so the message warning will show up in the browser console. - nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, - NS_LITERAL_CSTRING("DOM"), - aWorkerPrivate->GetDocument(), - nsContentUtils::eDOM_PROPERTIES, - "HittingMaxWorkersPerDomain"); + /* nothing */ } } else if (parent) { @@ -2594,10 +2577,8 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure options.behaviors().setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT); } -NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, Runnable) - -NS_IMETHODIMP -LogViolationDetailsRunnable::Run() +bool +LogViolationDetailsRunnable::MainThreadRun() { AssertIsOnMainThread(); @@ -2612,12 +2593,7 @@ LogViolationDetailsRunnable::Run() } } - RefPtr<MainThreadStopSyncLoopRunnable> response = - new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(), - true); - MOZ_ALWAYS_TRUE(response->Dispatch()); - - return NS_OK; + return true; } NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback) diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 1dc85d8fe9..f7f9a42606 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -9,6 +9,7 @@ #include "nsIChannel.h" #include "nsIContentPolicy.h" #include "nsIContentSecurityPolicy.h" +#include "nsIDocShell.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIInputStreamPump.h" @@ -890,6 +891,28 @@ class ScriptLoaderRunnable final : public WorkerFeature nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; + // Get the top-level worker. + WorkerPrivate* topWorkerPrivate = mWorkerPrivate; + WorkerPrivate* parent = topWorkerPrivate->GetParent(); + while (parent) { + topWorkerPrivate = parent; + parent = topWorkerPrivate->GetParent(); + } + + // If the top-level worker is a dedicated worker and has a window, and the + // window has a docshell, the caching behavior of this worker should match + // that of that docshell. + if (topWorkerPrivate->IsDedicatedWorker()) { + nsCOMPtr<nsPIDOMWindow> window = topWorkerPrivate->GetWindow(); + if (window) { + nsCOMPtr<nsIDocShell> docShell = do_GetInterface(window); + if (docShell) { + nsresult rv = docShell->GetDefaultLoadFlags(&loadFlags); + NS_ENSURE_SUCCESS(rv, rv); + } + } + } + // If we are loading a script for a ServiceWorker then we must not // try to intercept it. If the interception matches the current // ServiceWorker's scope then we could deadlock the load. @@ -1615,15 +1638,17 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont const uint8_t* aString) { AssertIsOnMainThread(); - MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache); mPump = nullptr; if (NS_FAILED(aStatus)) { + MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache || + mLoadInfo.mCacheStatus == ScriptLoadInfo::Cancel); Fail(aStatus); return NS_OK; } + MOZ_ASSERT(mLoadInfo.mCacheStatus == ScriptLoadInfo::ReadingFromCache); mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached; MOZ_ASSERT(mPrincipalInfo); @@ -1632,43 +1657,42 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont return NS_OK; } -class ChannelGetterRunnable final : public Runnable +class ChannelGetterRunnable final : public WorkerMainThreadRunnable { - WorkerPrivate* mParentWorker; - nsCOMPtr<nsIEventTarget> mSyncLoopTarget; const nsAString& mScriptURL; nsIChannel** mChannel; nsresult mResult; public: ChannelGetterRunnable(WorkerPrivate* aParentWorker, - nsIEventTarget* aSyncLoopTarget, const nsAString& aScriptURL, nsIChannel** aChannel) - : mParentWorker(aParentWorker), mSyncLoopTarget(aSyncLoopTarget), - mScriptURL(aScriptURL), mChannel(aChannel), mResult(NS_ERROR_FAILURE) + : WorkerMainThreadRunnable(aParentWorker, + NS_LITERAL_CSTRING("ScriptLoader :: ChannelGetter")) + , mScriptURL(aScriptURL) + , mChannel(aChannel) + , mResult(NS_ERROR_FAILURE) { - MOZ_ASSERT(mParentWorker); + MOZ_ASSERT(aParentWorker); aParentWorker->AssertIsOnWorkerThread(); - MOZ_ASSERT(aSyncLoopTarget); } - NS_IMETHOD - Run() override + virtual bool + MainThreadRun() override { AssertIsOnMainThread(); - nsIPrincipal* principal = mParentWorker->GetPrincipal(); + nsIPrincipal* principal = mWorkerPrivate->GetPrincipal(); MOZ_ASSERT(principal); // Figure out our base URI. - nsCOMPtr<nsIURI> baseURI = mParentWorker->GetBaseURI(); + nsCOMPtr<nsIURI> baseURI = mWorkerPrivate->GetBaseURI(); MOZ_ASSERT(baseURI); // May be null. - nsCOMPtr<nsIDocument> parentDoc = mParentWorker->GetDocument(); + nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument(); - nsCOMPtr<nsILoadGroup> loadGroup = mParentWorker->GetLoadGroup(); + nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup(); nsCOMPtr<nsIChannel> channel; mResult = @@ -1682,14 +1706,7 @@ class ChannelGetterRunnable final : public Runnable channel.forget(mChannel); } - RefPtr<MainThreadStopSyncLoopRunnable> runnable = - new MainThreadStopSyncLoopRunnable(mParentWorker, - mSyncLoopTarget.forget(), true); - if (!runnable->Dispatch()) { - NS_ERROR("This should never fail!"); - } - - return NS_OK; + return true; } nsresult @@ -1900,9 +1917,8 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx, // 1) mScriptLoader.mRv.Failed(). In that case we just want to leave it // as-is, except if it has a JS exception and we need to mute JS // exceptions. In that case, we log the exception without firing any - // events and then replace it on the ErrorResult with a generic - // NS_ERROR_FAILURE for lack of anything better. XXXbz: This should - // throw a NetworkError per spec updates. See bug 1249673. + // events and then replace it on the ErrorResult with a NetworkError, + // per spec. // // 2) mScriptLoader.mRv succeeded. As far as I can tell, this can only // happen when loading the main worker script and @@ -1912,7 +1928,7 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx, if (mScriptLoader.mRv.Failed()) { if (aMutedError && mScriptLoader.mRv.IsJSException()) { LogExceptionToConsole(aCx, aWorkerPrivate); - mScriptLoader.mRv.Throw(NS_ERROR_FAILURE); + mScriptLoader.mRv.Throw(NS_ERROR_DOM_NETWORK_ERR); } } else { mScriptLoader.mRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); @@ -2023,19 +2039,14 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx, { aParent->AssertIsOnWorkerThread(); - AutoSyncLoopHolder syncLoop(aParent); - RefPtr<ChannelGetterRunnable> getter = - new ChannelGetterRunnable(aParent, syncLoop.EventTarget(), aScriptURL, - aChannel); + new ChannelGetterRunnable(aParent, aScriptURL, aChannel); - if (NS_FAILED(NS_DispatchToMainThread(getter))) { + ErrorResult rv; + getter->Dispatch(rv); + if (rv.Failed()) { NS_ERROR("Failed to dispatch!"); - return NS_ERROR_FAILURE; - } - - if (!syncLoop.Run()) { - return NS_ERROR_FAILURE; + return rv.StealNSResult(); } return getter->GetResult(); diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index a40b7792b0..00d059ff51 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -35,6 +35,7 @@ NS_INTERFACE_MAP_END ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc) : mWindowId(0) + , mFrameType(FrameType::None) { MOZ_ASSERT(aDoc); nsresult rv = aDoc->GetOrCreateId(mClientId); @@ -64,8 +65,9 @@ ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc) } RefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aDoc->GetWindow()); - MOZ_ASSERT(outerWindow); - if (!outerWindow->IsTopLevelWindow()) { + if (!outerWindow) { + MOZ_ASSERT(mFrameType == FrameType::None); + } else if (!outerWindow->IsTopLevelWindow()) { mFrameType = FrameType::Nested; } else if (outerWindow->HadOriginalOpener()) { mFrameType = FrameType::Auxiliary; @@ -126,6 +128,9 @@ class ServiceWorkerClientPostMessageRunnable final { AssertIsOnMainThread(); + MOZ_ASSERT(aTargetContainer->GetParentObject(), + "How come we don't have a window here?!"); + JS::Rooted<JS::Value> messageData(aCx); ErrorResult rv; Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv); @@ -136,8 +141,24 @@ class ServiceWorkerClientPostMessageRunnable final RootedDictionary<ServiceWorkerMessageEventInit> init(aCx); + nsCOMPtr<nsIPrincipal> principal = aTargetContainer->GetParentObject()->PrincipalOrNull(); + NS_WARN_IF_FALSE(principal, "Why is the principal null here?"); + + bool isNullPrincipal = false; + bool isSystemPrincipal = false; + if (principal) { + principal->GetIsNullPrincipal(&isNullPrincipal); + MOZ_ASSERT(!isNullPrincipal); + principal->GetIsSystemPrincipal(&isSystemPrincipal); + MOZ_ASSERT(!isSystemPrincipal); + } + init.mData = messageData; - init.mOrigin.Construct(EmptyString()); + nsAutoCString origin; + if (principal && !isNullPrincipal && !isSystemPrincipal) { + principal->GetOrigin(origin); + } + init.mOrigin.Construct(NS_ConvertUTF8toUTF16(origin)); init.mLastEventId.Construct(EmptyString()); init.mPorts.Construct(); init.mPorts.Value().SetNull(); diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index b3808fd0a4..a20d2f51d1 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -42,6 +42,7 @@ namespace { static const char* gSupportedRegistrarVersions[] = { SERVICEWORKERREGISTRAR_VERSION, + "3", "2" }; @@ -143,6 +144,29 @@ ServiceWorkerRegistrar::GetRegistrations( } } +namespace { + +bool Equivalent(const ServiceWorkerRegistrationData& aLeft, + const ServiceWorkerRegistrationData& aRight) +{ + MOZ_ASSERT(aLeft.principal().type() == + mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); + MOZ_ASSERT(aRight.principal().type() == + mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); + + const auto& leftPrincipal = aLeft.principal().get_ContentPrincipalInfo(); + const auto& rightPrincipal = aRight.principal().get_ContentPrincipalInfo(); + + // Only compare the attributes, not the spec part of the principal. + // The scope comparison above already covers the origin and codebase + // principals include the full path in their spec which is not what + // we want here. + return aLeft.scope() == aRight.scope() && + leftPrincipal.attrs() == rightPrincipal.attrs(); +} + +} // anonymous namespace + void ServiceWorkerRegistrar::RegisterServiceWorker( const ServiceWorkerRegistrationData& aData) @@ -157,33 +181,7 @@ ServiceWorkerRegistrar::RegisterServiceWorker( { MonitorAutoLock lock(mMonitor); MOZ_ASSERT(mDataLoaded); - - const mozilla::ipc::PrincipalInfo& newPrincipalInfo = aData.principal(); - MOZ_ASSERT(newPrincipalInfo.type() == - mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); - - const mozilla::ipc::ContentPrincipalInfo& newContentPrincipalInfo = - newPrincipalInfo.get_ContentPrincipalInfo(); - - bool found = false; - for (uint32_t i = 0, len = mData.Length(); i < len; ++i) { - if (mData[i].scope() == aData.scope()) { - const mozilla::ipc::PrincipalInfo& existingPrincipalInfo = - mData[i].principal(); - const mozilla::ipc::ContentPrincipalInfo& existingContentPrincipalInfo = - existingPrincipalInfo.get_ContentPrincipalInfo(); - - if (newContentPrincipalInfo == existingContentPrincipalInfo) { - mData[i] = aData; - found = true; - break; - } - } - } - - if (!found) { - mData.AppendElement(aData); - } + RegisterServiceWorkerInternal(aData); } ScheduleSaveData(); @@ -207,9 +205,12 @@ ServiceWorkerRegistrar::UnregisterServiceWorker( MonitorAutoLock lock(mMonitor); MOZ_ASSERT(mDataLoaded); + ServiceWorkerRegistrationData tmp; + tmp.principal() = aPrincipalInfo; + tmp.scope() = aScope; + for (uint32_t i = 0; i < mData.Length(); ++i) { - if (mData[i].principal() == aPrincipalInfo && - mData[i].scope() == aScope) { + if (Equivalent(tmp, mData[i])) { mData.RemoveElementAt(i); deleted = true; break; @@ -317,9 +318,12 @@ ServiceWorkerRegistrar::ReadData() return NS_ERROR_FAILURE; } + nsTArray<ServiceWorkerRegistrationData> tmpData; + bool overwrite = false; + bool dedupe = false; while (hasMoreLines) { - ServiceWorkerRegistrationData* entry = mData.AppendElement(); + ServiceWorkerRegistrationData* entry = tmpData.AppendElement(); #define GET_LINE(x) \ rv = lineInputStream->ReadLine(x, &hasMoreLines); \ @@ -331,6 +335,7 @@ ServiceWorkerRegistrar::ReadData() } nsAutoCString line; + nsAutoCString unused; if (version.EqualsLiteral(SERVICEWORKERREGISTRAR_VERSION)) { nsAutoCString suffix; GET_LINE(suffix); @@ -340,11 +345,36 @@ ServiceWorkerRegistrar::ReadData() return NS_ERROR_INVALID_ARG; } - GET_LINE(line); + GET_LINE(entry->scope()); + entry->principal() = - mozilla::ipc::ContentPrincipalInfo(attrs, line); + mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope()); + + GET_LINE(entry->currentWorkerURL()); + + nsAutoCString cacheName; + GET_LINE(cacheName); + CopyUTF8toUTF16(cacheName, entry->cacheName()); + } else if (version.EqualsLiteral("3")) { + overwrite = true; + dedupe = true; + + nsAutoCString suffix; + GET_LINE(suffix); + + OriginAttributes attrs; + if (!attrs.PopulateFromSuffix(suffix)) { + return NS_ERROR_INVALID_ARG; + } + + // principal spec is no longer used; we use scope directly instead + GET_LINE(unused); GET_LINE(entry->scope()); + + entry->principal() = + mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope()); + GET_LINE(entry->currentWorkerURL()); nsAutoCString cacheName; @@ -352,6 +382,7 @@ ServiceWorkerRegistrar::ReadData() CopyUTF8toUTF16(cacheName, entry->cacheName()); } else if (version.EqualsLiteral("2")) { overwrite = true; + dedupe = true; nsAutoCString suffix; GET_LINE(suffix); @@ -361,14 +392,15 @@ ServiceWorkerRegistrar::ReadData() return NS_ERROR_INVALID_ARG; } - GET_LINE(line); - entry->principal() = - mozilla::ipc::ContentPrincipalInfo(attrs, line); + // principal spec is no longer used; we use scope directly instead + GET_LINE(unused); GET_LINE(entry->scope()); + entry->principal() = + mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope()); + // scriptSpec is no more used in latest version. - nsAutoCString unused; GET_LINE(unused); GET_LINE(entry->currentWorkerURL()); @@ -397,6 +429,38 @@ ServiceWorkerRegistrar::ReadData() stream->Close(); + // Copy data over to mData. + for (uint32_t i = 0; i < tmpData.Length(); ++i) { + bool match = false; + if (dedupe) { + MOZ_ASSERT(overwrite); + // If this is an old profile, then we might need to deduplicate. In + // theory this can be removed in the future (Bug 1248449) + for (uint32_t j = 0; j < mData.Length(); ++j) { + // Use same comparison as RegisterServiceWorker. Scope contains + // basic origin information. Combine with any principal attributes. + if (Equivalent(tmpData[i], mData[j])) { + // Last match wins, just like legacy loading used to do in + // the ServiceWorkerManager. + mData[j] = tmpData[i]; + // Dupe found, so overwrite file with reduced list. + match = true; + break; + } + } + } else { +#ifdef DEBUG + // Otherwise assert no duplications in debug builds. + for (uint32_t j = 0; j < mData.Length(); ++j) { + MOZ_ASSERT(!Equivalent(tmpData[i], mData[j])); + } +#endif + } + if (!match) { + mData.AppendElement(tmpData[i]); + } + } + // Overwrite previous version. // Cannot call SaveData directly because gtest uses main-thread. if (overwrite && NS_FAILED(WriteData())) { @@ -441,6 +505,23 @@ ServiceWorkerRegistrar::DeleteData() } } +void +ServiceWorkerRegistrar::RegisterServiceWorkerInternal(const ServiceWorkerRegistrationData& aData) +{ + bool found = false; + for (uint32_t i = 0, len = mData.Length(); i < len; ++i) { + if (Equivalent(aData, mData[i])) { + mData[i] = aData; + found = true; + break; + } + } + + if (!found) { + mData.AppendElement(aData); + } +} + class ServiceWorkerRegistrarSaveDataRunnable final : public Runnable { public: @@ -613,9 +694,6 @@ ServiceWorkerRegistrar::WriteData() buffer.Append(suffix.get()); buffer.Append('\n'); - buffer.Append(cInfo.spec()); - buffer.Append('\n'); - buffer.Append(data[i].scope()); buffer.Append('\n'); diff --git a/dom/workers/ServiceWorkerRegistrar.h b/dom/workers/ServiceWorkerRegistrar.h index 82275fb635..43922cfc5b 100644 --- a/dom/workers/ServiceWorkerRegistrar.h +++ b/dom/workers/ServiceWorkerRegistrar.h @@ -16,7 +16,7 @@ #include "nsTArray.h" #define SERVICEWORKERREGISTRAR_FILE "serviceworker.txt" -#define SERVICEWORKERREGISTRAR_VERSION "3" +#define SERVICEWORKERREGISTRAR_VERSION "4" #define SERVICEWORKERREGISTRAR_TERMINATOR "#" #define SERVICEWORKERREGISTRAR_TRUE "true" #define SERVICEWORKERREGISTRAR_FALSE "false" @@ -66,6 +66,8 @@ class ServiceWorkerRegistrar : public nsIObserver nsresult WriteData(); void DeleteData(); + void RegisterServiceWorkerInternal(const ServiceWorkerRegistrationData& aData); + ServiceWorkerRegistrar(); virtual ~ServiceWorkerRegistrar(); diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index 8a8e6671eb..14e8ac3664 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -970,6 +970,14 @@ ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv) return nullptr; } + // Avoid infinite update loops by ignoring update() calls during top + // level script evaluation. See: + // https://github.com/slightlyoff/ServiceWorker/issues/800 + if (worker->LoadScriptAsPartOfLoadingServiceWorkerScript()) { + promise->MaybeResolve(JS::UndefinedHandleValue); + return promise.forget(); + } + RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise); if (!proxy) { aRv.Throw(NS_ERROR_DOM_ABORT_ERR); diff --git a/dom/workers/ServiceWorkerScriptCache.cpp b/dom/workers/ServiceWorkerScriptCache.cpp index f73c1797ea..5ffec43aa2 100644 --- a/dom/workers/ServiceWorkerScriptCache.cpp +++ b/dom/workers/ServiceWorkerScriptCache.cpp @@ -1013,7 +1013,9 @@ GenerateCacheName(nsAString& aName) char chars[NSID_LENGTH]; id.ToProvidedString(chars); - aName.AssignASCII(chars, NSID_LENGTH); + + // NSID_LENGTH counts the null terminator. + aName.AssignASCII(chars, NSID_LENGTH - 1); return NS_OK; } diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp index b70b60c743..810b3c7261 100644 --- a/dom/workers/SharedWorker.cpp +++ b/dom/workers/SharedWorker.cpp @@ -137,7 +137,6 @@ SharedWorker::Close() if (mMessagePort) { mMessagePort->Close(); - mMessagePort = nullptr; } } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 4efd3ce5bb..2cb18e76c9 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -945,6 +945,62 @@ class ThawRunnable final : public WorkerControlRunnable } }; +class ReportErrorToConsoleRunnable final : public WorkerRunnable +{ + const char* mMessage; + +public: + // aWorkerPrivate is the worker thread we're on (or the main thread, if null) + static void + Report(WorkerPrivate* aWorkerPrivate, const char* aMessage) + { + if (aWorkerPrivate) { + aWorkerPrivate->AssertIsOnWorkerThread(); + } else { + AssertIsOnMainThread(); + } + + // Now fire a runnable to do the same on the parent's thread if we can. + if (aWorkerPrivate) { + RefPtr<ReportErrorToConsoleRunnable> runnable = + new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage); + runnable->Dispatch(); + return; + } + + // Log a warning to the console. + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("DOM"), + nullptr, + nsContentUtils::eDOM_PROPERTIES, + aMessage); + } + +private: + ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate, const char* aMessage) + : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), + mMessage(aMessage) + { } + + virtual void + PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override + { + aWorkerPrivate->AssertIsOnWorkerThread(); + + // Dispatch may fail if the worker was canceled, no need to report that as + // an error, so don't call base class PostDispatch. + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override + { + WorkerPrivate* parent = aWorkerPrivate->GetParent(); + MOZ_ASSERT_IF(!parent, NS_IsMainThread()); + Report(parent, mMessage); + return true; + } +}; + class ReportErrorRunnable final : public WorkerRunnable { nsString mMessage; @@ -5856,6 +5912,18 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aFallbackMessage, mErrorHandlerRecursionCount--; } +// static +void +WorkerPrivate::ReportErrorToConsole(const char* aMessage) +{ + WorkerPrivate* wp = nullptr; + if (!NS_IsMainThread()) { + wp = GetCurrentThreadWorkerPrivate(); + } + + ReportErrorToConsoleRunnable::Report(wp, aMessage); +} + int32_t WorkerPrivate::SetTimeout(JSContext* aCx, dom::Function* aHandler, diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index e11daef8d2..7f48c49cdc 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1128,6 +1128,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate> void ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport); + static void + ReportErrorToConsole(const char* aMessage); + int32_t SetTimeout(JSContext* aCx, Function* aHandler, diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 77b79c0885..45dd161549 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -289,7 +289,7 @@ WorkerGlobalScope::SetInterval(JSContext* aCx, } int32_t -WorkerGlobalScope::SetInterval(JSContext* /* unused */, +WorkerGlobalScope::SetInterval(JSContext* aCx, const nsAString& aHandler, const Optional<int32_t>& aTimeout, const Sequence<JS::Value>& /* unused */, @@ -302,8 +302,8 @@ WorkerGlobalScope::SetInterval(JSContext* /* unused */, bool isInterval = aTimeout.WasPassed(); int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0; - return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr, - aHandler, timeout, dummy, isInterval, aRv); + return mWorkerPrivate->SetTimeout(aCx, nullptr, aHandler, timeout, dummy, + isInterval, aRv); } void diff --git a/dom/workers/WorkerScope.h b/dom/workers/WorkerScope.h index d9d59fc3d7..74d62bd3de 100644 --- a/dom/workers/WorkerScope.h +++ b/dom/workers/WorkerScope.h @@ -132,7 +132,7 @@ class WorkerGlobalScope : public DOMEventTargetHelper, const Optional<int32_t>& aTimeout, const Sequence<JS::Value>& aArguments, ErrorResult& aRv); int32_t - SetInterval(JSContext* /* unused */, const nsAString& aHandler, + SetInterval(JSContext* aCx, const nsAString& aHandler, const Optional<int32_t>& aTimeout, const Sequence<JS::Value>& /* unused */, ErrorResult& aRv); void diff --git a/dom/workers/test/browser_bug1047663.js b/dom/workers/test/browser_bug1047663.js new file mode 100644 index 0000000000..8fa2c5358d --- /dev/null +++ b/dom/workers/test/browser_bug1047663.js @@ -0,0 +1,50 @@ +/* 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"; + +const TAB_URL = EXAMPLE_URL + "bug1047663_tab.html"; +const WORKER_URL = EXAMPLE_URL + "bug1047663_worker.sjs"; + +function test() { + waitForExplicitFinish(); + + Task.spawn(function* () { + let tab = yield addTab(TAB_URL); + + // Create a worker. Post a message to it, and check the reply. Since the + // server side JavaScript file returns the first source for the first + // request, the reply should be "one". If the reply is correct, terminate + // the worker. + yield createWorkerInTab(tab, WORKER_URL); + let message = yield postMessageToWorkerInTab(tab, WORKER_URL, "ping"); + is(message, "one"); + yield terminateWorkerInTab(tab, WORKER_URL); + + // Create a second worker with the same URL. Post a message to it, and check + // the reply. The server side JavaScript file returns the second source for + // all subsequent requests, but since the cache is still enabled, the reply + // should still be "one". If the reply is correct, terminate the worker. + yield createWorkerInTab(tab, WORKER_URL); + message = yield postMessageToWorkerInTab(tab, WORKER_URL, "ping"); + is(message, "one"); + yield terminateWorkerInTab(tab, WORKER_URL); + + // Disable the cache in this tab. This should also disable the cache for all + // workers in this tab. + yield disableCacheInTab(tab); + + // Create a third worker with the same URL. Post a message to it, and check + // the reply. Since the server side JavaScript file returns the second + // source for all subsequent requests, and the cache is now disabled, the + // reply should now be "two". If the reply is correct, terminate the worker. + yield createWorkerInTab(tab, WORKER_URL); + message = yield postMessageToWorkerInTab(tab, WORKER_URL, "ping"); + is(message, "two"); + yield terminateWorkerInTab(tab, WORKER_URL); + + removeTab(tab); + + finish(); + }); +} diff --git a/dom/workers/test/bug1047663_tab.html b/dom/workers/test/bug1047663_tab.html new file mode 100644 index 0000000000..62ab9be7d2 --- /dev/null +++ b/dom/workers/test/bug1047663_tab.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"/> + </head> + <body> + </body> +</html> diff --git a/dom/workers/test/bug1047663_worker.sjs b/dom/workers/test/bug1047663_worker.sjs new file mode 100644 index 0000000000..a39bf4474e --- /dev/null +++ b/dom/workers/test/bug1047663_worker.sjs @@ -0,0 +1,40 @@ +/* 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"; + +const WORKER_1 = ` + "use strict"; + + self.onmessage = function () { + postMessage("one"); + }; +`; + +const WORKER_2 = ` + "use strict"; + + self.onmessage = function () { + postMessage("two"); + }; +`; + +function handleRequest(request, response) { + let count = getState("count"); + if (count === "") { + count = "1"; + } + + // This header is necessary for the cache to trigger. + response.setHeader("Cache-control", "max-age=3600"); + + // If this is the first request, return the first source. + if (count === "1") { + response.write(WORKER_1); + setState("count", "2"); + } + // For all subsequent requests, return the second source. + else { + response.write(WORKER_2); + } +} diff --git a/dom/workers/test/frame_script.js b/dom/workers/test/frame_script.js new file mode 100644 index 0000000000..ffc384416c --- /dev/null +++ b/dom/workers/test/frame_script.js @@ -0,0 +1,72 @@ +/* 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"; + +const { interfaces: Ci } = Components; + +let workers = {}; + +let methods = { + /** + * Create a worker with the given `url` in this tab. + */ + createWorker: function (url) { + dump("Frame script: creating worker with url '" + url + "'\n"); + + workers[url] = new content.Worker(url); + return Promise.resolve(); + }, + + /** + * Terminate the worker with the given `url` in this tab. + */ + terminateWorker: function (url) { + dump("Frame script: terminating worker with url '" + url + "'\n"); + + workers[url].terminate(); + delete workers[url]; + return Promise.resolve(); + }, + + /** + * Post the given `message` to the worker with the given `url` in this tab. + */ + postMessageToWorker: function (url, message) { + dump("Frame script: posting message to worker with url '" + url + "'\n"); + + let worker = workers[url]; + worker.postMessage(message); + return new Promise(function (resolve) { + worker.onmessage = function (event) { + worker.onmessage = null; + resolve(event.data); + }; + }); + }, + + /** + * Disable the cache for this tab. + */ + disableCache: function () { + docShell.defaultLoadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE + | Ci.nsIRequest.INHIBIT_CACHING; + } +}; + +addMessageListener("jsonrpc", function (event) { + let { id, method, params } = event.data; + Promise.resolve().then(function () { + return methods[method].apply(undefined, params); + }).then(function (result) { + sendAsyncMessage("jsonrpc", { + id: id, + result: result + }); + }).catch(function (error) { + sendAsyncMessage("jsonrpc", { + id: id, + error: error.toString() + }); + }); +}); diff --git a/dom/workers/test/gtest/TestReadWrite.cpp b/dom/workers/test/gtest/TestReadWrite.cpp index 196c502973..a26cb248a7 100644 --- a/dom/workers/test/gtest/TestReadWrite.cpp +++ b/dom/workers/test/gtest/TestReadWrite.cpp @@ -14,6 +14,7 @@ #include "nsIFile.h" #include "nsIOutputStream.h" #include "nsNetUtil.h" +#include "nsPrintfCString.h" using namespace mozilla::dom; using namespace mozilla::ipc; @@ -34,6 +35,11 @@ class ServiceWorkerRegistrarTest : public ServiceWorkerRegistrar nsresult TestWriteData() { return WriteData(); } void TestDeleteData() { DeleteData(); } + void TestRegisterServiceWorker(const ServiceWorkerRegistrationData& aData) + { + RegisterServiceWorkerInternal(aData); + } + nsTArray<ServiceWorkerRegistrationData>& TestGetData() { return mData; } }; @@ -142,11 +148,11 @@ TEST(ServiceWorkerRegistrar, TestReadData) nsAutoCString buffer(SERVICEWORKERREGISTRAR_VERSION "\n"); buffer.Append("^appId=123&inBrowser=1\n"); - buffer.Append("spec 0\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n"); + buffer.Append("scope 0\ncurrentWorkerURL 0\ncacheName 0\n"); buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); buffer.Append("\n"); - buffer.Append("spec 1\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n"); + buffer.Append("scope 1\ncurrentWorkerURL 1\ncacheName 1\n"); buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail"; @@ -157,7 +163,7 @@ TEST(ServiceWorkerRegistrar, TestReadData) ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); - ASSERT_EQ((uint32_t)2, data.Length()) << "4 entries should be found"; + ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found"; const mozilla::ipc::PrincipalInfo& info0 = data[0].principal(); ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; @@ -167,7 +173,7 @@ TEST(ServiceWorkerRegistrar, TestReadData) cInfo0.attrs().CreateSuffix(suffix0); ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get()); - ASSERT_STREQ("spec 0", cInfo0.spec().get()); + ASSERT_STREQ("scope 0", cInfo0.spec().get()); ASSERT_STREQ("scope 0", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get()); @@ -180,7 +186,7 @@ TEST(ServiceWorkerRegistrar, TestReadData) cInfo1.attrs().CreateSuffix(suffix1); ASSERT_STREQ("", suffix1.get()); - ASSERT_STREQ("spec 1", cInfo1.spec().get()); + ASSERT_STREQ("scope 1", cInfo1.spec().get()); ASSERT_STREQ("scope 1", data[1].scope().get()); ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get()); ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get()); @@ -208,17 +214,20 @@ TEST(ServiceWorkerRegistrar, TestWriteData) { RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest; - nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); - for (int i = 0; i < 10; ++i) { - ServiceWorkerRegistrationData* d = data.AppendElement(); + ServiceWorkerRegistrationData reg; + + reg.scope() = nsPrintfCString("scope write %d", i); + reg.currentWorkerURL() = nsPrintfCString("currentWorkerURL write %d", i); + reg.cacheName() = + NS_ConvertUTF8toUTF16(nsPrintfCString("cacheName write %d", i)); nsAutoCString spec; spec.AppendPrintf("spec write %d", i); - d->principal() = mozilla::ipc::ContentPrincipalInfo(mozilla::OriginAttributes(i, i % 2), spec); - d->scope().AppendPrintf("scope write %d", i); - d->currentWorkerURL().AppendPrintf("currentWorkerURL write %d", i); - d->cacheName().AppendPrintf("cacheName write %d", i); + reg.principal() = + mozilla::ipc::ContentPrincipalInfo(mozilla::PrincipalOriginAttributes(i, i % 2), spec); + + swr->TestRegisterServiceWorker(reg); } nsresult rv = swr->TestWriteData(); @@ -247,7 +256,7 @@ TEST(ServiceWorkerRegistrar, TestWriteData) ASSERT_STREQ(expectSuffix.get(), suffix.get()); - test.AppendPrintf("spec write %d", i); + test.AppendPrintf("scope write %d", i); ASSERT_STREQ(test.get(), cInfo.spec().get()); test.Truncate(); @@ -284,7 +293,7 @@ TEST(ServiceWorkerRegistrar, TestVersion2Migration) ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); - ASSERT_EQ((uint32_t)2, data.Length()) << "4 entries should be found"; + ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found"; const mozilla::ipc::PrincipalInfo& info0 = data[0].principal(); ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; @@ -294,7 +303,7 @@ TEST(ServiceWorkerRegistrar, TestVersion2Migration) cInfo0.attrs().CreateSuffix(suffix0); ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get()); - ASSERT_STREQ("spec 0", cInfo0.spec().get()); + ASSERT_STREQ("scope 0", cInfo0.spec().get()); ASSERT_STREQ("scope 0", data[0].scope().get()); ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); ASSERT_STREQ("activeCache 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get()); @@ -307,12 +316,176 @@ TEST(ServiceWorkerRegistrar, TestVersion2Migration) cInfo1.attrs().CreateSuffix(suffix1); ASSERT_STREQ("", suffix1.get()); - ASSERT_STREQ("spec 1", cInfo1.spec().get()); + ASSERT_STREQ("scope 1", cInfo1.spec().get()); ASSERT_STREQ("scope 1", data[1].scope().get()); ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get()); ASSERT_STREQ("activeCache 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get()); } +TEST(ServiceWorkerRegistrar, TestVersion3Migration) +{ + nsAutoCString buffer("3" "\n"); + + buffer.Append("^appId=123&inBrowser=1\n"); + buffer.Append("spec 0\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + buffer.Append("\n"); + buffer.Append("spec 1\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail"; + + RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest; + + nsresult rv = swr->TestReadData(); + ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; + + const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); + ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found"; + + const mozilla::ipc::PrincipalInfo& info0 = data[0].principal(); + ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; + const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal(); + + nsAutoCString suffix0; + cInfo0.attrs().CreateSuffix(suffix0); + + ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get()); + ASSERT_STREQ("scope 0", cInfo0.spec().get()); + ASSERT_STREQ("scope 0", data[0].scope().get()); + ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); + ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get()); + + const mozilla::ipc::PrincipalInfo& info1 = data[1].principal(); + ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; + const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal(); + + nsAutoCString suffix1; + cInfo1.attrs().CreateSuffix(suffix1); + + ASSERT_STREQ("", suffix1.get()); + ASSERT_STREQ("scope 1", cInfo1.spec().get()); + ASSERT_STREQ("scope 1", data[1].scope().get()); + ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get()); + ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get()); +} + +TEST(ServiceWorkerRegistrar, TestDedupeRead) +{ + nsAutoCString buffer("3" "\n"); + + // unique entries + buffer.Append("^appId=123&inBrowser=1\n"); + buffer.Append("spec 0\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + buffer.Append("\n"); + buffer.Append("spec 1\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + // dupe entries + buffer.Append("^appId=123&inBrowser=1\n"); + buffer.Append("spec 1\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + buffer.Append("^appId=123&inBrowser=1\n"); + buffer.Append("spec 2\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + buffer.Append("\n"); + buffer.Append("spec 3\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n"); + buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n"); + + ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail"; + + RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest; + + nsresult rv = swr->TestReadData(); + ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; + + const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); + ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found"; + + const mozilla::ipc::PrincipalInfo& info0 = data[0].principal(); + ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; + const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal(); + + nsAutoCString suffix0; + cInfo0.attrs().CreateSuffix(suffix0); + + ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get()); + ASSERT_STREQ("scope 0", cInfo0.spec().get()); + ASSERT_STREQ("scope 0", data[0].scope().get()); + ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get()); + ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get()); + + const mozilla::ipc::PrincipalInfo& info1 = data[1].principal(); + ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content"; + const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal(); + + nsAutoCString suffix1; + cInfo1.attrs().CreateSuffix(suffix1); + + ASSERT_STREQ("", suffix1.get()); + ASSERT_STREQ("scope 1", cInfo1.spec().get()); + ASSERT_STREQ("scope 1", data[1].scope().get()); + ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get()); + ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get()); +} + +TEST(ServiceWorkerRegistrar, TestDedupeWrite) +{ + { + RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest; + + for (int i = 0; i < 10; ++i) { + ServiceWorkerRegistrationData reg; + + reg.scope() = NS_LITERAL_CSTRING("scope write dedupe"); + reg.currentWorkerURL() = nsPrintfCString("currentWorkerURL write %d", i); + reg.cacheName() = + NS_ConvertUTF8toUTF16(nsPrintfCString("cacheName write %d", i)); + + nsAutoCString spec; + spec.AppendPrintf("spec write dedupe/%d", i); + reg.principal() = + mozilla::ipc::ContentPrincipalInfo(mozilla::PrincipalOriginAttributes(0, false), spec); + + swr->TestRegisterServiceWorker(reg); + } + + nsresult rv = swr->TestWriteData(); + ASSERT_EQ(NS_OK, rv) << "WriteData() should not fail"; + } + + RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest; + + nsresult rv = swr->TestReadData(); + ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail"; + + // Duplicate entries should be removed. + const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData(); + ASSERT_EQ((uint32_t)1, data.Length()) << "1 entry should be found"; + + ASSERT_EQ(data[0].principal().type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo); + const mozilla::ipc::ContentPrincipalInfo& cInfo = data[0].principal(); + + mozilla::PrincipalOriginAttributes attrs(0, false); + nsAutoCString suffix, expectSuffix; + attrs.CreateSuffix(expectSuffix); + cInfo.attrs().CreateSuffix(suffix); + + // Last entry passed to RegisterServiceWorkerInternal() should overwrite + // previous values. So expect "9" in values here. + ASSERT_STREQ(expectSuffix.get(), suffix.get()); + ASSERT_STREQ("scope write dedupe", cInfo.spec().get()); + ASSERT_STREQ("scope write dedupe", data[0].scope().get()); + ASSERT_STREQ("currentWorkerURL write 9", data[0].currentWorkerURL().get()); + ASSERT_STREQ("cacheName write 9", + NS_ConvertUTF16toUTF8(data[0].cacheName()).get()); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/dom/workers/test/head.js b/dom/workers/test/head.js new file mode 100644 index 0000000000..5f0c5c26ec --- /dev/null +++ b/dom/workers/test/head.js @@ -0,0 +1,91 @@ +/* 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"; + +const EXAMPLE_URL = "http://example.com/browser/dom/workers/test/"; +const FRAME_SCRIPT_URL = getRootDirectory(gTestPath) + "frame_script.js"; + +/** + * Add a tab with given `url`, and load a frame script in it. Returns a promise + * that will be resolved when the tab finished loading. + */ +function addTab(url) { + let tab = gBrowser.addTab(TAB_URL); + gBrowser.selectedTab = tab; + let linkedBrowser = tab.linkedBrowser; + linkedBrowser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false); + return new Promise(function (resolve) { + linkedBrowser.addEventListener("load", function onload() { + linkedBrowser.removeEventListener("load", onload, true); + resolve(tab); + }, true); + }); +} + +/** + * Remove the given `tab`. + */ +function removeTab(tab) { + gBrowser.removeTab(tab); +} + +let nextId = 0; + +/** + * Send a JSON RPC request to the frame script in the given `tab`, invoking the + * given `method` with the given `params`. Returns a promise that will be + * resolved with the result of the invocation. + */ +function jsonrpc(tab, method, params) { + let currentId = nextId++; + let messageManager = tab.linkedBrowser.messageManager; + messageManager.sendAsyncMessage("jsonrpc", { + id: currentId, + method: method, + params: params + }); + return new Promise(function (resolve, reject) { + messageManager.addMessageListener("jsonrpc", function listener(event) { + let { id, result, error } = event.data; + if (id !== currentId) { + return; + } + messageManager.removeMessageListener("jsonrpc", listener); + if (error) { + reject(error); + return; + } + resolve(result); + }); + }); +} + +/** + * Create a worker with the given `url` in the given `tab`. + */ +function createWorkerInTab(tab, url) { + return jsonrpc(tab, "createWorker", [url]); +} + +/** + * Terminate the worker with the given `url` in the given `tab`. + */ +function terminateWorkerInTab(tab, url) { + return jsonrpc(tab, "terminateWorker", [url]); +} + +/** + * Post the given `message` to the worker with the given `url` in the given + * `tab`. + */ +function postMessageToWorkerInTab(tab, url, message) { + return jsonrpc(tab, "postMessageToWorker", [url, message]); +} + +/** + * Disable the cache in the given `tab`. + */ +function disableCacheInTab(tab) { + return jsonrpc(tab, "disableCache", []); +} diff --git a/dom/workers/test/importScripts_3rdParty_worker.js b/dom/workers/test/importScripts_3rdParty_worker.js new file mode 100644 index 0000000000..ebf2d3b149 --- /dev/null +++ b/dom/workers/test/importScripts_3rdParty_worker.js @@ -0,0 +1,82 @@ +const workerURL = 'http://mochi.test:8888/tests/dom/workers/test/importScripts_3rdParty_worker.js'; + +onmessage = function(a) { + if (a.data.nested) { + var worker = new Worker(workerURL); + worker.onmessage = function(event) { + postMessage(event.data); + } + + worker.onerror = function(event) { + event.preventDefault(); + postMessage({ error: event instanceof ErrorEvent && + event.filename == workerURL }); + } + + a.data.nested = false; + worker.postMessage(a.data); + return; + } + + // This first URL will use the same origin of this script. + var sameOriginURL = new URL(a.data.url); + var fileName1 = 42; + + // This is cross-origin URL. + var crossOriginURL = new URL(a.data.url); + crossOriginURL.host = 'example.com'; + crossOriginURL.port = 80; + var fileName2 = 42; + + if (a.data.test == 'none') { + importScripts(crossOriginURL.href); + return; + } + + try { + importScripts(sameOriginURL.href); + } catch(e) { + if (!(e instanceof SyntaxError)) { + postMessage({ result: false }); + return; + } + + fileName1 = e.fileName; + } + + if (fileName1 != sameOriginURL.href || !fileName1) { + postMessage({ result: false }); + return; + } + + if (a.data.test == 'try') { + var exception; + try { + importScripts(crossOriginURL.href); + } catch(e) { + fileName2 = e.filename; + exception = e; + } + + postMessage({ result: fileName2 == workerURL && + exception.name == "NetworkError" && + exception.code == DOMException.NETWORK_ERR }); + return; + } + + if (a.data.test == 'eventListener') { + addEventListener("error", function(event) { + event.preventDefault(); + postMessage({result: event instanceof ErrorEvent && + event.filename == workerURL }); + }); + } + + if (a.data.test == 'onerror') { + onerror = function(...args) { + postMessage({result: args[1] == workerURL }); + } + } + + importScripts(crossOriginURL.href); +} diff --git a/dom/workers/test/mochitest.ini b/dom/workers/test/mochitest.ini index c8f5ffa470..990f21a5dc 100644 --- a/dom/workers/test/mochitest.ini +++ b/dom/workers/test/mochitest.ini @@ -115,6 +115,7 @@ support-files = sharedWorker_lifetime.js worker_fileReader.js fileapi_chromeScript.js + importScripts_3rdParty_worker.js !/dom/base/test/file_XHRResponseURL.js !/dom/base/test/file_XHRResponseURL.sjs !/dom/base/test/file_XHRResponseURL.text @@ -249,6 +250,7 @@ skip-if = buildapp == 'b2g' skip-if = (os == "win") || (os == "mac") || toolkit == 'android' #bug 798220 [test_xhrAbort.html] [test_referrer.html] +[test_importScripts_3rdparty.html] [test_sharedWorker_ports.html] [test_sharedWorker_lifetime.html] [test_fileReader.html] diff --git a/dom/workers/test/serviceworkers/test_match_all_client_id.html b/dom/workers/test/serviceworkers/test_match_all_client_id.html index c3cc5756a2..4c8ed9673d 100644 --- a/dom/workers/test/serviceworkers/test_match_all_client_id.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_id.html @@ -34,6 +34,7 @@ return new Promise(function(res, rej) { window.onmessage = function(e) { ok(e.data, "Same client id for multiple calls."); + is(e.origin, "http://mochi.test:8888", "Event should have the correct origin"); if (!e.data) { rej(); diff --git a/dom/workers/test/sharedWorker_ports.js b/dom/workers/test/sharedWorker_ports.js index a0d29e29a2..64672e6abb 100644 --- a/dom/workers/test/sharedWorker_ports.js +++ b/dom/workers/test/sharedWorker_ports.js @@ -17,6 +17,7 @@ onconnect = function(evt) { test: (evtFromPort2.data.type == "connected"), msg: "The original message received" }); port.postMessage({type: "finish"}); + close(); } } } diff --git a/dom/workers/test/test_importScripts_3rdparty.html b/dom/workers/test/test_importScripts_3rdparty.html new file mode 100644 index 0000000000..a3d73c5b55 --- /dev/null +++ b/dom/workers/test/test_importScripts_3rdparty.html @@ -0,0 +1,134 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<!DOCTYPE HTML> +<html> +<head> + <title>Test for 3rd party imported script and muted errors</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script type="text/javascript"> + +const workerURL = 'http://mochi.test:8888/tests/dom/workers/test/importScripts_3rdParty_worker.js'; + +var tests = [ + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onmessage = function(event) { + ok("result" in event.data && event.data.result, "It seems we don't share data!"); + next(); + }; + + worker.postMessage({ url: location.href, test: 'try', nested: false }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onmessage = function(event) { + ok("result" in event.data && event.data.result, "It seems we don't share data in nested workers!"); + next(); + }; + + worker.postMessage({ url: location.href, test: 'try', nested: true }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onmessage = function(event) { + ok("result" in event.data && event.data.result, "It seems we don't share data via eventListener!"); + next(); + }; + + worker.postMessage({ url: location.href, test: 'eventListener', nested: false }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onmessage = function(event) { + ok("result" in event.data && event.data.result, "It seems we don't share data in nested workers via eventListener!"); + next(); + }; + + worker.postMessage({ url: location.href, test: 'eventListener', nested: true }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onmessage = function(event) { + ok("result" in event.data && event.data.result, "It seems we don't share data via onerror!"); + next(); + }; + worker.onerror = function(event) { + event.preventDefault(); + } + + worker.postMessage({ url: location.href, test: 'onerror', nested: false }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onerror = function(event) { + event.preventDefault(); + ok(event instanceof ErrorEvent, "ErrorEvent received."); + is(event.filename, workerURL, "ErrorEvent.filename is correct"); + next(); + }; + + worker.postMessage({ url: location.href, test: 'none', nested: false }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.addEventListener("error", function(event) { + event.preventDefault(); + ok(event instanceof ErrorEvent, "ErrorEvent received."); + is(event.filename, workerURL, "ErrorEvent.filename is correct"); + next(); + }); + + worker.postMessage({ url: location.href, test: 'none', nested: false }); + }, + + function() { + var worker = new Worker("importScripts_3rdParty_worker.js"); + worker.onerror = function(event) { + ok(false, "No error should be received!"); + }; + + worker.onmessage = function(event) { + ok("error" in event.data && event.data.error, "The error has been fully received from a nested worker"); + next(); + }; + worker.postMessage({ url: location.href, test: 'none', nested: true }); + }, + + function() { + var url = URL.createObjectURL(new Blob(["%&%^&%^"])); + var worker = new Worker(url); + worker.onerror = function(event) { + event.preventDefault(); + ok(event instanceof ErrorEvent, "ErrorEvent received."); + next(); + }; + } +]; + +function next() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + var test = tests.shift(); + test(); +} + +SimpleTest.waitForExplicitFinish(); +next(); + +</script> +</body> +</html> diff --git a/dom/workers/test/test_sharedWorker_ports.html b/dom/workers/test/test_sharedWorker_ports.html index 8233b3f71f..32698ab527 100644 --- a/dom/workers/test/test_sharedWorker_ports.html +++ b/dom/workers/test/test_sharedWorker_ports.html @@ -28,6 +28,9 @@ } if (event.data.type == "finish") { + info("Finished!"); + ok(sw1.port, "The port still exists"); + sw1.port.foo = sw1; // Just a test to see if we leak. SimpleTest.finish(); } } diff --git a/dom/xbl/crashtests/crashtests.list b/dom/xbl/crashtests/crashtests.list index ab582fcdc3..81fdfe5fb8 100644 --- a/dom/xbl/crashtests/crashtests.list +++ b/dom/xbl/crashtests/crashtests.list @@ -4,8 +4,8 @@ load 226744-1.xhtml load 232095-1.xul load 277523-1.xhtml load 277950-1.xhtml -skip-if(Android||B2G||browserIsRemote) load 336744-1.html # no remote support for xul popups, bug 617653 -asserts(0-1) load 336960-1.html # maybe bug 429586 +skip-if(Android||B2G) load 336744-1.html # bug 1268050 +load 336960-1.html load 342954-1.xhtml load 342954-2.xhtml load 368276-1.xhtml diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index 830ad6e8f5..dfedab8edb 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -245,12 +245,7 @@ FieldGetterImpl(JSContext *cx, const JS::CallArgs& args) return true; } - JS::Rooted<JS::Value> v(cx); - if (!JS_GetPropertyById(cx, thisObj, id, &v)) { - return false; - } - args.rval().set(v); - return true; + return JS_GetPropertyById(cx, thisObj, id, args.rval()); } static bool diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp index 12c2a7eff6..3c1625cbeb 100644 --- a/dom/xbl/nsXBLPrototypeBinding.cpp +++ b/dom/xbl/nsXBLPrototypeBinding.cpp @@ -876,7 +876,8 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream, for (; interfaceCount > 0; interfaceCount--) { nsIID iid; - aStream->ReadID(&iid); + rv = aStream->ReadID(&iid); + NS_ENSURE_SUCCESS(rv, rv); mInterfaceTable.Put(iid, mBinding); } diff --git a/dom/xbl/nsXBLPrototypeHandler.cpp b/dom/xbl/nsXBLPrototypeHandler.cpp index 2f14df6530..1aeaed2cc1 100644 --- a/dom/xbl/nsXBLPrototypeHandler.cpp +++ b/dom/xbl/nsXBLPrototypeHandler.cpp @@ -25,6 +25,7 @@ #include "nsIDOMHTMLTextAreaElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsFocusManager.h" +#include "nsIFormControl.h" #include "nsIDOMEventListener.h" #include "nsPIDOMWindow.h" #include "nsPIWindowRoot.h" @@ -456,6 +457,10 @@ nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEv else controller = GetController(aTarget); // We're attached to the receiver possibly. + // We are the default action for this command. + // Stop any other default action from executing. + aEvent->PreventDefault(); + if (mEventName == nsGkAtoms::keypress && mDetail == nsIDOMKeyEvent::DOM_VK_SPACE && mMisc == 1) { @@ -475,40 +480,19 @@ nsXBLPrototypeHandler::DispatchXBLCommand(EventTarget* aTarget, nsIDOMEvent* aEv nsFocusManager::GetFocusedDescendant(windowToCheck, true, getter_AddRefs(focusedWindow)); } - bool isLink = false; - nsIContent *content = focusedContent; - - // if the focused element is a link then we do want space to - // scroll down. The focused element may be an element in a link, - // we need to check the parent node too. Only do this check if an - // element is focused and has a parent. - if (focusedContent && focusedContent->GetParent()) { - while (content) { - if (content->IsHTMLElement(nsGkAtoms::a)) { - isLink = true; - break; - } - - if (content->HasAttr(kNameSpaceID_XLink, nsGkAtoms::type)) { - isLink = content->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type, - nsGkAtoms::simple, eCaseMatters); - - if (isLink) { - break; - } - } - - content = content->GetParent(); - } + // If the focus is in an editable region, don't scroll. + if (focusedContent && focusedContent->IsEditable()) { + return NS_OK; + } - if (!isLink) + // If the focus is in a form control, don't scroll. + for (nsIContent* c = focusedContent; c; c = c->GetParent()) { + nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(c); + if (formControl) { return NS_OK; + } } } - - // We are the default action for this command. - // Stop any other default action from executing. - aEvent->PreventDefault(); if (controller) controller->DoCommand(command.get()); @@ -651,8 +635,8 @@ nsXBLPrototypeHandler::MouseEventMatched(nsIDOMMouseEvent* aMouseEvent) struct keyCodeData { const char* str; - size_t strlength; - uint32_t keycode; + uint16_t strlength; + uint16_t keycode; }; // All of these must be uppercase, since the function below does diff --git a/dom/xbl/nsXBLService.cpp b/dom/xbl/nsXBLService.cpp index 6b951a6c72..d37bca7224 100644 --- a/dom/xbl/nsXBLService.cpp +++ b/dom/xbl/nsXBLService.cpp @@ -817,6 +817,21 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI, return NS_OK; } +static bool +IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) +{ + if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { + return true; + } + + nsCOMPtr<nsIURI> uri; + aPrincipal->GetURI(getter_AddRefs(uri)); + NS_ENSURE_TRUE(uri, false); + + bool isChrome = false; + return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome; +} + nsresult nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, nsIDocument* aBoundDocument, @@ -830,7 +845,9 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement, "If we're doing a security check, we better have a document!"); *aResult = nullptr; - if (aOriginPrincipal && !nsContentUtils::IsSystemPrincipal(aOriginPrincipal)) { + // Allow XBL in unprivileged documents if it's specified in a privileged or + // chrome: stylesheet. This allows themes to specify XBL bindings. + if (aOriginPrincipal && !IsSystemOrChromeURLPrincipal(aOriginPrincipal)) { NS_ENSURE_TRUE(!aBoundDocument || aBoundDocument->AllowXULXBL(), NS_ERROR_XBL_BLOCKED); } diff --git a/dom/xbl/test/file_bug821850.xhtml b/dom/xbl/test/file_bug821850.xhtml index 6542998070..0d68a908f8 100644 --- a/dom/xbl/test/file_bug821850.xhtml +++ b/dom/xbl/test/file_bug821850.xhtml @@ -152,12 +152,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850 is(window.primitiveExpando, 11, "Can see waived expandos"); is(window.stringExpando, "stringExpando", "Can see waived expandos"); is(typeof window.objectExpando, "object", "object expando exists"); - checkThrows(function() window.objectExpando.foo); + checkThrows(() => window.objectExpando.foo); is(SpecialPowers.wrap(window.objectExpando).foo, 12, "SpecialPowers sees the right thing"); is(typeof window.globalExpando, "object", "Can see global object"); - checkThrows(function() window.globalExpando.win); + checkThrows(() => window.globalExpando.win); is(window.functionExpando(), "called", "XBL functions are callable"); - checkThrows(function() window.functionExpando.prop); + checkThrows(() => window.functionExpando.prop); // Inspect the bound element. var bound = document.getElementById('bound'); diff --git a/dom/xbl/test/test_bug379959.html b/dom/xbl/test/test_bug379959.html index 3ae172fc08..2b31b54c57 100644 --- a/dom/xbl/test/test_bug379959.html +++ b/dom/xbl/test/test_bug379959.html @@ -31,7 +31,6 @@ function receiveMessage(e) { is(e.origin, "http://mochi.test:8888", "wrong sender!"); - messages++; if (e.data.test === "dataIsAllowed") { is(e.data.result, 1, "data-url load should have succeeded"); @@ -57,8 +56,6 @@ window.addEventListener("message", receiveMessage, false); -var iframe = document.getElementById('f'); - function runTest() { // make sure data: is allowed document.getElementById('dataFrame').src = "file_bug379959_data.html"; diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index 5fe107db05..811ea755a6 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -96,16 +96,12 @@ NS_NewXMLContentSink(nsIXMLContentSink** aResult, } nsXMLContentSink::nsXMLContentSink() - : mConstrainSize(true), - mPrettyPrintXML(true) + : mPrettyPrintXML(true) { } nsXMLContentSink::~nsXMLContentSink() { - if (mText) { - PR_Free(mText); // Doesn't null out, unlike PR_FREEIF - } } nsresult @@ -475,7 +471,6 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content); sele->SetScriptLineNumber(aLineNumber); sele->SetCreatorParser(GetParser()); - mConstrainSize = false; } // XHTML needs some special attention @@ -552,7 +547,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent) if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) ) { - mConstrainSize = true; nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); if (mPreventScriptExecution) { @@ -753,26 +747,19 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) if (mTextLength != 0) { if (mLastTextNode) { - if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) { - mLastTextNodeSize = 0; - mLastTextNode = nullptr; - FlushText(aReleaseTextNode); - } else { - bool notify = HaveNotifiedForCurrentContent(); - // We could probably always increase mInNotification here since - // if AppendText doesn't notify it shouldn't trigger evil code. - // But just in case it does, we don't want to mask any notifications. - if (notify) { - ++mInNotification; - } - rv = mLastTextNode->AppendText(mText, mTextLength, notify); - if (notify) { - --mInNotification; - } - - mLastTextNodeSize += mTextLength; - mTextLength = 0; + bool notify = HaveNotifiedForCurrentContent(); + // We could probably always increase mInNotification here since + // if AppendText doesn't notify it shouldn't trigger evil code. + // But just in case it does, we don't want to mask any notifications. + if (notify) { + ++mInNotification; + } + rv = mLastTextNode->AppendText(mText, mTextLength, notify); + if (notify) { + --mInNotification; } + + mTextLength = 0; } else { RefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager); @@ -780,7 +767,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) // Set the text in the text node textContent->SetText(mText, mTextLength, false); - mLastTextNodeSize += mTextLength; mTextLength = 0; // Add text to its parent @@ -789,7 +775,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) } if (aReleaseTextNode) { - mLastTextNodeSize = 0; mLastTextNode = nullptr; } @@ -1417,41 +1402,19 @@ nsresult nsXMLContentSink::AddText(const char16_t* aText, int32_t aLength) { - // Create buffer when we first need it - if (0 == mTextSize) { - mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE); - if (nullptr == mText) { - return NS_ERROR_OUT_OF_MEMORY; - } - mTextSize = NS_ACCUMULATION_BUFFER_SIZE; - } - - // Copy data from string into our buffer; flush buffer when it fills up + // Copy data from string into our buffer; flush buffer when it fills up. int32_t offset = 0; while (0 != aLength) { - int32_t amount = mTextSize - mTextLength; + int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength; if (0 == amount) { - // XSLT wants adjacent textnodes merged. - if (mConstrainSize && !mXSLTProcessor) { - nsresult rv = FlushText(); - if (NS_OK != rv) { - return rv; - } - - amount = mTextSize - mTextLength; - } - else { - mTextSize += aLength; - mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); - if (nullptr == mText) { - mTextSize = 0; - - return NS_ERROR_OUT_OF_MEMORY; - } - - amount = aLength; + nsresult rv = FlushText(false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } + MOZ_ASSERT(mTextLength == 0); + amount = NS_ACCUMULATION_BUFFER_SIZE; } + if (amount > aLength) { amount = aLength; } diff --git a/dom/xml/nsXMLContentSink.h b/dom/xml/nsXMLContentSink.h index 9f66a20b9c..fbdac6633e 100644 --- a/dom/xml/nsXMLContentSink.h +++ b/dom/xml/nsXMLContentSink.h @@ -171,18 +171,15 @@ class nsXMLContentSink : public nsContentSink, nsCOMPtr<nsIContent> mDocElement; nsCOMPtr<nsIContent> mCurrentHead; // When set, we're in an XHTML <haed> - char16_t* mText; XMLContentSinkState mState; + // The length of the valid data in mText. int32_t mTextLength; - int32_t mTextSize; int32_t mNotifyLevel; nsCOMPtr<nsIContent> mLastTextNode; - int32_t mLastTextNodeSize; - uint8_t mConstrainSize : 1; uint8_t mPrettyPrintXML : 1; uint8_t mPrettyPrintHasSpecialRoot : 1; uint8_t mPrettyPrintHasFactoredElements : 1; @@ -194,6 +191,10 @@ class nsXMLContentSink : public nsContentSink, nsTArray<StackNode> mContentStack; nsCOMPtr<nsIDocumentTransformer> mXSLTProcessor; + + static const int NS_ACCUMULATION_BUFFER_SIZE = 4096; + // Our currently accumulated text that we have not flushed to a textnode yet. + char16_t mText[NS_ACCUMULATION_BUFFER_SIZE]; }; #endif // nsXMLContentSink_h__ diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp index 201f5d3954..33f7e919aa 100644 --- a/dom/xslt/base/txURIUtils.cpp +++ b/dom/xslt/base/txURIUtils.cpp @@ -17,6 +17,30 @@ using mozilla::LoadInfo; * A set of utilities for handling URIs **/ +/** + * Resolves the given href argument, using the given documentBase + * if necessary. + * The new resolved href will be appended to the given dest String +**/ +void URIUtils::resolveHref(const nsAString& href, const nsAString& base, + nsAString& dest) { + if (base.IsEmpty()) { + dest.Append(href); + return; + } + if (href.IsEmpty()) { + dest.Append(base); + return; + } + nsCOMPtr<nsIURI> pURL; + nsAutoString resultHref; + nsresult result = NS_NewURI(getter_AddRefs(pURL), base); + if (NS_SUCCEEDED(result)) { + NS_MakeAbsoluteURI(resultHref, href, pURL); + dest.Append(resultHref); + } +} //-- resolveHref + // static void URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode) diff --git a/dom/xslt/base/txURIUtils.h b/dom/xslt/base/txURIUtils.h index 188f7224df..ca38538a8b 100644 --- a/dom/xslt/base/txURIUtils.h +++ b/dom/xslt/base/txURIUtils.h @@ -23,6 +23,14 @@ class URIUtils { * Reset the given document with the document of the source node */ static void ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode); + + /** + * Resolves the given href argument, using the given documentBase + * if necessary. + * The new resolved href will be appended to the given dest String + **/ + static void resolveHref(const nsAString& href, const nsAString& base, + nsAString& dest); }; //-- URIUtils /* */ diff --git a/dom/xslt/nsIXSLTProcessorPrivate.idl b/dom/xslt/nsIXSLTProcessorPrivate.idl index 9212f70fd3..d88320cef2 100644 --- a/dom/xslt/nsIXSLTProcessorPrivate.idl +++ b/dom/xslt/nsIXSLTProcessorPrivate.idl @@ -5,16 +5,9 @@ #include "nsISupports.idl" -[scriptable, uuid(75d14f5d-293d-4872-8a26-e79268de592f)] +[scriptable, uuid(b8d727f7-67f4-4dc1-a318-ec0c87280816)] interface nsIXSLTProcessorPrivate : nsISupports { - /** - * This needs to be called if the XSLTProcessor is instantiated - * through the XPCOM registry (i.e. using do_createInstance) and the - * stylesheet uses xsl:import/xsl:include or the document() xpath function. - */ - void init(in nsISupports global); - /** * Disables all loading of external documents, such as from * <xsl:import> and document() diff --git a/dom/xslt/tests/mochitest/file_bug1222624.xml b/dom/xslt/tests/mochitest/file_bug1222624.xml deleted file mode 100644 index c8290a3380..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml-stylesheet type="text/xsl" href="file_bug1222624.xsl"?> -<root> - <load>file_bug1222624_data2.xml</load> -</root> diff --git a/dom/xslt/tests/mochitest/file_bug1222624.xsl b/dom/xslt/tests/mochitest/file_bug1222624.xsl deleted file mode 100644 index cf954c4fc8..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624.xsl +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:import href="file_bug1222624_sub.xsl"/> - <xsl:template match="/root"> - <result> - <xsl:call-template name="external"/> - <xsl:value-of select="document('file_bug1222624_data1.xml')"/> - <xsl:text>!</xsl:text> - <xsl:value-of select="document(load)"/> - </result> - </xsl:template> -</xsl:stylesheet> diff --git a/dom/xslt/tests/mochitest/file_bug1222624_data1.xml b/dom/xslt/tests/mochitest/file_bug1222624_data1.xml deleted file mode 100644 index f50fdbc1cb..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624_data1.xml +++ /dev/null @@ -1 +0,0 @@ -<data>doc1</data> diff --git a/dom/xslt/tests/mochitest/file_bug1222624_data2.xml b/dom/xslt/tests/mochitest/file_bug1222624_data2.xml deleted file mode 100644 index e6228590c1..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624_data2.xml +++ /dev/null @@ -1 +0,0 @@ -<data>doc2</data> diff --git a/dom/xslt/tests/mochitest/file_bug1222624_sub.xsl b/dom/xslt/tests/mochitest/file_bug1222624_sub.xsl deleted file mode 100644 index 189031a1f3..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624_sub.xsl +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:include href="file_bug1222624_sub_sub.xsl"/> -</xsl:stylesheet> diff --git a/dom/xslt/tests/mochitest/file_bug1222624_sub_sub.xsl b/dom/xslt/tests/mochitest/file_bug1222624_sub_sub.xsl deleted file mode 100644 index 881e4c55bc..0000000000 --- a/dom/xslt/tests/mochitest/file_bug1222624_sub_sub.xsl +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:template name="external"> - <external/> - </xsl:template> -</xsl:stylesheet> diff --git a/dom/xslt/tests/mochitest/mochitest.ini b/dom/xslt/tests/mochitest/mochitest.ini index 08ae189808..53a6d001cd 100644 --- a/dom/xslt/tests/mochitest/mochitest.ini +++ b/dom/xslt/tests/mochitest/mochitest.ini @@ -16,7 +16,5 @@ [test_bug667315.html] [test_bug1135764.html] support-files = file_bug1135764.xml file_bug1135764.xsl -[test_bug1222624.html] -support-files = file_bug1222624.xml file_bug1222624.xsl file_bug1222624_sub.xsl file_bug1222624_sub_sub.xsl file_bug1222624_data1.xml file_bug1222624_data2.xml [test_exslt_regex.html] [test_parameter.html] diff --git a/dom/xslt/tests/mochitest/test_bug1222624.html b/dom/xslt/tests/mochitest/test_bug1222624.html deleted file mode 100644 index be016a4701..0000000000 --- a/dom/xslt/tests/mochitest/test_bug1222624.html +++ /dev/null @@ -1,50 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1222624 ---> -<head> - <title>Test for Bug 1222624</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1222624">Mozilla Bug 1222624</a> -<p id="display"></p> -<iframe id="frame"></iframe> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -/** Test for Bug 1222624 **/ - -const transformRes = '<?xml version="1.0" encoding="UTF-8"?>\n<result><external/>doc1!doc2</result>'; - -xhr = new XMLHttpRequest(); -xhr.open("GET", "file_bug1222624.xml", false); -xhr.send(); -var xmlDoc = xhr.responseXML; - -xhr.open("GET", "file_bug1222624.xsl", false); -xhr.send(); -var xslDoc = xhr.responseXML; - -var processor = new XSLTProcessor; -processor.importStylesheet(xslDoc); -var apiRes = new XMLSerializer().serializeToString(processor.transformToDocument(xmlDoc)); - -is(apiRes, transformRes, "API transformation correct"); - -SimpleTest.waitForExplicitFinish(); - -var frame = $("frame"); -frame.src = "file_bug1222624.xml"; -frame.onload = function () { - var piRes = new XMLSerializer().serializeToString(frame.contentDocument); - is(piRes, transformRes, "processing-instruction transformation correct"); - SimpleTest.finish(); -} - -</script> -</pre> -</body> -</html> diff --git a/dom/xslt/xml/txXMLParser.cpp b/dom/xslt/xml/txXMLParser.cpp index 8882cdfbf8..0cf281f2cf 100644 --- a/dom/xslt/xml/txXMLParser.cpp +++ b/dom/xslt/xml/txXMLParser.cpp @@ -15,14 +15,20 @@ #include "nsIPrincipal.h" nsresult -txParseDocumentFromURI(nsIURI* aUri, - nsIDocument* aLoadingDocument, +txParseDocumentFromURI(const nsAString& aHref, + const txXPathNode& aLoader, nsAString& aErrMsg, txXPathNode** aResult) { + NS_ENSURE_ARG_POINTER(aResult); *aResult = nullptr; + nsCOMPtr<nsIURI> documentURI; + nsresult rv = NS_NewURI(getter_AddRefs(documentURI), aHref); + NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup(); + nsIDocument* loaderDocument = txXPathNativeNode::getDocument(aLoader); + + nsCOMPtr<nsILoadGroup> loadGroup = loaderDocument->GetDocumentLoadGroup(); // For the system principal loaderUri will be null here, which is good // since that means that chrome documents can load any uri. @@ -30,24 +36,20 @@ txParseDocumentFromURI(nsIURI* aUri, // Raw pointer, we want the resulting txXPathNode to hold a reference to // the document. nsIDOMDocument* theDocument = nullptr; - nsAutoSyncOperation sync(aLoadingDocument); - nsresult rv = - nsSyncLoadService::LoadDocument(aUri, - nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - aLoadingDocument->NodePrincipal(), - nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, - loadGroup, - true, - aLoadingDocument->GetReferrerPolicy(), - &theDocument); + nsAutoSyncOperation sync(loaderDocument); + rv = nsSyncLoadService::LoadDocument(documentURI, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, + loaderDocument->NodePrincipal(), + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + loadGroup, true, + loaderDocument->GetReferrerPolicy(), + &theDocument); if (NS_FAILED(rv)) { aErrMsg.AppendLiteral("Document load of "); - nsAutoCString spec; - aUri->GetSpec(spec); - aErrMsg.Append(NS_ConvertUTF8toUTF16(spec)); + aErrMsg.Append(aHref); aErrMsg.AppendLiteral(" failed."); - return rv; + return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE; } *aResult = txXPathNativeNode::createXPathNode(theDocument); diff --git a/dom/xslt/xml/txXMLParser.h b/dom/xslt/xml/txXMLParser.h index 2153d90dc1..fea9defe34 100644 --- a/dom/xslt/xml/txXMLParser.h +++ b/dom/xslt/xml/txXMLParser.h @@ -9,8 +9,6 @@ #include "txCore.h" class txXPathNode; -class nsIURI; -class nsIDocument; /** * API to load XML files into DOM datastructures. @@ -22,9 +20,7 @@ class nsIDocument; * of the document aLoader. */ extern "C" nsresult -txParseDocumentFromURI(nsIURI* aUri, - nsIDocument* aLoadingDocument, - nsAString& aErrMsg, - txXPathNode** aResult); +txParseDocumentFromURI(const nsAString& aHref, const txXPathNode& aLoader, + nsAString& aErrMsg, txXPathNode** aResult); #endif diff --git a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp index de0a84c7d7..64ec7071fa 100644 --- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp +++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp @@ -563,9 +563,9 @@ txXPathNodeUtils::getXSLTId(const txXPathNode& aNode, /* static */ void -txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsIURI** aUri) +txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsAString& aURI) { - *aUri = aNode.mNode->GetBaseURI().take(); + aNode.mNode->GetBaseURI(aURI); } /* static */ diff --git a/dom/xslt/xpath/txXPathTreeWalker.h b/dom/xslt/xpath/txXPathTreeWalker.h index 1c66f2c8ba..26cb42ddd4 100644 --- a/dom/xslt/xpath/txXPathTreeWalker.h +++ b/dom/xslt/xpath/txXPathTreeWalker.h @@ -93,7 +93,7 @@ class txXPathNodeUtils static nsresult getXSLTId(const txXPathNode& aNode, const txXPathNode& aBase, nsAString& aResult); static void release(txXPathNode* aNode); - static void getBaseURI(const txXPathNode& aNode, nsIURI** aURI); + static void getBaseURI(const txXPathNode& aNode, nsAString& aURI); static int comparePosition(const txXPathNode& aNode, const txXPathNode& aOtherNode); static bool localNameEquals(const txXPathNode& aNode, diff --git a/dom/xslt/xslt/txDocumentFunctionCall.cpp b/dom/xslt/xslt/txDocumentFunctionCall.cpp index 1de5cf75c8..3ea7a83b24 100644 --- a/dom/xslt/xslt/txDocumentFunctionCall.cpp +++ b/dom/xslt/xslt/txDocumentFunctionCall.cpp @@ -13,33 +13,46 @@ #include "txXSLTFunctions.h" #include "txExecutionState.h" #include "txURIUtils.h" -#include "nsIURI.h" -#include "nsNetUtil.h" + +/* + * Creates a new DocumentFunctionCall. + */ +DocumentFunctionCall::DocumentFunctionCall(const nsAString& aBaseURI) + : mBaseURI(aBaseURI) +{ +} static void -retrieveNode(txExecutionState* aExecutionState, - const nsAString& aUri, - nsIURI* aBaseUri, - txNodeSet* aNodeSet) +retrieveNode(txExecutionState* aExecutionState, const nsAString& aUri, + const nsAString& aBaseUri, txNodeSet* aNodeSet) { - nsCOMPtr<nsIURI> uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri, nullptr, aBaseUri); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; + nsAutoString absUrl; + URIUtils::resolveHref(aUri, aBaseUri, absUrl); + + int32_t hash = absUrl.RFindChar(char16_t('#')); + uint32_t urlEnd, fragStart, fragEnd; + if (hash == kNotFound) { + urlEnd = absUrl.Length(); + fragStart = 0; + fragEnd = 0; + } + else { + urlEnd = hash; + fragStart = hash + 1; + fragEnd = absUrl.Length(); } - nsAutoCString frag; - uri->GetRef(frag); - uri->SetRef(EmptyCString()); + nsDependentSubstring docUrl(absUrl, 0, urlEnd); + nsDependentSubstring frag(absUrl, fragStart, fragEnd); - const txXPathNode* loadNode = aExecutionState->retrieveDocument(uri); + const txXPathNode* loadNode = aExecutionState->retrieveDocument(docUrl); if (loadNode) { if (frag.IsEmpty()) { aNodeSet->add(*loadNode); } else { txXPathTreeWalker walker(*loadNode); - if (walker.moveToElementById(NS_ConvertUTF8toUTF16(frag))) { + if (walker.moveToElementById(frag)) { aNodeSet->add(walker.getCurrentPosition()); } } @@ -74,7 +87,7 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext, rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult1)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIURI> baseURI; + nsAutoString baseURI; bool baseURISet = false; if (mParams.Length() == 2) { @@ -91,8 +104,7 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext, baseURISet = true; if (!nodeSet2->isEmpty()) { - txXPathNodeUtils::getBaseURI(nodeSet2->get(0), - getter_AddRefs(baseURI)); + txXPathNodeUtils::getBaseURI(nodeSet2->get(0), baseURI); } } @@ -109,7 +121,7 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext, if (!baseURISet) { // if the second argument wasn't specified, use // the baseUri of node itself - txXPathNodeUtils::getBaseURI(node, getter_AddRefs(baseURI)); + txXPathNodeUtils::getBaseURI(node, baseURI); } retrieveNode(es, uriStr, baseURI, nodeSet); } @@ -122,8 +134,8 @@ DocumentFunctionCall::evaluate(txIEvalContext* aContext, // The first argument is not a NodeSet nsAutoString uriStr; exprResult1->stringValue(uriStr); - nsIURI* base = baseURISet ? baseURI.get() : mBaseURI.get(); - retrieveNode(es, uriStr, base, nodeSet); + const nsAString* base = baseURISet ? &baseURI : &mBaseURI; + retrieveNode(es, uriStr, *base, nodeSet); NS_ADDREF(*aResult = nodeSet); diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index 527e5a4a24..44139ef34e 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -21,28 +21,27 @@ txLoadedDocumentsHash::init(txXPathNode* aSourceDocument) { mSourceDocument = aSourceDocument; - nsCOMPtr<nsIURI> baseURI; - txXPathNodeUtils::getBaseURI(*mSourceDocument, getter_AddRefs(baseURI)); + nsAutoString baseURI; + txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI); - LookupOrAdd(baseURI)->mDocument = mSourceDocument; + PutEntry(baseURI)->mDocument = mSourceDocument; } txLoadedDocumentsHash::~txLoadedDocumentsHash() { if (mSourceDocument) { - nsCOMPtr<nsIURI> baseURI; - txXPathNodeUtils::getBaseURI(*mSourceDocument, getter_AddRefs(baseURI)); + nsAutoString baseURI; + txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI); - txLoadedDocumentInfo* info = Get(baseURI); - if (info) { - delete info->mDocument.forget(); + txLoadedDocumentEntry* entry = GetEntry(baseURI); + if (entry) { + delete entry->mDocument.forget(); } } } txExecutionState::txExecutionState(txStylesheet* aStylesheet, - bool aDisableLoads, - nsIDocument* aLoadingDocument) + bool aDisableLoads) : mOutputHandler(nullptr), mResultHandler(nullptr), mStylesheet(aStylesheet), @@ -52,7 +51,6 @@ txExecutionState::txExecutionState(txStylesheet* aStylesheet, mEvalContext(nullptr), mInitialEvalContext(nullptr), mGlobalParams(nullptr), - mLoadingDocument(aLoadingDocument), mKeyHash(aStylesheet->getKeyMap()), mDisableLoads(aDisableLoads) { @@ -408,48 +406,41 @@ txExecutionState::getEvalContext() } const txXPathNode* -txExecutionState::retrieveDocument(nsIURI* aUri) +txExecutionState::retrieveDocument(const nsAString& aUri) { -#ifdef DEBUG - { - bool hasFrag; - aUri->GetHasRef(&hasFrag); - MOZ_ASSERT(!hasFrag, "Remove the fragment"); - } -#endif + NS_ASSERTION(!aUri.Contains(char16_t('#')), + "Remove the fragment."); - if (mDisableLoads || !mLoadingDocument) { + if (mDisableLoads) { return nullptr; } - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Debug)) { - nsAutoCString spec; - aUri->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Debug, - ("Retrieve Document %s", spec.get())); - } + MOZ_LOG(txLog::xslt, LogLevel::Debug, + ("Retrieve Document %s", NS_LossyConvertUTF16toASCII(aUri).get())); // try to get already loaded document - txLoadedDocumentInfo* info = mLoadedDocuments.LookupOrAdd(aUri); + txLoadedDocumentEntry *entry = mLoadedDocuments.PutEntry(aUri); + if (!entry) { + return nullptr; + } - if (!info->mDocument && !info->LoadingFailed()) { + if (!entry->mDocument && !entry->LoadingFailed()) { // open URI nsAutoString errMsg; - info->mLoadResult = - txParseDocumentFromURI(aUri, mLoadingDocument, - errMsg, getter_Transfers(info->mDocument)); + // XXX we should get the loader from the actual node + // triggering the load, but this will do for the time being + entry->mLoadResult = + txParseDocumentFromURI(aUri, *mLoadedDocuments.mSourceDocument, + errMsg, getter_Transfers(entry->mDocument)); - if (info->LoadingFailed()) { - nsAutoCString spec; - aUri->GetSpec(spec); + if (entry->LoadingFailed()) { receiveError(NS_LITERAL_STRING("Couldn't load document '") + - NS_ConvertUTF8toUTF16(spec) + - NS_LITERAL_STRING("': ") + errMsg, - info->mLoadResult); + aUri + NS_LITERAL_STRING("': ") + errMsg, + entry->mLoadResult); } } - return info->mDocument; + return entry->mDocument; } nsresult diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h index 63b48c16dd..ac87dfc434 100644 --- a/dom/xslt/xslt/txExecutionState.h +++ b/dom/xslt/xslt/txExecutionState.h @@ -17,19 +17,24 @@ #include "txStylesheet.h" #include "txXPathTreeWalker.h" #include "nsTArray.h" -#include "nsURIHashKey.h" class txAOutputHandlerFactory; class txAXMLEventHandler; class txInstruction; -class txLoadedDocumentInfo +class txLoadedDocumentEntry : public nsStringHashKey { public: - explicit txLoadedDocumentInfo() : mLoadResult(NS_OK) + explicit txLoadedDocumentEntry(KeyTypePointer aStr) : nsStringHashKey(aStr), + mLoadResult(NS_OK) { } - ~txLoadedDocumentInfo() + txLoadedDocumentEntry(const txLoadedDocumentEntry& aToCopy) + : nsStringHashKey(aToCopy) + { + NS_ERROR("We're horked."); + } + ~txLoadedDocumentEntry() { if (mDocument) { txXPathNodeUtils::release(mDocument); @@ -47,11 +52,11 @@ class txLoadedDocumentInfo nsresult mLoadResult; }; -class txLoadedDocumentsHash : public nsClassHashtable<nsURIHashKey, txLoadedDocumentInfo> +class txLoadedDocumentsHash : public nsTHashtable<txLoadedDocumentEntry> { public: txLoadedDocumentsHash() - : nsClassHashtable<nsURIHashKey, txLoadedDocumentInfo>(4), + : nsTHashtable<txLoadedDocumentEntry>(4), mSourceDocument(nullptr) { } @@ -67,8 +72,7 @@ class txLoadedDocumentsHash : public nsClassHashtable<nsURIHashKey, txLoadedDocu class txExecutionState : public txIMatchContext { public: - txExecutionState(txStylesheet* aStylesheet, bool aDisableLoads, - nsIDocument* aLoaderDocument); + txExecutionState(txStylesheet* aStylesheet, bool aDisableLoads); ~txExecutionState(); nsresult init(const txXPathNode& aNode, txOwningExpandedNameMap<txIGlobalParameter>* aGlobalParams); @@ -113,7 +117,7 @@ class txExecutionState : public txIMatchContext // state-getting functions txIEvalContext* getEvalContext(); - const txXPathNode* retrieveDocument(nsIURI* aUri); + const txXPathNode* retrieveDocument(const nsAString& aUri); nsresult getKeyNodes(const txExpandedName& aKeyName, const txXPathNode& aRoot, const nsAString& aKeyValue, bool aIndexIfNotFound, @@ -167,7 +171,6 @@ class txExecutionState : public txIMatchContext //Document* mRTFDocument; txOwningExpandedNameMap<txIGlobalParameter>* mGlobalParams; - nsCOMPtr<nsIDocument> mLoadingDocument; txLoadedDocumentsHash mLoadedDocuments; txKeyHash mKeyHash; RefPtr<txResultRecycler> mRecycler; diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp index 2e4768fb3d..e00b354a4a 100644 --- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -257,16 +257,6 @@ txStylesheetSink::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); - nsCOMPtr<nsIPrincipal> channelPrincipal; - nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal( - channel, getter_AddRefs(channelPrincipal)); - mCompiler->setPrincipal(channelPrincipal); - - nsCOMPtr<nsIURI> baseURI; - nsresult rv = NS_GetFinalChannelURI(channel, getter_AddRefs(baseURI)); - NS_ENSURE_SUCCESS(rv, rv); - mCompiler->setBaseURI(baseURI); - // check channel's charset... nsAutoCString charsetVal; nsAutoCString charset; @@ -385,8 +375,9 @@ class txCompileObserver final : public txACompileObserver TX_DECL_ACOMPILEOBSERVER NS_INLINE_DECL_REFCOUNTING(txCompileObserver) - nsresult startLoad(nsIURI* aUri, nsIPrincipal* aSourcePrincipal, - txStylesheetCompiler* aCompiler); + nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, + nsIPrincipal* aSourcePrincipal, + ReferrerPolicy aReferrerPolicy); private: RefPtr<txMozillaXSLTProcessor> mProcessor; @@ -409,15 +400,30 @@ txCompileObserver::txCompileObserver(txMozillaXSLTProcessor* aProcessor, } nsresult -txCompileObserver::loadURI(nsIURI* aUri, - nsIPrincipal* aReferrerPrincipal, +txCompileObserver::loadURI(const nsAString& aUri, + const nsAString& aReferrerUri, + ReferrerPolicy aReferrerPolicy, txStylesheetCompiler* aCompiler) { - if (mProcessor->IsLoadDisabled() || !mLoaderDocument) { + if (mProcessor->IsLoadDisabled()) { return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR; } - return startLoad(aUri, aReferrerPrincipal, aCompiler); + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIURI> referrerUri; + rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIPrincipal> referrerPrincipal; + rv = nsContentUtils::GetSecurityManager()-> + GetSimpleCodebasePrincipal(referrerUri, + getter_AddRefs(referrerPrincipal)); + NS_ENSURE_SUCCESS(rv, rv); + + return startLoad(uri, aCompiler, referrerPrincipal, aReferrerPolicy); } void @@ -435,11 +441,10 @@ txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler, } nsresult -txCompileObserver::startLoad(nsIURI* aUri, nsIPrincipal* aReferrerPrincipal, - txStylesheetCompiler* aCompiler) +txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, + nsIPrincipal* aReferrerPrincipal, + ReferrerPolicy aReferrerPolicy) { - MOZ_ASSERT(aReferrerPrincipal); - nsCOMPtr<nsILoadGroup> loadGroup = mLoaderDocument->GetDocumentLoadGroup(); if (!loadGroup) { return NS_ERROR_FAILURE; @@ -468,8 +473,7 @@ txCompileObserver::startLoad(nsIURI* aUri, nsIPrincipal* aReferrerPrincipal, nsCOMPtr<nsIURI> referrerURI; aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI)); if (referrerURI) { - httpChannel->SetReferrerWithPolicy(referrerURI, - mLoaderDocument->GetReferrerPolicy()); + httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy); } } @@ -477,6 +481,7 @@ txCompileObserver::startLoad(nsIURI* aUri, nsIPrincipal* aReferrerPrincipal, NS_ENSURE_SUCCESS(rv, rv); RefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser); + NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY); channel->SetNotificationCallbacks(sink); @@ -489,26 +494,24 @@ txCompileObserver::startLoad(nsIURI* aUri, nsIPrincipal* aReferrerPrincipal, nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, - nsIDocument* aLoaderDocument) + nsIDocument* aLoaderDocument, ReferrerPolicy aReferrerPolicy) { - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsAutoCString spec; - aUri->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("TX_LoadSheet: %s\n", spec.get())); - } + nsIPrincipal* principal = aLoaderDocument->NodePrincipal(); + + nsAutoCString spec; + aUri->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, ("TX_LoadSheet: %s\n", spec.get())); RefPtr<txCompileObserver> observer = new txCompileObserver(aProcessor, aLoaderDocument); - - nsAutoCString fragment; - aUri->GetRef(fragment); + NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY); RefPtr<txStylesheetCompiler> compiler = - new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), observer); + new txStylesheetCompiler(NS_ConvertUTF8toUTF16(spec), aReferrerPolicy, + observer); + NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); - return observer->startLoad(aUri, aLoaderDocument->NodePrincipal(), - compiler); + return observer->startLoad(aUri, compiler, principal, aReferrerPolicy); } /** @@ -582,11 +585,7 @@ handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) class txSyncCompileObserver final : public txACompileObserver { public: - explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor, - nsIDocument* aLoaderDocument) - : mProcessor(aProcessor), - mLoaderDocument(aLoaderDocument) - {} + explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor); TX_DECL_ACOMPILEOBSERVER NS_INLINE_DECL_REFCOUNTING(txSyncCompileObserver) @@ -598,43 +597,60 @@ class txSyncCompileObserver final : public txACompileObserver } RefPtr<txMozillaXSLTProcessor> mProcessor; - nsCOMPtr<nsIDocument> mLoaderDocument; }; +txSyncCompileObserver::txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor) + : mProcessor(aProcessor) +{ +} + nsresult -txSyncCompileObserver::loadURI(nsIURI* aUri, - nsIPrincipal* aReferrerPrincipal, +txSyncCompileObserver::loadURI(const nsAString& aUri, + const nsAString& aReferrerUri, + ReferrerPolicy aReferrerPolicy, txStylesheetCompiler* aCompiler) { - MOZ_ASSERT(aReferrerPrincipal); - - if (mProcessor->IsLoadDisabled() || !mLoaderDocument) { + if (mProcessor->IsLoadDisabled()) { return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR; } - nsAutoSyncOperation sync(mLoaderDocument); + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIURI> referrerUri; + rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIPrincipal> referrerPrincipal; + rv = nsContentUtils::GetSecurityManager()-> + GetSimpleCodebasePrincipal(referrerUri, + getter_AddRefs(referrerPrincipal)); + NS_ENSURE_SUCCESS(rv, rv); + + // This is probably called by js, a loadGroup for the channel doesn't + // make sense. + nsCOMPtr<nsINode> source; + if (mProcessor) { + source = + do_QueryInterface(mProcessor->GetSourceContentModel()); + } + nsAutoSyncOperation sync(source ? source->OwnerDoc() : nullptr); nsCOMPtr<nsIDOMDocument> document; - nsCOMPtr<nsILoadGroup> loadGroup = mLoaderDocument->GetDocumentLoadGroup(); - nsresult rv = - nsSyncLoadService::LoadDocument(aUri, - nsIContentPolicy::TYPE_XSLT, - aReferrerPrincipal, - nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, - loadGroup, - false, - mLoaderDocument->GetReferrerPolicy(), - getter_AddRefs(document)); + rv = nsSyncLoadService::LoadDocument(uri, nsIContentPolicy::TYPE_XSLT, + referrerPrincipal, + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + nullptr, false, + aReferrerPolicy, + getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDocument> doc = do_QueryInterface(document); - nsCOMPtr<nsIURI> baseURI = doc->GetBaseURI(); - aCompiler->setBaseURI(baseURI); - aCompiler->setPrincipal(doc->NodePrincipal()); rv = handleNode(doc, aCompiler); if (NS_FAILED(rv)) { nsAutoCString spec; - aUri->GetSpec(spec); + uri->GetSpec(spec); aCompiler->cancel(rv, nullptr, NS_ConvertUTF8toUTF16(spec).get()); return rv; } @@ -651,20 +667,46 @@ void txSyncCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler, } nsresult -TX_CompileStylesheet(nsINode* aNode, - nsIDocument* aLoaderDocument, - txMozillaXSLTProcessor* aProcessor, +TX_CompileStylesheet(nsINode* aNode, txMozillaXSLTProcessor* aProcessor, txStylesheet** aStylesheet) { + // If we move GetBaseURI to nsINode this can be simplified. + nsCOMPtr<nsIDocument> doc = aNode->OwnerDoc(); + + nsCOMPtr<nsIURI> uri; + if (aNode->IsNodeOfType(nsINode::eCONTENT)) { + uri = static_cast<nsIContent*>(aNode)->GetBaseURI(); + } + else { + NS_ASSERTION(aNode->IsNodeOfType(nsINode::eDOCUMENT), "not a doc"); + uri = static_cast<nsIDocument*>(aNode)->GetBaseURI(); + } + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); + + nsAutoCString spec; + uri->GetSpec(spec); + NS_ConvertUTF8toUTF16 baseURI(spec); + + nsIURI* docUri = doc->GetDocumentURI(); + NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE); + + // We need to remove the ref, a URI with a ref would mean that we have an + // embedded stylesheet. + docUri->CloneIgnoringRef(getter_AddRefs(uri)); + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); + + uri->GetSpec(spec); + NS_ConvertUTF8toUTF16 stylesheetURI(spec); + RefPtr<txSyncCompileObserver> obs = - new txSyncCompileObserver(aProcessor, aLoaderDocument); + new txSyncCompileObserver(aProcessor); + NS_ENSURE_TRUE(obs, NS_ERROR_OUT_OF_MEMORY); RefPtr<txStylesheetCompiler> compiler = - new txStylesheetCompiler(EmptyString(), obs); + new txStylesheetCompiler(stylesheetURI, doc->GetReferrerPolicy(), obs); + NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); - nsCOMPtr<nsIURI> baseURI = aNode->GetBaseURI(); compiler->setBaseURI(baseURI); - compiler->setPrincipal(aNode->NodePrincipal()); nsresult rv = handleNode(aNode, compiler); if (NS_FAILED(rv)) { diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index d29fc6046e..daa585fd00 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -357,20 +357,6 @@ txMozillaXSLTProcessor::txMozillaXSLTProcessor(nsISupports* aOwner) { } -NS_IMETHODIMP -txMozillaXSLTProcessor::Init(nsISupports* aOwner) -{ - mOwner = aOwner; - if (nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aOwner)) { - if (win->IsOuterWindow()) { - // Must be bound to inner window, innerize if necessary. - mOwner = win->GetCurrentInnerWindow(); - } - } - - return NS_OK; -} - txMozillaXSLTProcessor::~txMozillaXSLTProcessor() { if (mStylesheetDocument) { @@ -612,7 +598,7 @@ txMozillaXSLTProcessor::ImportStylesheet(nsIDOMNode *aStyle) styleNode->IsNodeOfType(nsINode::eDOCUMENT)), NS_ERROR_INVALID_ARG); - nsresult rv = TX_CompileStylesheet(styleNode, getLoaderDoc(), this, + nsresult rv = TX_CompileStylesheet(styleNode, this, getter_AddRefs(mStylesheet)); // XXX set up exception context, bug 204658 NS_ENSURE_SUCCESS(rv, rv); @@ -667,7 +653,7 @@ txMozillaXSLTProcessor::TransformToDoc(nsIDOMDocument **aResult, sourceDOMDocument = do_QueryInterface(mSource); } - txExecutionState es(mStylesheet, IsLoadDisabled(), getLoaderDoc()); + txExecutionState es(mStylesheet, IsLoadDisabled()); // XXX Need to add error observers @@ -735,7 +721,7 @@ txMozillaXSLTProcessor::TransformToFragment(nsIDOMNode *aSource, return NS_ERROR_OUT_OF_MEMORY; } - txExecutionState es(mStylesheet, IsLoadDisabled(), getLoaderDoc()); + txExecutionState es(mStylesheet, IsLoadDisabled()); // XXX Need to add error observers @@ -1050,7 +1036,12 @@ NS_IMETHODIMP txMozillaXSLTProcessor::LoadStyleSheet(nsIURI* aUri, nsIDocument* aLoaderDocument) { - nsresult rv = TX_LoadSheet(aUri, this, aLoaderDocument); + mozilla::net::ReferrerPolicy refpol = mozilla::net::RP_Default; + if (mStylesheetDocument) { + refpol = mStylesheetDocument->GetReferrerPolicy(); + } + + nsresult rv = TX_LoadSheet(aUri, this, aLoaderDocument, refpol); if (NS_FAILED(rv) && mObserver) { // This is most likely a network or security error, just // use the uri as context. @@ -1207,24 +1198,6 @@ txMozillaXSLTProcessor::notifyError() mObserver->OnTransformDone(mTransformResult, document); } -nsIDocument* -txMozillaXSLTProcessor::getLoaderDoc() -{ - if (mOwner) { - nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mOwner); - if (win) { - return win->GetExtantDoc(); - } - } - - if (mSource) { - nsCOMPtr<nsINode> node = do_QueryInterface(mSource); - return node->OwnerDoc(); - } - - return nullptr; -} - nsresult txMozillaXSLTProcessor::ensureStylesheet() { @@ -1239,8 +1212,7 @@ txMozillaXSLTProcessor::ensureStylesheet() style = mStylesheetDocument; } - return TX_CompileStylesheet(style, getLoaderDoc(), this, - getter_AddRefs(mStylesheet)); + return TX_CompileStylesheet(style, this, getter_AddRefs(mStylesheet)); } void diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.h b/dom/xslt/xslt/txMozillaXSLTProcessor.h index 1cf381a873..6fa2ab1338 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.h +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h @@ -166,8 +166,6 @@ class txMozillaXSLTProcessor final : public nsIXSLTProcessor, void notifyError(); nsresult ensureStylesheet(); - nsIDocument* getLoaderDoc(); - nsCOMPtr<nsISupports> mOwner; RefPtr<txStylesheet> mStylesheet; @@ -187,10 +185,10 @@ class txMozillaXSLTProcessor final : public nsIXSLTProcessor, }; extern nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, - nsIDocument* aLoaderDocument); + nsIDocument* aLoaderDocument, + mozilla::net::ReferrerPolicy aReferrerPolicy); extern nsresult TX_CompileStylesheet(nsINode* aNode, - nsIDocument* aLoaderDocument, txMozillaXSLTProcessor* aProcessor, txStylesheet** aStylesheet); diff --git a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp index 3a17098a04..f447df7cfc 100644 --- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp +++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp @@ -20,7 +20,6 @@ #include "txNamespaceMap.h" #include "txURIUtils.h" #include "txXSLTFunctions.h" -#include "nsNetUtil.h" using namespace mozilla; @@ -757,12 +756,10 @@ txFnStartImport(int32_t aNamespaceID, nsGkAtoms::href, true, &attr); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, nullptr, - aState.mElementContext->mBaseURI); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aState.loadImportedStylesheet(uri, importPtr->mFrame); + nsAutoString absUri; + URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, + absUri); + rv = aState.loadImportedStylesheet(absUri, importPtr->mFrame); NS_ENSURE_SUCCESS(rv, rv); return aState.pushHandlerTable(gTxIgnoreHandler); @@ -790,12 +787,10 @@ txFnStartInclude(int32_t aNamespaceID, nsGkAtoms::href, true, &attr); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, nullptr, - aState.mElementContext->mBaseURI); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aState.loadIncludedStylesheet(uri); + nsAutoString absUri; + URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, + absUri); + rv = aState.loadIncludedStylesheet(absUri); NS_ENSURE_SUCCESS(rv, rv); return aState.pushHandlerTable(gTxIgnoreHandler); diff --git a/dom/xslt/xslt/txStylesheetCompiler.cpp b/dom/xslt/xslt/txStylesheetCompiler.cpp index bf37a9fb24..d22ba41efb 100644 --- a/dom/xslt/xslt/txStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txStylesheetCompiler.cpp @@ -23,29 +23,31 @@ #include "nsICategoryManager.h" #include "nsServiceManagerUtils.h" #include "nsTArray.h" -#include "nsIURI.h" using namespace mozilla; using mozilla::net::ReferrerPolicy; -txStylesheetCompiler::txStylesheetCompiler(const nsString& aFragment, +txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, + ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver) : txStylesheetCompilerState(aObserver) { - mStatus = init(aFragment, nullptr, nullptr); + mStatus = init(aStylesheetURI, aReferrerPolicy, nullptr, nullptr); } -txStylesheetCompiler::txStylesheetCompiler(const nsString& aFragment, +txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, txStylesheet* aStylesheet, txListIterator* aInsertPosition, + ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver) : txStylesheetCompilerState(aObserver) { - mStatus = init(aFragment, aStylesheet, aInsertPosition); + mStatus = init(aStylesheetURI, aReferrerPolicy, aStylesheet, + aInsertPosition); } void -txStylesheetCompiler::setBaseURI(nsIURI* aBaseURI) +txStylesheetCompiler::setBaseURI(const nsString& aBaseURI) { NS_ASSERTION(mObjectStack.size() == 1 && !mObjectStack.peek(), "Execution already started"); @@ -57,16 +59,6 @@ txStylesheetCompiler::setBaseURI(nsIURI* aBaseURI) mElementContext->mBaseURI = aBaseURI; } -void -txStylesheetCompiler::setPrincipal(nsIPrincipal* aPrincipal) -{ - if (NS_FAILED(mStatus)) { - return; - } - - mStylesheetPrincipal = aPrincipal; -} - nsresult txStylesheetCompiler::startElement(int32_t aNamespaceID, nsIAtom* aLocalName, nsIAtom* aPrefix, @@ -225,11 +217,9 @@ txStylesheetCompiler::startElementInternal(int32_t aNamespaceID, rv = ensureNewElementContext(); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, - nullptr, mElementContext->mBaseURI); - NS_ENSURE_SUCCESS(rv, rv); - mElementContext->mBaseURI = uri.forget(); + nsAutoString uri; + URIUtils::resolveHref(attr->mValue, mElementContext->mBaseURI, uri); + mElementContext->mBaseURI = uri; } // extension-element-prefixes @@ -381,15 +371,9 @@ txStylesheetCompiler::characters(const nsAString& aStr) nsresult txStylesheetCompiler::doneLoading() { - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsCOMPtr<nsIURI> uri; - mStylesheetPrincipal->GetURI(getter_AddRefs(uri)); - nsAutoCString spec; - uri->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::doneLoading: %s\n", - spec.get())); - } + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::doneLoading: %s\n", + NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); if (NS_FAILED(mStatus)) { return mStatus; } @@ -403,17 +387,11 @@ void txStylesheetCompiler::cancel(nsresult aError, const char16_t *aErrorText, const char16_t *aParam) { - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsCOMPtr<nsIURI> uri; - mStylesheetPrincipal->GetURI(getter_AddRefs(uri)); - nsAutoCString spec; - uri->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::cancel: %s, module: %d, code %d\n", - spec.get(), - NS_ERROR_GET_MODULE(aError), - NS_ERROR_GET_CODE(aError))); - } + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::cancel: %s, module: %d, code %d\n", + NS_LossyConvertUTF16toASCII(mStylesheetURI).get(), + NS_ERROR_GET_MODULE(aError), + NS_ERROR_GET_CODE(aError))); if (NS_SUCCEEDED(mStatus)) { mStatus = aError; } @@ -433,30 +411,20 @@ txStylesheetCompiler::getStylesheet() } nsresult -txStylesheetCompiler::loadURI(nsIURI* aUri, - nsIPrincipal* aReferrerPrincipal, +txStylesheetCompiler::loadURI(const nsAString& aUri, + const nsAString& aReferrerUri, + ReferrerPolicy aReferrerPolicy, txStylesheetCompiler* aCompiler) { - nsCOMPtr<nsIURI> stylesheetURI; - mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); - - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsAutoCString stylesheetSpec; - stylesheetURI->GetSpec(stylesheetSpec); - nsAutoCString uriSpec; - aUri->GetSpec(uriSpec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::loadURI forwards %s thru %s\n", - uriSpec.get(), - stylesheetSpec.get())); - } - - bool equals; - if (NS_FAILED(stylesheetURI->Equals(aUri, &equals)) || equals) { + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::loadURI forwards %s thru %s\n", + NS_LossyConvertUTF16toASCII(aUri).get(), + NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); + if (mStylesheetURI.Equals(aUri)) { return NS_ERROR_XSLT_LOAD_RECURSION; } return mObserver ? - mObserver->loadURI(aUri, aReferrerPrincipal, aCompiler) : + mObserver->loadURI(aUri, aReferrerUri, aReferrerPolicy, aCompiler) : NS_ERROR_FAILURE; } @@ -566,20 +534,27 @@ txStylesheetCompilerState::txStylesheetCompilerState(txACompileObserver* aObserv } nsresult -txStylesheetCompilerState::init(const nsString& aFragment, +txStylesheetCompilerState::init(const nsAString& aStylesheetURI, + ReferrerPolicy aReferrerPolicy, txStylesheet* aStylesheet, txListIterator* aInsertPosition) { NS_ASSERTION(!aStylesheet || aInsertPosition, "must provide insertposition if loading subsheet"); - + mStylesheetURI = aStylesheetURI; + mReferrerPolicy = aReferrerPolicy; // Check for fragment identifier of an embedded stylesheet. - if (!aFragment.IsEmpty()) { - // This is really an embedded stylesheet, not just a - // "url#". We may want to unescape the fragment. - mTarget = aFragment; - mEmbedStatus = eNeedEmbed; - mHandlerTable = gTxEmbedHandler; + int32_t fragment = aStylesheetURI.FindChar('#') + 1; + if (fragment > 0) { + int32_t fragmentLength = aStylesheetURI.Length() - fragment; + if (fragmentLength > 0) { + // This is really an embedded stylesheet, not just a + // "url#". We may want to unescape the fragment. + mTarget = Substring(aStylesheetURI, (uint32_t)fragment, + fragmentLength); + mEmbedStatus = eNeedEmbed; + mHandlerTable = gTxEmbedHandler; + } } nsresult rv = NS_OK; if (aStylesheet) { @@ -598,7 +573,8 @@ txStylesheetCompilerState::init(const nsString& aFragment, mIsTopCompiler = true; } - mElementContext = new txElementContext(); + mElementContext = new txElementContext(aStylesheetURI); + NS_ENSURE_TRUE(mElementContext->mMappings, NS_ERROR_OUT_OF_MEMORY); // Push the "old" txElementContext rv = pushObject(0); @@ -761,25 +737,18 @@ txStylesheetCompilerState::addInstruction(nsAutoPtr<txInstruction>&& aInstructio } nsresult -txStylesheetCompilerState::loadIncludedStylesheet(nsIURI* aURI) +txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI) { - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsAutoCString spec; - aURI->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("CompilerState::loadIncludedStylesheet: %s\n", - spec.get())); - } - - nsCOMPtr<nsIURI> stylesheetURI; - mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); - bool equals; - if (NS_FAILED(stylesheetURI->Equals(aURI, &equals)) || equals) { + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("CompilerState::loadIncludedStylesheet: %s\n", + NS_LossyConvertUTF16toASCII(aURI).get())); + if (mStylesheetURI.Equals(aURI)) { return NS_ERROR_XSLT_LOAD_RECURSION; } NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); nsAutoPtr<txToplevelItem> item(new txDummyItem); + NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); nsresult rv = mToplevelIterator.addBefore(item); NS_ENSURE_SUCCESS(rv, rv); @@ -791,21 +760,19 @@ txStylesheetCompilerState::loadIncludedStylesheet(nsIURI* aURI) txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this); - nsAutoCString fragment; - aURI->GetRef(fragment); - RefPtr<txStylesheetCompiler> compiler = - new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), - mStylesheet, - &mToplevelIterator, - observer); + new txStylesheetCompiler(aURI, mStylesheet, &mToplevelIterator, + mReferrerPolicy, observer); + NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); // step forward before calling the observer in case of syncronous loading mToplevelIterator.next(); - mChildCompilerList.AppendElement(compiler); + if (mChildCompilerList.AppendElement(compiler) == nullptr) { + return NS_ERROR_OUT_OF_MEMORY; + } - rv = mObserver->loadURI(aURI, mStylesheetPrincipal, compiler); + rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler); if (NS_FAILED(rv)) { mChildCompilerList.RemoveElement(compiler); } @@ -814,21 +781,13 @@ txStylesheetCompilerState::loadIncludedStylesheet(nsIURI* aURI) } nsresult -txStylesheetCompilerState::loadImportedStylesheet(nsIURI* aURI, +txStylesheetCompilerState::loadImportedStylesheet(const nsAString& aURI, txStylesheet::ImportFrame* aFrame) { - if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { - nsAutoCString spec; - aURI->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("CompilerState::loadImportedStylesheet: %s\n", - spec.get())); - } - - nsCOMPtr<nsIURI> stylesheetURI; - mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); - bool equals; - if (NS_FAILED(stylesheetURI->Equals(aURI, &equals)) || equals) { + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("CompilerState::loadImportedStylesheet: %s\n", + NS_LossyConvertUTF16toASCII(aURI).get())); + if (mStylesheetURI.Equals(aURI)) { return NS_ERROR_XSLT_LOAD_RECURSION; } NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); @@ -838,18 +797,17 @@ txStylesheetCompilerState::loadImportedStylesheet(nsIURI* aURI, txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this); - nsAutoCString fragment; - aURI->GetRef(fragment); - RefPtr<txStylesheetCompiler> compiler = - new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), - mStylesheet, - &iter, + new txStylesheetCompiler(aURI, mStylesheet, &iter, mReferrerPolicy, observer); + NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); - mChildCompilerList.AppendElement(compiler); + if (mChildCompilerList.AppendElement(compiler) == nullptr) { + return NS_ERROR_OUT_OF_MEMORY; + } - nsresult rv = mObserver->loadURI(aURI, mStylesheetPrincipal, compiler); + nsresult rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, + compiler); if (NS_FAILED(rv)) { mChildCompilerList.RemoveElement(compiler); } @@ -1110,7 +1068,9 @@ extern bool TX_XSLTFunctionAvailable(nsIAtom* aName, int32_t aNameSpaceID) { RefPtr<txStylesheetCompiler> compiler = - new txStylesheetCompiler(EmptyString(), nullptr); + new txStylesheetCompiler(EmptyString(), + mozilla::net::RP_Default, nullptr); + NS_ENSURE_TRUE(compiler, false); nsAutoPtr<FunctionCall> fnCall; @@ -1154,9 +1114,10 @@ txStylesheetCompilerState::shutdown() sXPCOMFunctionMappings = nullptr; } -txElementContext::txElementContext() +txElementContext::txElementContext(const nsAString& aBaseURI) : mPreserveWhitespace(false), mForwardsCompatibleParsing(true), + mBaseURI(aBaseURI), mMappings(new txNamespaceMap), mDepth(0) { diff --git a/dom/xslt/xslt/txStylesheetCompiler.h b/dom/xslt/xslt/txStylesheetCompiler.h index b15272160c..7fb0f05d60 100644 --- a/dom/xslt/xslt/txStylesheetCompiler.h +++ b/dom/xslt/xslt/txStylesheetCompiler.h @@ -32,12 +32,12 @@ class txInScopeVariable; class txElementContext : public txObject { public: - explicit txElementContext(); + explicit txElementContext(const nsAString& aBaseURI); txElementContext(const txElementContext& aOther); bool mPreserveWhitespace; bool mForwardsCompatibleParsing; - nsCOMPtr<nsIURI> mBaseURI; + nsString mBaseURI; RefPtr<txNamespaceMap> mMappings; nsTArray<int32_t> mInstructionNamespaces; int32_t mDepth; @@ -49,8 +49,9 @@ class txACompileObserver NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; NS_IMETHOD_(MozExternalRefCountType) Release() = 0; - virtual nsresult loadURI(nsIURI* aUri, - nsIPrincipal* aReferrerPrincipal, + virtual nsresult loadURI(const nsAString& aUri, + const nsAString& aReferrerUri, + mozilla::net::ReferrerPolicy aReferrerPolicy, txStylesheetCompiler* aCompiler) = 0; virtual void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, @@ -59,8 +60,8 @@ class txACompileObserver }; #define TX_DECL_ACOMPILEOBSERVER \ - nsresult loadURI(nsIURI* aUri, \ - nsIPrincipal* aReferrerPrincipal, \ + nsresult loadURI(const nsAString& aUri, const nsAString& aReferrerUri, \ + mozilla::net::ReferrerPolicy aReferrerPolicy, \ txStylesheetCompiler* aCompiler); \ void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, \ const char16_t *aErrorText = nullptr, \ @@ -72,8 +73,9 @@ class txStylesheetCompilerState : public txIParseContext explicit txStylesheetCompilerState(txACompileObserver* aObserver); ~txStylesheetCompilerState(); - nsresult init(const nsString& aFragment, txStylesheet* aStylesheet, - txListIterator* aInsertPosition); + nsresult init(const nsAString& aStylesheetURI, + mozilla::net::ReferrerPolicy aReferrerPolicy, + txStylesheet* aStylesheet, txListIterator* aInsertPosition); // Embedded stylesheets state bool handleEmbeddedSheet() @@ -114,8 +116,8 @@ class txStylesheetCompilerState : public txIParseContext nsresult openInstructionContainer(txInstructionContainer* aContainer); void closeInstructionContainer(); nsresult addInstruction(nsAutoPtr<txInstruction>&& aInstruction); - nsresult loadIncludedStylesheet(nsIURI* aURI); - nsresult loadImportedStylesheet(nsIURI* aURI, + nsresult loadIncludedStylesheet(const nsAString& aURI); + nsresult loadImportedStylesheet(const nsAString& aURI, txStylesheet::ImportFrame* aFrame); // misc @@ -164,7 +166,6 @@ class txStylesheetCompilerState : public txIParseContext uint16_t mDisAllowed; protected: - nsCOMPtr<nsIPrincipal> mStylesheetPrincipal; RefPtr<txACompileObserver> mObserver; nsTArray<txInScopeVariable*> mInScopeVariables; nsTArray<txStylesheetCompiler*> mChildCompilerList; @@ -177,6 +178,7 @@ class txStylesheetCompilerState : public txIParseContext eInEmbed, eHasEmbed } mEmbedStatus; + nsString mStylesheetURI; bool mIsTopCompiler; bool mDoneWithThisStylesheet; txStack mObjectStack; @@ -187,6 +189,7 @@ class txStylesheetCompilerState : public txIParseContext txInstruction** mNextInstrPtr; txListIterator mToplevelIterator; nsTArray<txInstruction**> mGotoTargetPointers; + mozilla::net::ReferrerPolicy mReferrerPolicy; }; struct txStylesheetAttr @@ -204,15 +207,16 @@ class txStylesheetCompiler final : private txStylesheetCompilerState, friend class txStylesheetCompilerState; friend bool TX_XSLTFunctionAvailable(nsIAtom* aName, int32_t aNameSpaceID); - txStylesheetCompiler(const nsString& aFragment, + txStylesheetCompiler(const nsAString& aStylesheetURI, + mozilla::net::ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver); - txStylesheetCompiler(const nsString& aFragment, + txStylesheetCompiler(const nsAString& aStylesheetURI, txStylesheet* aStylesheet, txListIterator* aInsertPosition, + mozilla::net::ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver); - void setBaseURI(nsIURI* aBaseURI); - void setPrincipal(nsIPrincipal* aPrincipal); + void setBaseURI(const nsString& aBaseURI); nsresult startElement(int32_t aNamespaceID, nsIAtom* aLocalName, nsIAtom* aPrefix, txStylesheetAttr* aAttributes, diff --git a/dom/xslt/xslt/txXSLTFunctions.h b/dom/xslt/xslt/txXSLTFunctions.h index 3ef80f0950..1bc0f9961e 100644 --- a/dom/xslt/xslt/txXSLTFunctions.h +++ b/dom/xslt/xslt/txXSLTFunctions.h @@ -23,14 +23,12 @@ class DocumentFunctionCall : public FunctionCall { /** * Creates a new document() function call **/ - explicit DocumentFunctionCall(nsIURI* aBaseURI) - : mBaseURI(aBaseURI) - {} + explicit DocumentFunctionCall(const nsAString& aBaseURI); TX_DECL_FUNCTION private: - nsCOMPtr<nsIURI> mBaseURI; + nsString mBaseURI; }; /* diff --git a/editor/libeditor/nsHTMLDataTransfer.cpp b/editor/libeditor/nsHTMLDataTransfer.cpp index b4bb8a9210..1f0b6adfcb 100644 --- a/editor/libeditor/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/nsHTMLDataTransfer.cpp @@ -1777,7 +1777,7 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsAString & aQuotedText, return NS_OK; // rules canceled the operation } - // Wrap the inserted quote in a <span> so it won't be wrapped: + // Wrap the inserted quote in a <span> so we can distinguish it. nsCOMPtr<Element> newNode = DeleteSelectionAndCreateElement(*nsGkAtoms::span); @@ -1787,12 +1787,11 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsAString & aQuotedText, // but we'll fall through and try to insert the text anyway. if (newNode) { // Add an attribute on the pre node so we'll know it's a quotation. - // Do this after the insertion, so that newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::mozquote, NS_LITERAL_STRING("true"), true); - // turn off wrapping on spans + // Allow wrapping on spans so long lines get wrapped to the screen. newNode->SetAttr(kNameSpaceID_None, nsGkAtoms::style, - NS_LITERAL_STRING("white-space: pre;"), true); + NS_LITERAL_STRING("white-space: pre-wrap;"), true); // and set the selection inside it: selection->Collapse(newNode, 0); @@ -2292,22 +2291,26 @@ nsHTMLEditor::ReplaceOrphanedStructure(StartOrEnd aStartOrEnd, } // If we found substructure, paste it instead of its descendants. - // Postprocess list to remove any descendants of this node so that we don't - // insert them twice. - while (aNodeArray.Length()) { - int32_t idx = aStartOrEnd == StartOrEnd::start ? 0 - : aNodeArray.Length() - 1; + // Only replace with the substructure if all the nodes in the list are + // descendants. + bool shouldReplaceNodes = true; + for (uint32_t i = 0; i < aNodeArray.Length(); i++) { + uint32_t idx = aStartOrEnd == StartOrEnd::start ? + i : (aNodeArray.Length() - i - 1); OwningNonNull<nsINode> endpoint = aNodeArray[idx]; if (!nsEditorUtils::IsDescendantOf(endpoint, replaceNode)) { + shouldReplaceNodes = false; break; } - aNodeArray.RemoveElementAt(idx); } - // Now replace the removed nodes with the structural parent - if (aStartOrEnd == StartOrEnd::end) { - aNodeArray.AppendElement(*replaceNode); - } else { - aNodeArray.InsertElementAt(0, *replaceNode); + if (shouldReplaceNodes) { + // Now replace the removed nodes with the structural parent + aNodeArray.Clear(); + if (aStartOrEnd == StartOrEnd::end) { + aNodeArray.AppendElement(*replaceNode); + } else { + aNodeArray.InsertElementAt(0, *replaceNode); + } } } diff --git a/editor/libeditor/nsTableEditor.cpp b/editor/libeditor/nsTableEditor.cpp index 277a165b05..0b1ffeb3aa 100644 --- a/editor/libeditor/nsTableEditor.cpp +++ b/editor/libeditor/nsTableEditor.cpp @@ -2725,8 +2725,10 @@ nsHTMLEditor::GetCellAt(nsIDOMElement* aTable, int32_t aRowIndex, int32_t aColIn } nsTableOuterFrame* tableFrame = GetTableFrame(aTable); - if (!tableFrame) - return NS_ERROR_FAILURE; + if (!tableFrame) { + *aCell = nullptr; + return NS_EDITOR_ELEMENT_NOT_FOUND; + } nsCOMPtr<nsIDOMElement> domCell = do_QueryInterface(tableFrame->GetCellAt(aRowIndex, aColIndex)); diff --git a/editor/libeditor/nsTextEditRules.cpp b/editor/libeditor/nsTextEditRules.cpp index d38b144d5f..9a9af8c4d0 100644 --- a/editor/libeditor/nsTextEditRules.cpp +++ b/editor/libeditor/nsTextEditRules.cpp @@ -438,12 +438,20 @@ nsTextEditRules::CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection) return NS_OK; } + NS_ENSURE_STATE(mEditor); + + // If there is no selection ranges, we should set to the end of the editor. + // This is usually performed in nsTextEditRules::Init(), however, if the + // editor is reframed, this may be called by AfterEdit(). + if (!aSelection->RangeCount()) { + mEditor->EndOfDocument(); + } + // if we are at the end of the textarea, we need to set the // selection to stick to the mozBR at the end of the textarea. int32_t selOffset; nsCOMPtr<nsIDOMNode> selNode; nsresult res; - NS_ENSURE_STATE(mEditor); res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset); NS_ENSURE_SUCCESS(res, res); diff --git a/editor/libeditor/tests/file_bug915962.html b/editor/libeditor/tests/file_bug915962.html new file mode 100644 index 0000000000..07c06792d3 --- /dev/null +++ b/editor/libeditor/tests/file_bug915962.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<html> + <body> + <button>Button</button> + <div style="height: 20000px;" tabindex="-1"><hr></div> + </body> +</html> diff --git a/editor/libeditor/tests/mochitest.ini b/editor/libeditor/tests/mochitest.ini index 4cc6ceb8b2..a5a2820400 100644 --- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -9,6 +9,7 @@ support-files = file_bug549262.html file_bug586662.html file_bug674770-1.html + file_bug915962.html file_select_all_without_body.html green.png @@ -138,7 +139,9 @@ skip-if = toolkit == 'android' [test_bug832025.html] [test_bug857487.html] [test_bug858918.html] +[test_bug915962.html] [test_bug974309.html] +skip-if = toolkit == 'android' [test_bug966155.html] skip-if = os != "win" [test_bug966552.html] @@ -164,5 +167,7 @@ skip-if = toolkit == 'android' [test_bug1181130-1.html] [test_bug1181130-2.html] [test_backspace_vs.html] +[test_bug1247483.html] +skip-if = toolkit == 'android' [test_bug1258085.html] [test_bug1352799.html] diff --git a/editor/libeditor/tests/test_bug1247483.html b/editor/libeditor/tests/test_bug1247483.html new file mode 100644 index 0000000000..40dbc36cec --- /dev/null +++ b/editor/libeditor/tests/test_bug1247483.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html><head> +<title>Test for bug 1247483</title> +<style src="/tests/SimpleTest/test.css" type="text/css"></style> +<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + +<script class="testbody" type="application/javascript"> + +function runTest() { + // Copy content from table. + var selection = getSelection(); + var startRange = document.createRange(); + startRange.setStart(document.getElementById("start"), 0); + startRange.setEnd(document.getElementById("end"), 2); + selection.removeAllRanges(); + selection.addRange(startRange); + SpecialPowers.wrap(document).execCommand("copy", false, null); + + // Paste content into "pastecontainer" + var pasteContainer = document.getElementById("pastecontainer"); + var pasteRange = document.createRange(); + pasteRange.selectNodeContents(pasteContainer); + pasteRange.collapse(false); + selection.removeAllRanges(); + selection.addRange(pasteRange); + SpecialPowers.wrap(document).execCommand("paste", false, null); + + is(pasteContainer.querySelectorAll("td").length, 4, "4 <td> should be pasted."); + + document.execCommand("undo", false, null); + + is(pasteContainer.querySelectorAll("td").length, 0, "Undo should have remove the 4 pasted <td>."); + + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); + +addLoadEvent(runTest); +</script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1247483">Mozilla Bug 1247483</a> +<p id="display"></p> + +<pre id="test"> +</pre> + +<div id="container" contenteditable="true"> +<table> + <tr id="start"><td>1 1</td><td>1 2</td></tr> + <tr id="end"><td>2 1</td><td>2 2</td></tr> +</table> +</div> + +<div id="pastecontainer" contenteditable="true"> +</div> + +</body> +</html> diff --git a/editor/libeditor/tests/test_bug915962.html b/editor/libeditor/tests/test_bug915962.html new file mode 100644 index 0000000000..7a457c1a69 --- /dev/null +++ b/editor/libeditor/tests/test_bug915962.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=915962 +--> +<head> + <title>Test for Bug 915962</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=915962">Mozilla Bug 915962</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 915962 **/ + +var smoothScrollPref = "general.smoothScroll"; +SimpleTest.waitForExplicitFinish(); +var win = window.open("file_bug915962.html", "_blank", + "width=600,height=600,scrollbars=yes"); + +// grab the timer right at the start +var cwu = SpecialPowers.getDOMWindowUtils(win); +function step() { + cwu.advanceTimeAndRefresh(100); +} +SimpleTest.waitForFocus(function() { + SpecialPowers.pushPrefEnv({"set":[[smoothScrollPref, false]]}, startTest); +}, win); +function startTest() { + // Make sure that pressing Space when a tabindex=-1 element is focused + // will scroll the page. + var button = win.document.querySelector("button"); + var sc = win.document.querySelector("div"); + sc.focus(); + is(win.scrollY, 0, "Sanity check"); + synthesizeKey(" ", {}, win); + + step(); + + isnot(win.scrollY, 0, "Page is scrolled down"); + var oldY = win.scrollY; + synthesizeKey(" ", {shiftKey: true}, win); + + step(); + + ok(win.scrollY < oldY, "Page is scrolled up"); + + // Make sure that pressing Space when a tabindex=-1 element is focused + // will not scroll the page, and will activate the element. + button.focus(); + var clicked = false; + button.onclick = () => clicked = true; + oldY = win.scrollY; + synthesizeKey(" ", {}, win); + + step(); + + ok(win.scrollY <= oldY, "Page is not scrolled down"); + ok(clicked, "The button should be clicked"); + + win.close(); + cwu.restoreNormalRefresh(); + + win = window.open("file_bug915962.html", "_blank", + "width=600,height=600,scrollbars=yes"); + cwu = SpecialPowers.getDOMWindowUtils(win); + SimpleTest.waitForFocus(function() { + is(win.scrollY, 0, "Sanity check"); + synthesizeKey(" ", {}, win); + + step(); + + isnot(win.scrollY, 0, "Page is scrolled down without crashing"); + + win.close(); + cwu.restoreNormalRefresh(); + + SimpleTest.finish(); + }, win); +} +</script> +</pre> +</body> +</html> diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h index 94e314c668..cfd8359a03 100644 --- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -138,6 +138,7 @@ enum class LogReason : int { TextureAliveAfterShutdown, InvalidContext, InvalidCommandList, + AsyncTransactionTimeout, // End MustBeLessThanThis = 101, }; diff --git a/gfx/config/gfxConfig.cpp b/gfx/config/gfxConfig.cpp new file mode 100644 index 0000000000..fd253e83f0 --- /dev/null +++ b/gfx/config/gfxConfig.cpp @@ -0,0 +1,223 @@ +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ +/* 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 "gfxConfig.h" +#include "plstr.h" + +namespace mozilla { +namespace gfx { + +static gfxConfig sConfig; + +/* static */ FeatureState& +gfxConfig::GetFeature(Feature aFeature) +{ + return sConfig.GetState(aFeature); +} + +/* static */ bool +gfxConfig::IsEnabled(Feature aFeature) +{ + const FeatureState& state = sConfig.GetState(aFeature); + return state.IsEnabled(); +} + +/* static */ bool +gfxConfig::IsDisabledByDefault(Feature aFeature) +{ + const FeatureState& state = sConfig.GetState(aFeature); + return state.DisabledByDefault(); +} + +/* static */ bool +gfxConfig::IsForcedOnByUser(Feature aFeature) +{ + const FeatureState& state = sConfig.GetState(aFeature); + return state.IsForcedOnByUser(); +} + +/* static */ FeatureStatus +gfxConfig::GetValue(Feature aFeature) +{ + const FeatureState& state = sConfig.GetState(aFeature); + return state.GetValue(); +} + +/* static */ bool +gfxConfig::SetDefault(Feature aFeature, + bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + return state.SetDefault(aEnable, aDisableStatus, aDisableMessage); +} + +/* static */ void +gfxConfig::DisableByDefault(Feature aFeature, + FeatureStatus aDisableStatus, + const char* aDisableMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.DisableByDefault(aDisableStatus, aDisableMessage); +} + +/* static */ void +gfxConfig::EnableByDefault(Feature aFeature) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.EnableByDefault(); +} + +/* static */ void +gfxConfig::SetDefaultFromPref(Feature aFeature, + const char* aPrefName, + bool aIsEnablePref, + bool aDefaultValue) +{ + FeatureState& state = sConfig.GetState(aFeature); + return state.SetDefaultFromPref(aPrefName, aIsEnablePref, aDefaultValue); +} + +/* static */ bool +gfxConfig::InitOrUpdate(Feature aFeature, + bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + return state.InitOrUpdate(aEnable, aDisableStatus, aDisableMessage); +} + +/* static */ void +gfxConfig::SetFailed(Feature aFeature, FeatureStatus aStatus, const char* aMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.SetFailed(aStatus, aMessage); +} + +/* static */ void +gfxConfig::Disable(Feature aFeature, FeatureStatus aStatus, const char* aMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.Disable(aStatus, aMessage); +} + +/* static */ void +gfxConfig::UserEnable(Feature aFeature, const char* aMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.UserEnable(aMessage); +} + +/* static */ void +gfxConfig::UserForceEnable(Feature aFeature, const char* aMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.UserForceEnable(aMessage); +} + +/* static */ void +gfxConfig::UserDisable(Feature aFeature, const char* aMessage) +{ + FeatureState& state = sConfig.GetState(aFeature); + state.UserDisable(aMessage); +} + +/* static */ void +gfxConfig::Reenable(Feature aFeature, Fallback aFallback) +{ + FeatureState& state = sConfig.GetState(aFeature); + MOZ_ASSERT(IsFeatureStatusFailure(state.GetValue())); + + const char* message = state.GetRuntimeMessage(); + EnableFallback(aFallback, message); + state.SetRuntime(FeatureStatus::Available, nullptr); +} + +/* static */ bool +gfxConfig::UseFallback(Fallback aFallback) +{ + return sConfig.UseFallbackImpl(aFallback); +} + +/* static */ void +gfxConfig::EnableFallback(Fallback aFallback, const char* aMessage) +{ + // Ignore aMessage for now. + sConfig.EnableFallbackImpl(aFallback, aMessage); +} + +bool +gfxConfig::UseFallbackImpl(Fallback aFallback) const +{ + return !!(mFallbackBits & (uint64_t(1) << uint64_t(aFallback))); +} + +void +gfxConfig::EnableFallbackImpl(Fallback aFallback, const char* aMessage) +{ + if (!UseFallbackImpl(aFallback)) { + MOZ_ASSERT(mNumFallbackLogEntries < kNumFallbacks); + + FallbackLogEntry& entry = mFallbackLog[mNumFallbackLogEntries]; + mNumFallbackLogEntries++; + + entry.mFallback = aFallback; + PL_strncpyz(entry.mMessage, aMessage, sizeof(entry.mMessage)); + } + mFallbackBits |= (uint64_t(1) << uint64_t(aFallback)); +} + +struct FeatureInfo { + const char* name; + const char* description; +}; +static const FeatureInfo sFeatureInfo[] = { +#define FOR_EACH_FEATURE(name, type, desc) {#name, desc}, + GFX_FEATURE_MAP(FOR_EACH_FEATURE) +#undef FOR_EACH_FEATURE + {nullptr, nullptr} +}; + +/* static */ void +gfxConfig::ForEachFeature(const FeatureIterCallback& aCallback) +{ + for (size_t i = 0; i < kNumFeatures; i++) { + FeatureState& state = GetFeature(static_cast<Feature>(i)); + if (!state.IsInitialized()) { + continue; + } + + aCallback(sFeatureInfo[i].name, + sFeatureInfo[i].description, + state); + } +} + +static const char* sFallbackNames[] = { +#define FOR_EACH_FALLBACK(name) #name, + GFX_FALLBACK_MAP(FOR_EACH_FALLBACK) +#undef FOR_EACH_FALLBACK + nullptr +}; + +/* static */ void +gfxConfig::ForEachFallback(const FallbackIterCallback& aCallback) +{ + sConfig.ForEachFallbackImpl(aCallback); +} + +void +gfxConfig::ForEachFallbackImpl(const FallbackIterCallback& aCallback) +{ + for (size_t i = 0; i < mNumFallbackLogEntries; i++) { + const FallbackLogEntry& entry = mFallbackLog[i]; + aCallback(sFallbackNames[size_t(entry.mFallback)], entry.mMessage); + } +} + +} // namespace gfx +} // namespace mozilla diff --git a/gfx/config/gfxConfig.h b/gfx/config/gfxConfig.h new file mode 100644 index 0000000000..6e1d4d28de --- /dev/null +++ b/gfx/config/gfxConfig.h @@ -0,0 +1,203 @@ +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ +/* 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_gfx_config_gfxConfig_h +#define mozilla_gfx_config_gfxConfig_h + +#include "gfxFeature.h" +#include "gfxFallback.h" +#include "mozilla/Assertions.h" +#include "mozilla/Function.h" + +namespace mozilla { +namespace gfx { + +// Manages the history and state of a graphics feature. The flow of a feature +// is: +// - A default value, set by all.js, gfxPrefs, or gfxPlatform. +// - A user value, set by an external value or user pref. +// - An environment value, determined by system/hardware factors or nsIGfxInfo. +// - A runtime value, determined by any failures encountered after enabling +// the feature. +// +// Each state change for a feature is recorded in this class. +class gfxConfig +{ +public: + // Return the full state history of a feature. + static FeatureState& GetFeature(Feature aFeature); + + // Query whether a parameter is enabled, taking into account any user or + // runtime overrides. The algorithm works as follow: + // + // 1. If a runtime decision disabled the feature, return false. + // 2. If the user force-enabled the feature, return true. + // 3. If the environment disabled the feature, return false. + // 4. If the user specified a decision, return it. + // 5. Return the base setting for the feature. + static bool IsEnabled(Feature aFeature); + + // Query the history of a parameter. ForcedOnByUser returns whether or not + // the user specifically used a "force" preference to enable the parameter. + // IsDisabledByDefault returns whether or not the initial status of the + // feature, before adding user prefs and runtime decisions, was disabled. + static bool IsForcedOnByUser(Feature aFeature); + static bool IsDisabledByDefault(Feature aFeature); + + // Query the status value of a parameter. This is computed similar to + // IsEnabled: + // + // 1. If a runtime failure was set, return it. + // 2. If the user force-enabled the feature, return ForceEnabled. + // 3. If an environment status was set, return it. + // 4. If a user status was set, return it. + // 5. Return the default status. + static FeatureStatus GetValue(Feature aFeature); + + // Initialize the base value of a parameter. The return value is aEnable. + static bool SetDefault(Feature aFeature, + bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage); + static void DisableByDefault(Feature aFeature, + FeatureStatus aDisableStatus, + const char* aDisableMessage); + static void EnableByDefault(Feature aFeature); + + // Set a environment status that overrides both the default and user + // statuses; this should be used to disable features based on system + // or hardware problems that can be determined up-front. The only + // status that can override this decision is the user force-enabling + // the feature. + static void Disable(Feature aFeature, + FeatureStatus aStatus, + const char* aMessage); + + // Given a preference name, infer the default value and whether or not the + // user has changed it. |aIsEnablePref| specifies whether or not the pref + // is intended to enable a feature (true), or disable it (false). + static void SetDefaultFromPref(Feature aFeature, + const char* aPrefName, + bool aIsEnablePref, + bool aDefaultValue); + + // Disable a parameter based on a runtime decision. This permanently + // disables the feature, since runtime decisions override all other + // decisions. + static void SetFailed(Feature aFeature, + FeatureStatus aStatus, + const char* aMessage); + + // Force a feature to be disabled permanently. This is the same as + // SetFailed(), but the name may be clearer depending on the context. + static void ForceDisable(Feature aFeature, + FeatureStatus aStatus, + const char* aMessage) + { + SetFailed(aFeature, aStatus, aMessage); + } + + // Convenience helpers for SetFailed(). + static bool MaybeSetFailed(Feature aFeature, + bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage) + { + if (!aEnable) { + SetFailed(aFeature, aDisableStatus, aDisableMessage); + return false; + } + return true; + } + + // Convenience helper for SetFailed(). + static bool MaybeSetFailed(Feature aFeature, + FeatureStatus aStatus, + const char* aDisableMessage) + { + return MaybeSetFailed( + aFeature, + (aStatus != FeatureStatus::Available && + aStatus != FeatureStatus::ForceEnabled), + aStatus, + aDisableMessage); + } + + // Re-enables a feature that was previously disabled, by attaching it to a + // fallback. The fallback inherits the message that was used for disabling + // the feature. This can be used, for example, when D3D11 fails at runtime + // but we acquire a second, successful device with WARP. + static void Reenable(Feature aFeature, Fallback aFallback); + + // Same as SetDefault, except if the feature already has a default value + // set, the new value will be set as a runtime value. This is useful for + // when the base value can change (for example, via an update from the + // parent process). + static bool InitOrUpdate(Feature aFeature, + bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage); + + // Set a user status that overrides the base value (but not runtime value) + // of a parameter. + static void UserEnable(Feature aFeature, const char* aMessage); + static void UserForceEnable(Feature aFeature, const char* aMessage); + static void UserDisable(Feature aFeature, const char* aMessage); + + // Query whether a fallback has been toggled. + static bool UseFallback(Fallback aFallback); + + // Enable a fallback. + static void EnableFallback(Fallback aFallback, const char* aMessage); + + // Run a callback for each initialized FeatureState. + typedef mozilla::function<void(const char* aName, + const char* aDescription, + FeatureState& aFeature)> FeatureIterCallback; + static void ForEachFeature(const FeatureIterCallback& aCallback); + + // Run a callback for each enabled fallback. + typedef mozilla::function<void(const char* aName, const char* aMsg)> + FallbackIterCallback; + static void ForEachFallback(const FallbackIterCallback& aCallback); + +private: + void ForEachFallbackImpl(const FallbackIterCallback& aCallback); + +private: + FeatureState& GetState(Feature aFeature) { + MOZ_ASSERT(size_t(aFeature) < kNumFeatures); + return mFeatures[size_t(aFeature)]; + } + const FeatureState& GetState(Feature aFeature) const { + MOZ_ASSERT(size_t(aFeature) < kNumFeatures); + return mFeatures[size_t(aFeature)]; + } + + bool UseFallbackImpl(Fallback aFallback) const; + void EnableFallbackImpl(Fallback aFallback, const char* aMessage); + +private: + static const size_t kNumFeatures = size_t(Feature::NumValues); + static const size_t kNumFallbacks = size_t(Fallback::NumValues); + +private: + FeatureState mFeatures[kNumFeatures]; + uint64_t mFallbackBits; + +private: + struct FallbackLogEntry { + Fallback mFallback; + char mMessage[80]; + }; + + FallbackLogEntry mFallbackLog[kNumFallbacks]; + size_t mNumFallbackLogEntries; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // mozilla_gfx_config_gfxConfig_h diff --git a/gfx/config/gfxFallback.h b/gfx/config/gfxFallback.h new file mode 100644 index 0000000000..5636598093 --- /dev/null +++ b/gfx/config/gfxFallback.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ +/* 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_gfx_config_gfxFallback_h +#define mozilla_gfx_config_gfxFallback_h + +#include <stdint.h> +#include "gfxTelemetry.h" + +namespace mozilla { +namespace gfx { + +#define GFX_FALLBACK_MAP(_) \ + /* Name */ \ + _(USE_D3D11_WARP_COMPOSITOR) \ + /* Add new entries above this comment */ + +enum class Fallback : uint32_t { +#define MAKE_ENUM(name) name, + GFX_FALLBACK_MAP(MAKE_ENUM) +#undef MAKE_ENUM + NumValues +}; + +} // namespace gfx +} // namespace mozilla + +#endif // mozilla_gfx_config_gfxFallback_h diff --git a/gfx/config/gfxFeature.cpp b/gfx/config/gfxFeature.cpp new file mode 100644 index 0000000000..5602dcc310 --- /dev/null +++ b/gfx/config/gfxFeature.cpp @@ -0,0 +1,241 @@ +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ +/* 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 "mozilla/Preferences.h" +#include "prprf.h" +#include "gfxFeature.h" + +namespace mozilla { +namespace gfx { + +bool +FeatureState::IsEnabled() const +{ + return IsFeatureStatusSuccess(GetValue()); +} + +FeatureStatus +FeatureState::GetValue() const +{ + AssertInitialized(); + + if (mRuntime.mStatus != FeatureStatus::Unused) { + return mRuntime.mStatus; + } + if (mUser.mStatus == FeatureStatus::ForceEnabled) { + return FeatureStatus::ForceEnabled; + } + if (mEnvironment.mStatus != FeatureStatus::Unused) { + return mEnvironment.mStatus; + } + if (mUser.mStatus != FeatureStatus::Unused) { + return mUser.mStatus; + } + return mDefault.mStatus; +} + +bool +FeatureState::SetDefault(bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage) +{ + if (!aEnable) { + DisableByDefault(aDisableStatus, aDisableMessage); + return false; + } + EnableByDefault(); + return true; +} + +void +FeatureState::SetDefaultFromPref(const char* aPrefName, + bool aIsEnablePref, + bool aDefaultValue) +{ + bool baseValue = Preferences::GetDefaultBool(aPrefName, aDefaultValue); + SetDefault(baseValue == aIsEnablePref, FeatureStatus::Disabled, "Disabled by default"); + + if (Preferences::HasUserValue(aPrefName)) { + bool userValue = Preferences::GetBool(aPrefName, aDefaultValue); + if (userValue == aIsEnablePref) { + UserEnable("Enabled by user preference"); + } else { + UserDisable("Disabled by user preference"); + } + } +} + +bool +FeatureState::InitOrUpdate(bool aEnable, + FeatureStatus aDisableStatus, + const char* aDisableMessage) +{ + if (!IsInitialized()) { + return SetDefault(aEnable, aDisableStatus, aDisableMessage); + } + return MaybeSetFailed(aEnable, aDisableStatus, aDisableMessage); +} + +void +FeatureState::UserEnable(const char* aMessage) +{ + AssertInitialized(); + SetUser(FeatureStatus::Available, aMessage); +} + +void +FeatureState::UserForceEnable(const char* aMessage) +{ + AssertInitialized(); + SetUser(FeatureStatus::ForceEnabled, aMessage); +} + +void +FeatureState::UserDisable(const char* aMessage) +{ + AssertInitialized(); + SetUser(FeatureStatus::Disabled, aMessage); +} + +void +FeatureState::Disable(FeatureStatus aStatus, const char* aMessage) +{ + AssertInitialized(); + + // We should never bother setting an environment status to "enabled," since + // it could override an explicit user decision to disable it. + MOZ_ASSERT(IsFeatureStatusFailure(aStatus)); + + SetEnvironment(aStatus, aMessage); +} + +void +FeatureState::SetFailed(FeatureStatus aStatus, const char* aMessage) +{ + AssertInitialized(); + + // We should never bother setting a runtime status to "enabled," since it could + // override an explicit user decision to disable it. + MOZ_ASSERT(IsFeatureStatusFailure(aStatus)); + + SetRuntime(aStatus, aMessage); +} + +bool +FeatureState::MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage) +{ + if (!aEnable) { + SetFailed(aStatus, aMessage); + return false; + } + return true; +} + +bool +FeatureState::MaybeSetFailed(FeatureStatus aStatus, const char* aMessage) +{ + return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage); +} + +bool +FeatureState::DisabledByDefault() const +{ + AssertInitialized(); + return mDefault.mStatus != FeatureStatus::Available; +} + +bool +FeatureState::IsForcedOnByUser() const +{ + AssertInitialized(); + return mUser.mStatus == FeatureStatus::ForceEnabled; +} + +void +FeatureState::EnableByDefault() +{ + // User/runtime decisions should not have been made yet. + MOZ_ASSERT(!mUser.IsInitialized()); + MOZ_ASSERT(!mEnvironment.IsInitialized()); + MOZ_ASSERT(!mRuntime.IsInitialized()); + + mDefault.Set(FeatureStatus::Available); +} + +void +FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage) +{ + // User/runtime decisions should not have been made yet. + MOZ_ASSERT(!mUser.IsInitialized()); + MOZ_ASSERT(!mEnvironment.IsInitialized()); + MOZ_ASSERT(!mRuntime.IsInitialized()); + + mDefault.Set(aStatus, aMessage); +} + +void +FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage) +{ + // Default decision must have been made, but not runtime or environment. + MOZ_ASSERT(mDefault.IsInitialized()); + MOZ_ASSERT(!mEnvironment.IsInitialized()); + MOZ_ASSERT(!mRuntime.IsInitialized()); + + mUser.Set(aStatus, aMessage); +} + +void +FeatureState::SetEnvironment(FeatureStatus aStatus, const char* aMessage) +{ + // Default decision must have been made, but not runtime. + MOZ_ASSERT(mDefault.IsInitialized()); + MOZ_ASSERT(!mRuntime.IsInitialized()); + + mEnvironment.Set(aStatus, aMessage); +} + +void +FeatureState::SetRuntime(FeatureStatus aStatus, const char* aMessage) +{ + AssertInitialized(); + + mRuntime.Set(aStatus, aMessage); +} + +const char* +FeatureState::GetRuntimeMessage() const +{ + MOZ_ASSERT(IsFeatureStatusFailure(mRuntime.mStatus)); + return mRuntime.mMessage; +} + +void +FeatureState::ForEachStatusChange(const StatusIterCallback& aCallback) const +{ + AssertInitialized(); + + aCallback("default", mDefault.mStatus, mDefault.MessageOrNull()); + if (mUser.IsInitialized()) { + aCallback("user", mUser.mStatus, mUser.Message()); + } + if (mEnvironment.IsInitialized()) { + aCallback("env", mEnvironment.mStatus, mEnvironment.Message()); + } + if (mRuntime.IsInitialized()) { + aCallback("runtime", mRuntime.mStatus, mRuntime.Message()); + } +} + +void +FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */) +{ + mStatus = aStatus; + if (aMessage) { + PR_snprintf(mMessage, sizeof(mMessage), "%s", aMessage); + } +} + +} // namespace gfx +} // namespace mozilla diff --git a/gfx/config/gfxFeature.h b/gfx/config/gfxFeature.h new file mode 100644 index 0000000000..ba38224332 --- /dev/null +++ b/gfx/config/gfxFeature.h @@ -0,0 +1,117 @@ +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sts=2 ts=8 sw=2 tw=99 et: */ +/* 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_gfx_config_gfxFeature_h +#define mozilla_gfx_config_gfxFeature_h + +#include <stdint.h> +#include "gfxTelemetry.h" +#include "mozilla/Assertions.h" +#include "mozilla/Function.h" + +namespace mozilla { +namespace gfx { + +#define GFX_FEATURE_MAP(_) \ + /* Name, Type, Description */ \ + _(HW_COMPOSITING, Feature, "Compositing") \ + _(D3D11_COMPOSITING, Feature, "Direct3D11 Compositing") \ + _(DIRECT2D, Feature, "Direct2D") \ + /* Add new entries above this comment */ + +enum class Feature : uint32_t { +#define MAKE_ENUM(name, type, desc) name, + GFX_FEATURE_MAP(MAKE_ENUM) +#undef MAKE_ENUM + NumValues +}; + +class FeatureState +{ + friend class gfxConfig; + + public: + bool IsEnabled() const; + FeatureStatus GetValue() const; + + void EnableByDefault(); + void DisableByDefault(FeatureStatus aStatus, const char* aMessage); + bool SetDefault(bool aEnable, FeatureStatus aDisableStatus, const char* aDisableMessage); + bool InitOrUpdate(bool aEnable, + FeatureStatus aDisableStatus, + const char* aMessage); + void SetDefaultFromPref(const char* aPrefName, + bool aIsEnablePref, + bool aDefaultValue); + void UserEnable(const char* aMessage); + void UserForceEnable(const char* aMessage); + void UserDisable(const char* aMessage); + void Disable(FeatureStatus aStatus, const char* aMessage); + void ForceDisable(FeatureStatus aStatus, const char* aMessage) { + SetFailed(aStatus, aMessage); + } + void SetFailed(FeatureStatus aStatus, const char* aMessage); + bool MaybeSetFailed(bool aEnable, FeatureStatus aStatus, const char* aMessage); + bool MaybeSetFailed(FeatureStatus aStatus, const char* aMessage); + + // aType is "base", "user", "env", or "runtime". + // aMessage may be null. + typedef mozilla::function<void(const char* aType, + FeatureStatus aStatus, + const char* aMessage)> StatusIterCallback; + void ForEachStatusChange(const StatusIterCallback& aCallback) const; + + private: + void SetUser(FeatureStatus aStatus, const char* aMessage); + void SetEnvironment(FeatureStatus aStatus, const char* aMessage); + void SetRuntime(FeatureStatus aStatus, const char* aMessage); + bool IsForcedOnByUser() const; + bool DisabledByDefault() const; + const char* GetRuntimeMessage() const; + bool IsInitialized() const { + return mDefault.IsInitialized(); + } + + void AssertInitialized() const { + MOZ_ASSERT(IsInitialized()); + } + + private: + struct Instance { + char mMessage[64]; + FeatureStatus mStatus; + + void Set(FeatureStatus aStatus, const char* aMessage = nullptr); + bool IsInitialized() const { + return mStatus != FeatureStatus::Unused; + } + const char* MessageOrNull() const { + return mMessage[0] != '\0' ? mMessage : nullptr; + } + const char* Message() const { + MOZ_ASSERT(MessageOrNull()); + return mMessage; + } + }; + + // The default state is the state we decide on startup, based on the operating + // system or a base preference. + // + // The user state factors in any changes to preferences that the user made. + // + // The environment state factors in any additional decisions made, such as + // availability or blacklisting. + // + // The runtime state factors in any problems discovered at runtime. + Instance mDefault; + Instance mUser; + Instance mEnvironment; + Instance mRuntime; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // mozilla_gfx_config_gfxFeature_h diff --git a/gfx/config/moz.build b/gfx/config/moz.build new file mode 100644 index 0000000000..e060a0bda6 --- /dev/null +++ b/gfx/config/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS += [ + 'gfxConfig.h', + 'gfxFallback.h', + 'gfxFeature.h', +] + +UNIFIED_SOURCES += [ + 'gfxConfig.cpp', + 'gfxFeature.cpp', +] + +FINAL_LIBRARY = 'xul' diff --git a/gfx/ipc/GraphicsMessages.ipdlh b/gfx/ipc/GraphicsMessages.ipdlh index 09fb18416c..7a6c86a0c1 100644 --- a/gfx/ipc/GraphicsMessages.ipdlh +++ b/gfx/ipc/GraphicsMessages.ipdlh @@ -12,7 +12,7 @@ namespace gfx { struct DeviceInitData { - bool useAcceleration; + bool useHwCompositing; // Windows only. bool useD3D11; diff --git a/gfx/layers/BufferTexture.cpp b/gfx/layers/BufferTexture.cpp index c508cc4084..2096793dd3 100644 --- a/gfx/layers/BufferTexture.cpp +++ b/gfx/layers/BufferTexture.cpp @@ -195,41 +195,43 @@ BufferTextureData::CreateForYCbCr(ClientIPCAllocator* aAllocator, aTextureFlags); } -gfx::IntSize -BufferTextureData::GetSize() const -{ - return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor); -} - -gfx::SurfaceFormat -BufferTextureData::GetFormat() const +void +BufferTextureData::FillInfo(TextureData::Info& aInfo) const { - return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor); -} - + aInfo.size = GetSize(); + aInfo.format = GetFormat(); + aInfo.hasSynchronization = false; + aInfo.canExposeMappedData = true; -bool -BufferTextureData::HasIntermediateBuffer() const -{ if (mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor) { - return true; + aInfo.hasIntermediateBuffer = true; + } else { + aInfo.hasIntermediateBuffer = mDescriptor.get_RGBDescriptor().hasIntermediateBuffer(); } - return mDescriptor.get_RGBDescriptor().hasIntermediateBuffer(); -} -bool -BufferTextureData::SupportsMoz2D() const -{ - switch (GetFormat()) { + switch (aInfo.format) { case gfx::SurfaceFormat::YUV: case gfx::SurfaceFormat::NV12: case gfx::SurfaceFormat::UNKNOWN: - return false; + aInfo.supportsMoz2D = false; + break; default: - return true; + aInfo.supportsMoz2D = true; } } +gfx::IntSize +BufferTextureData::GetSize() const +{ + return ImageDataSerializer::SizeFromBufferDescriptor(mDescriptor); +} + +gfx::SurfaceFormat +BufferTextureData::GetFormat() const +{ + return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor); +} + already_AddRefed<gfx::DrawTarget> BufferTextureData::BorrowDrawTarget() { diff --git a/gfx/layers/BufferTexture.h b/gfx/layers/BufferTexture.h index b0ba2aa40c..3e8a4519b9 100644 --- a/gfx/layers/BufferTexture.h +++ b/gfx/layers/BufferTexture.h @@ -41,22 +41,14 @@ class BufferTextureData : public TextureData virtual void Unlock() override {} - virtual gfx::IntSize GetSize() const override; - - virtual gfx::SurfaceFormat GetFormat() const override; + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; - virtual bool CanExposeMappedData() const override { return true; } - virtual bool BorrowMappedData(MappedTextureData& aMap) override; virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) override; - virtual bool SupportsMoz2D() const override; - - virtual bool HasIntermediateBuffer() const override; - // use TextureClient's default implementation virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override; @@ -64,6 +56,10 @@ class BufferTextureData : public TextureData void SetDesciptor(const BufferDescriptor& aDesc); protected: + gfx::IntSize GetSize() const; + + gfx::SurfaceFormat GetFormat() const; + static BufferTextureData* CreateInternal(ClientIPCAllocator* aAllocator, const BufferDescriptor& aDesc, gfx::BackendType aMoz2DBackend, diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 5dbbbc1beb..8f033fcc17 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -21,6 +21,7 @@ #include "nsRegion.h" #include <vector> #include "mozilla/WidgetUtils.h" +#include "CompositorWidgetProxy.h" /** * Different elements of a web pages are rendered into separate "layers" before @@ -189,11 +190,13 @@ class Compositor public: NS_INLINE_DECL_REFCOUNTING(Compositor) - explicit Compositor(CompositorBridgeParent* aParent = nullptr) + explicit Compositor(widget::CompositorWidgetProxy* aWidget, + CompositorBridgeParent* aParent = nullptr) : mCompositorID(0) , mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC) , mParent(aParent) , mScreenRotation(ROTATION_0) + , mWidget(aWidget) { } @@ -204,7 +207,8 @@ class Compositor virtual bool Initialize() = 0; virtual void Destroy() = 0; - virtual void DetachWidget() {} + + virtual void DetachWidget() { mWidget = nullptr; } /** * Return true if the effect type is supported. @@ -472,9 +476,7 @@ class Compositor virtual void ForcePresent() { } - // XXX I expect we will want to move mWidget into this class and implement - // these methods properly. - virtual nsIWidget* GetWidget() const { return nullptr; } + widget::CompositorWidgetProxy* GetWidget() const { return mWidget; } virtual bool HasImageHostOverlays() { return false; } @@ -584,6 +586,8 @@ class Compositor RefPtr<gfx::DrawTarget> mTarget; gfx::IntRect mTargetBounds; + widget::CompositorWidgetProxy* mWidget; + #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 FenceHandle mReleaseFenceHandle; #endif diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 616be12326..eb4d516614 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -1676,7 +1676,7 @@ class Layer { * Returns the current area of the layer (in layer-space coordinates) * marked as needed to be recomposited. */ - const gfx::TiledIntRegion& GetInvalidRegion() { return mInvalidRegion; } + const virtual gfx::TiledIntRegion& GetInvalidRegion() { return mInvalidRegion; } void AddInvalidRegion(const nsIntRegion& aRegion) { mInvalidRegion.Add(aRegion); } diff --git a/gfx/layers/TextureDIB.cpp b/gfx/layers/TextureDIB.cpp index 3f631b5391..4366db27e5 100644 --- a/gfx/layers/TextureDIB.cpp +++ b/gfx/layers/TextureDIB.cpp @@ -117,6 +117,17 @@ class ShmemDIBTextureData : public DIBTextureData HBITMAP mBitmap; }; +void +DIBTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.hasIntermediateBuffer = true; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = true; + aInfo.canExposeMappedData = false; +} + already_AddRefed<gfx::DrawTarget> DIBTextureData::BorrowDrawTarget() { @@ -257,7 +268,7 @@ ShmemDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) bool ShmemDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { - if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) { + if (mFormat == gfx::SurfaceFormat::UNKNOWN) { return false; } diff --git a/gfx/layers/TextureDIB.h b/gfx/layers/TextureDIB.h index cf94da6c42..95fc534e62 100644 --- a/gfx/layers/TextureDIB.h +++ b/gfx/layers/TextureDIB.h @@ -22,16 +22,10 @@ class DIBTextureData : public TextureData virtual void Unlock() override {} - virtual gfx::IntSize GetSize() const override { return mSize; } - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } - - virtual bool SupportsMoz2D() const override { return true; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; - virtual bool HasIntermediateBuffer() const override { return true; } - static DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, ClientIPCAllocator* aAllocator); diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 116678bac5..f7ad9f4150 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -78,9 +78,8 @@ class DataTextureSourceBasic : public DataTextureSource bool mWrappingExistingData; }; -BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent, nsIWidget *aWidget) - : Compositor(aParent) - , mWidget(aWidget) +BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget) + : Compositor(aWidget, aParent) , mDidExternalComposition(false) { MOZ_COUNT_CTOR(BasicCompositor); @@ -119,8 +118,8 @@ void BasicCompositor::DetachWidget() { if (mWidget) { mWidget->CleanupRemoteDrawing(); - mWidget = nullptr; } + Compositor::DetachWidget(); } TextureFactoryIdentifier diff --git a/gfx/layers/basic/BasicCompositor.h b/gfx/layers/basic/BasicCompositor.h index 8824115981..4c03c4e4ae 100644 --- a/gfx/layers/basic/BasicCompositor.h +++ b/gfx/layers/basic/BasicCompositor.h @@ -42,7 +42,7 @@ class BasicCompositingRenderTarget : public CompositingRenderTarget class BasicCompositor : public Compositor { public: - explicit BasicCompositor(CompositorBridgeParent* aParent, nsIWidget *aWidget); + explicit BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy *aWidget); protected: virtual ~BasicCompositor(); @@ -126,15 +126,10 @@ class BasicCompositor : public Compositor return LayersBackend::LAYERS_BASIC; } - virtual nsIWidget* GetWidget() const override { return mWidget; } - gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; } private: - // Widget associated with this compositor - nsIWidget *mWidget; - // The final destination surface RefPtr<gfx::DrawTarget> mDrawTarget; // The current render target for drawing diff --git a/gfx/layers/basic/TextureClientX11.cpp b/gfx/layers/basic/TextureClientX11.cpp index 0d7ff0c333..af7ec93f99 100644 --- a/gfx/layers/basic/TextureClientX11.cpp +++ b/gfx/layers/basic/TextureClientX11.cpp @@ -47,6 +47,16 @@ X11TextureData::Unlock() } } +void +X11TextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.supportsMoz2D = true; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.canExposeMappedData = false; +} bool X11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) diff --git a/gfx/layers/basic/TextureClientX11.h b/gfx/layers/basic/TextureClientX11.h index 69d2f2fcff..82b934b18c 100644 --- a/gfx/layers/basic/TextureClientX11.h +++ b/gfx/layers/basic/TextureClientX11.h @@ -25,16 +25,10 @@ class X11TextureData : public TextureData virtual void Unlock() override; - virtual gfx::IntSize GetSize() const override { return mSize; } - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; - virtual bool SupportsMoz2D() const override { return true; } - - virtual bool HasIntermediateBuffer() const override { return false; } - virtual void Deallocate(ClientIPCAllocator*) override; virtual TextureData* diff --git a/gfx/layers/basic/X11BasicCompositor.h b/gfx/layers/basic/X11BasicCompositor.h index d9efc568d7..43262697e7 100644 --- a/gfx/layers/basic/X11BasicCompositor.h +++ b/gfx/layers/basic/X11BasicCompositor.h @@ -46,7 +46,7 @@ class X11DataTextureSourceBasic : public DataTextureSource class X11BasicCompositor : public BasicCompositor { public: - explicit X11BasicCompositor(CompositorBridgeParent* aParent, nsIWidget *aWidget) + explicit X11BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget) : BasicCompositor(aParent, aWidget) {} diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index 55ae6e6656..5000ee75b1 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -175,7 +175,8 @@ ClientTiledPaintedLayer::BeginPaint() // on this layer. If there is an OMT animation then we need to draw the whole // visible region of this layer as determined by layout, because we don't know // what parts of it might move into view in the compositor. - if (!hasTransformAnimation && + mPaintData.mHasTransformAnimation = hasTransformAnimation; + if (!mPaintData.mHasTransformAnimation && mContentClient->GetLowPrecisionTiledBuffer()) { ParentLayerRect criticalDisplayPort = (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom()) @@ -263,15 +264,6 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } - if (!mPaintData.mCriticalDisplayPort) { - // This catches three scenarios: - // 1) This layer doesn't have a scrolling ancestor - // 2) This layer is subject to OMTA transforms - // 3) Low-precision painting is disabled - // In all of these cases, we don't want to draw this layer progressively. - return false; - } - if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) { // This layer is fixed-position and so even if it does have a scrolling // ancestor it will likely be entirely on-screen all the time, so we @@ -279,10 +271,19 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } + if (mPaintData.mHasTransformAnimation) { + // The compositor is going to animate this somehow, so we want it all + // on the screen at once. + return false; + } + if (ClientManager()->AsyncPanZoomEnabled()) { LayerMetricsWrapper scrollAncestor; GetAncestorLayers(&scrollAncestor, nullptr, nullptr); MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is set + if (!scrollAncestor) { + return false; + } const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); if (!IsScrollingOnCompositor(parentMetrics)) { return false; diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 3ede7dcb7c..c9afbe8271 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -73,7 +73,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) #ifdef XP_WIN if (backend == LayersBackend::LAYERS_D3D11) { - useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D; + useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend(); } else #endif #ifdef MOZ_WIDGET_GTK diff --git a/gfx/layers/client/SingleTiledContentClient.cpp b/gfx/layers/client/SingleTiledContentClient.cpp index 149a1cdc93..1971c8daad 100644 --- a/gfx/layers/client/SingleTiledContentClient.cpp +++ b/gfx/layers/client/SingleTiledContentClient.cpp @@ -51,6 +51,7 @@ ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLay ClientLayerManager* aManager) : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient) , mManager(aManager) + , mWasLastPaintProgressive(false) , mFormat(gfx::SurfaceFormat::UNKNOWN) { } @@ -96,7 +97,8 @@ ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles() 0, 0, 1, 1, 1.0, mFrameResolution.xScale, - mFrameResolution.yScale); + mFrameResolution.yScale, + mWasLastPaintProgressive); } already_AddRefed<TextureClient> @@ -113,8 +115,11 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) + void* aCallbackData, + bool aIsProgressive) { + mWasLastPaintProgressive = aIsProgressive; + // Compare layer valid region size to current backbuffer size, discard if not matching. gfx::IntSize size = aNewValidRegion.GetBounds().Size(); gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); diff --git a/gfx/layers/client/SingleTiledContentClient.h b/gfx/layers/client/SingleTiledContentClient.h index 2486f83cea..42b5359a63 100644 --- a/gfx/layers/client/SingleTiledContentClient.h +++ b/gfx/layers/client/SingleTiledContentClient.h @@ -41,7 +41,8 @@ class ClientSingleTiledLayerBuffer const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) override; + void* aCallbackData, + bool aIsProgressive = false) override; bool SupportsProgressiveUpdate() override { return false; } bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -88,6 +89,7 @@ class ClientSingleTiledLayerBuffer nsIntRegion mPaintedRegion; nsIntRegion mValidRegion; + bool mWasLastPaintProgressive; /** * While we're adding tiles, this is used to keep track of the position of diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 9cc3e4014d..27ce0bfb42 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -97,7 +97,6 @@ class TextureChild final : public ChildActor<PTextureChild> TextureChild() : mForwarder(nullptr) - , mMonitor("TextureChild") , mTextureClient(nullptr) , mTextureData(nullptr) , mDestroyed(false) @@ -117,10 +116,10 @@ class TextureChild final : public ChildActor<PTextureChild> void WaitForCompositorRecycle() { - { - MonitorAutoLock mon(mMonitor); - mWaitForRecycle = mDestroyed ? nullptr : mTextureClient; - } + Lock(); + mWaitForRecycle = mDestroyed ? nullptr : mTextureClient; + Unlock(); + RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get()); MOZ_ASSERT(CanSend()); SendClientRecycle(); @@ -129,10 +128,10 @@ class TextureChild final : public ChildActor<PTextureChild> void CancelWaitForCompositorRecycle() { RECYCLE_LOG("[CLIENT] Cancelling wait for recycle %p\n", mWaitForRecycle.get()); - { - MonitorAutoLock mon(mMonitor); - mWaitForRecycle = nullptr; - } + + Lock(); + mWaitForRecycle = nullptr; + Unlock(); } CompositableForwarder* GetForwarder() { return mForwarder; } @@ -143,6 +142,10 @@ class TextureChild final : public ChildActor<PTextureChild> bool IPCOpen() const { return mIPCOpen; } + void Lock() const { mLock.Enter(); } + + void Unlock() const { mLock.Leave(); } + private: // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor @@ -160,16 +163,11 @@ class TextureChild final : public ChildActor<PTextureChild> Release(); } - void SetTextureClient(TextureClient* aTextureClient) { - MonitorAutoLock mon(mMonitor); - mTextureClient = aTextureClient; - } + mutable gfx::CriticalSection mLock; RefPtr<CompositableForwarder> mForwarder; RefPtr<TextureClient> mWaitForRecycle; - // Monitor protecting mTextureClient. - Monitor mMonitor; TextureClient* mTextureClient; TextureData* mTextureData; Atomic<bool> mDestroyed; @@ -319,12 +317,15 @@ DeallocateTextureClient(TextureDeallocParams params) void TextureClient::Destroy(bool aForceSync) { - MOZ_ASSERT(!IsLocked()); + if (mActor) { + mActor->Lock(); + } RefPtr<TextureChild> actor = mActor; mActor = nullptr; if (actor && !actor->mDestroyed.compareExchange(false, true)) { + actor->Unlock(); actor = nullptr; } @@ -348,6 +349,14 @@ void TextureClient::Destroy(bool aForceSync) // client side, but having asynchronous deallocate in some of the cases will // be a worthwhile optimization. params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync; + + // Release the lock before calling DeallocateTextureClient because the latter + // may wait for the main thread which could create a dead-lock. + + if (actor) { + actor->Unlock(); + } + DeallocateTextureClient(params); } } @@ -360,6 +369,22 @@ TextureClient::DestroyFallback(PTextureChild* aActor) return aActor->SendDestroySync(); } +void +TextureClient::LockActor() const +{ + if (mActor) { + mActor->Lock(); + } +} + +void +TextureClient::UnlockActor() const +{ + if (mActor) { + mActor->Unlock(); + } +} + bool TextureClient::Lock(OpenMode aMode) { @@ -374,6 +399,8 @@ TextureClient::Lock(OpenMode aMode) mRemoveFromCompositableWaiter = nullptr; } + LockActor(); + mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr); mOpenMode = aMode; @@ -395,6 +422,10 @@ TextureClient::Lock(OpenMode aMode) } } + if (!mIsLocked) { + UnlockActor(); + } + return mIsLocked; } @@ -425,27 +456,8 @@ TextureClient::Unlock() mData->Unlock(); mIsLocked = false; mOpenMode = OpenMode::OPEN_NONE; -} - -bool -TextureClient::HasIntermediateBuffer() const -{ - MOZ_ASSERT(IsValid()); - return mData->HasIntermediateBuffer(); -} - -gfx::IntSize -TextureClient::GetSize() const -{ - MOZ_ASSERT(IsValid()); - return mData->GetSize(); -} -gfx::SurfaceFormat -TextureClient::GetFormat() const -{ - MOZ_ASSERT(IsValid()); - return mData->GetFormat(); + UnlockActor(); } TextureClient::~TextureClient() @@ -490,7 +502,16 @@ already_AddRefed<TextureClient> TextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { MOZ_ASSERT(IsValid()); + + MOZ_ASSERT(!mIsLocked); + if (mIsLocked) { + return nullptr; + } + + LockActor(); TextureData* data = mData->CreateSimilar(mAllocator, aFlags, aAllocFlags); + UnlockActor(); + if (!data) { return nullptr; } @@ -538,21 +559,23 @@ TextureClient::BorrowMappedData(MappedTextureData& aMap) // return nullptr; //} - return mData->BorrowMappedData(aMap); + return mData ? mData->BorrowMappedData(aMap) : false; } bool TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) { MOZ_ASSERT(IsValid()); - return mData->BorrowMappedYCbCrData(aMap); + + return mData ? mData->BorrowMappedYCbCrData(aMap) : false; } bool TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) { MOZ_ASSERT(IsValid()); - return mData->Serialize(aOutDescriptor); + + return mData ? mData->Serialize(aOutDescriptor) : false; } void @@ -589,18 +612,29 @@ TextureClient::DestroyIPDLActor(PTextureChild* actor) } // static -TextureClient* +already_AddRefed<TextureClient> TextureClient::AsTextureClient(PTextureChild* actor) { if (!actor) { return nullptr; } + TextureChild* tc = static_cast<TextureChild*>(actor); + + // TODO: This is not entirely race-free because TextureClient's ref count + // can reach zero on another thread and AsTextureClient gets called before + // Destroy. + tc->Lock(); + if (tc->mDestroyed) { + tc->Unlock(); return nullptr; } - return tc->mTextureClient; + RefPtr<TextureClient> texture = tc->mTextureClient; + tc->Unlock(); + + return texture.forget(); } bool @@ -634,6 +668,12 @@ void TextureClient::RecycleTexture(TextureFlags aFlags) { MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE); + MOZ_ASSERT(!mIsLocked); + if (mIsLocked) { + return; + } + + LockActor(); mAddedToCompositableClient = false; if (mFlags != aFlags) { @@ -642,6 +682,8 @@ TextureClient::RecycleTexture(TextureFlags aFlags) mActor->SendRecycleTexture(mFlags); } } + + UnlockActor(); } void @@ -705,6 +747,13 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) mActor->mForwarder = aForwarder; mActor->mTextureClient = this; mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD); + + // If the TextureClient is already locked, we have to lock TextureChild's mutex + // since it will be unlocked in TextureClient::Unlock. + if (mIsLocked) { + LockActor(); + } + return mActor->IPCOpen(); } @@ -921,6 +970,7 @@ TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, ClientIPCA , mPoolTracker(nullptr) #endif { + mData->FillInfo(mInfo); mFlags |= mData->GetTextureFlags(); } @@ -983,6 +1033,22 @@ TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) mRemoveFromCompositableWaiter = aWaiter; } +already_AddRefed<gfx::DataSourceSurface> +TextureClient::GetAsSurface() +{ + Lock(OpenMode::OPEN_READ); + RefPtr<gfx::DataSourceSurface> data; + RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget(); + if (dt) { + RefPtr<gfx::SourceSurface> surf = dt->Snapshot(); + if (surf) { + data = surf->GetDataSurface(); + } + } + Unlock(); + return data.forget(); +} + void TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix) { diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 6116e429b7..8762808925 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -24,6 +24,7 @@ #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/mozalloc.h" // for operator delete +#include "mozilla/gfx/CriticalSection.h" #include "nsAutoPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed #include "nsISupportsImpl.h" // for TextureImage::AddRef, etc @@ -181,26 +182,33 @@ class D3D11TextureData; class TextureData { public: + struct Info { + gfx::IntSize size; + gfx::SurfaceFormat format; + bool hasIntermediateBuffer; + bool hasSynchronization; + bool supportsMoz2D; + bool canExposeMappedData; + + Info() + : format(gfx::SurfaceFormat::UNKNOWN) + , hasIntermediateBuffer(false) + , hasSynchronization(false) + , supportsMoz2D(false) + , canExposeMappedData(false) + {} + }; + TextureData() { MOZ_COUNT_CTOR(TextureData); } virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); } - virtual gfx::IntSize GetSize() const = 0; - - virtual gfx::SurfaceFormat GetFormat() const = 0; + virtual void FillInfo(TextureData::Info& aInfo) const = 0; virtual bool Lock(OpenMode aMode, FenceHandle* aFence) = 0; virtual void Unlock() = 0; - virtual bool SupportsMoz2D() const { return false; } - - virtual bool CanExposeMappedData() const { return false; } - - virtual bool HasIntermediateBuffer() const = 0; - - virtual bool HasSynchronization() const { return false; } - virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() { return nullptr; } virtual bool BorrowMappedData(MappedTextureData&) { return false; } @@ -327,9 +335,29 @@ class TextureClient bool IsLocked() const { return mIsLocked; } - bool CanExposeDrawTarget() const { return mData->SupportsMoz2D(); } + gfx::IntSize GetSize() const { return mInfo.size; } + + gfx::SurfaceFormat GetFormat() const { return mInfo.format; } + + /** + * Returns true if this texture has a synchronization mechanism (mutex, fence, etc.). + * Textures that do not implement synchronization should be immutable or should + * use immediate uploads (see TextureFlags in CompositorTypes.h) + * Even if a texture does not implement synchronization, Lock and Unlock need + * to be used appropriately since the latter are also there to map/numap data. + */ + bool HasSynchronization() const { return mInfo.hasSynchronization; } + + /** + * Indicates whether the TextureClient implementation is backed by an + * in-memory buffer. The consequence of this is that locking the + * TextureClient does not contend with locking the texture on the host side. + */ + bool HasIntermediateBuffer() const { return mInfo.hasIntermediateBuffer; } + + bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; } - bool CanExposeMappedData() const { return mData->CanExposeMappedData(); } + bool CanExposeMappedData() const { return mInfo.canExposeMappedData; } /** * Returns a DrawTarget to draw into the TextureClient. @@ -372,25 +400,11 @@ class TextureClient */ void UpdateFromSurface(gfx::SourceSurface* aSurface); - virtual gfx::SurfaceFormat GetFormat() const; - /** * This method is strictly for debugging. It causes locking and * needless copies. */ - already_AddRefed<gfx::DataSourceSurface> GetAsSurface() { - Lock(OpenMode::OPEN_READ); - RefPtr<gfx::DataSourceSurface> data; - RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget(); - if (dt) { - RefPtr<gfx::SourceSurface> surf = dt->Snapshot(); - if (surf) { - data = surf->GetDataSurface(); - } - } - Unlock(); - return data.forget(); - } + already_AddRefed<gfx::DataSourceSurface> GetAsSurface(); virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); @@ -403,22 +417,6 @@ class TextureClient const gfx::IntRect* aRect, const gfx::IntPoint* aPoint); - /** - * Returns true if this texture has a synchronization mechanism (mutex, fence, etc.). - * Textures that do not implement synchronization should be immutable or should - * use immediate uploads (see TextureFlags in CompositorTypes.h) - * Even if a texture does not implement synchronization, Lock and Unlock need - * to be used appropriately since the latter are also there to map/numap data. - */ - bool HasSynchronization() const { return false; } - - /** - * Indicates whether the TextureClient implementation is backed by an - * in-memory buffer. The consequence of this is that locking the - * TextureClient does not contend with locking the texture on the host side. - */ - bool HasIntermediateBuffer() const; - /** * Allocate and deallocate a TextureChild actor. * @@ -435,9 +433,7 @@ class TextureClient /** * Get the TextureClient corresponding to the actor passed in parameter. */ - static TextureClient* AsTextureClient(PTextureChild* actor); - - gfx::IntSize GetSize() const; + static already_AddRefed<TextureClient> AsTextureClient(PTextureChild* actor); /** * TextureFlags contain important information about various aspects @@ -456,6 +452,7 @@ class TextureClient void RemoveFlags(TextureFlags aFlags); + // The TextureClient must not be locked when calling this method. void RecycleTexture(TextureFlags aFlags); /** @@ -505,6 +502,7 @@ class TextureClient * Create and init the TextureChild/Parent IPDL actor pair. * * Should be called only once per TextureClient. + * The TextureClient must not be locked when calling this method. */ bool InitIPDLActor(CompositableForwarder* aForwarder); @@ -618,6 +616,10 @@ class TextureClient */ bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor); + void LockActor() const; + void UnlockActor() const; + + TextureData::Info mInfo; RefPtr<ClientIPCAllocator> mAllocator; RefPtr<TextureChild> mActor; diff --git a/gfx/layers/client/TextureClientSharedSurface.cpp b/gfx/layers/client/TextureClientSharedSurface.cpp index 58a740035e..7fe4fb5afe 100644 --- a/gfx/layers/client/TextureClientSharedSurface.cpp +++ b/gfx/layers/client/TextureClientSharedSurface.cpp @@ -35,10 +35,15 @@ void SharedSurfaceTextureData::Deallocate(ClientIPCAllocator*) {} -gfx::IntSize -SharedSurfaceTextureData::GetSize() const +void +SharedSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const { - return mSurf->mSize; + aInfo.size = mSurf->mSize; + aInfo.format = gfx::SurfaceFormat::UNKNOWN; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = false; + aInfo.canExposeMappedData = false; } bool diff --git a/gfx/layers/client/TextureClientSharedSurface.h b/gfx/layers/client/TextureClientSharedSurface.h index 3913737eac..01899661ce 100644 --- a/gfx/layers/client/TextureClientSharedSurface.h +++ b/gfx/layers/client/TextureClientSharedSurface.h @@ -44,13 +44,7 @@ class SharedSurfaceTextureData : public TextureData virtual void Unlock() override {} - virtual bool HasIntermediateBuffer() const override { return false; } - - virtual gfx::SurfaceFormat GetFormat() const override { - return gfx::SurfaceFormat::UNKNOWN; - } - - virtual gfx::IntSize GetSize() const override; + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 5895a785d5..213e6a60f0 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -506,7 +506,7 @@ TileClient::PrivateProtector::Set(TileClient * const aContainer, TextureClient* // Placeholder TileClient::TileClient() - : mCompositableClient(nullptr) + : mCompositableClient(nullptr), mWasPlaceholder(false) { } @@ -527,6 +527,7 @@ TileClient::TileClient(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; + mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -548,6 +549,7 @@ TileClient::operator=(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; + mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -832,9 +834,12 @@ TileDescriptor TileClient::GetTileDescriptor() { if (IsPlaceholderTile()) { + mWasPlaceholder = true; return PlaceholderTileDescriptor(); } MOZ_ASSERT(mFrontLock); + bool wasPlaceholder = mWasPlaceholder; + mWasPlaceholder = false; if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) { // AddRef here and Release when receiving on the host side to make sure the // reference count doesn't go to zero before the host receives the message. @@ -846,13 +851,15 @@ TileClient::GetTileDescriptor() return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(uintptr_t(mFrontLock.get()))); + TileLock(uintptr_t(mFrontLock.get())), + wasPlaceholder); } else { gfxShmSharedReadLock *lock = static_cast<gfxShmSharedReadLock*>(mFrontLock.get()); return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(lock->GetShmemSection())); + TileLock(lock->GetShmemSection()), + wasPlaceholder); } } @@ -879,12 +886,7 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() InfallibleTArray<TileDescriptor> tiles; for (TileClient& tile : mRetainedTiles) { - TileDescriptor tileDesc; - if (tile.IsPlaceholderTile()) { - tileDesc = PlaceholderTileDescriptor(); - } else { - tileDesc = tile.GetTileDescriptor(); - } + TileDescriptor tileDesc = tile.GetTileDescriptor(); tiles.AppendElement(tileDesc); // Reset the update rect tile.mUpdateRect = IntRect(); @@ -895,7 +897,8 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() mTiles.mFirst.x, mTiles.mFirst.y, mTiles.mSize.width, mTiles.mSize.height, mResolution, mFrameResolution.xScale, - mFrameResolution.yScale); + mFrameResolution.yScale, + mWasLastPaintProgressive); } void @@ -903,13 +906,15 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) + void* aCallbackData, + bool aIsProgressive) { TILING_LOG("TILING %p: PaintThebes painting region %s\n", mPaintedLayer, Stringify(aPaintRegion).c_str()); TILING_LOG("TILING %p: PaintThebes new valid region %s\n", mPaintedLayer, Stringify(aNewValidRegion).c_str()); mCallback = aCallback; mCallbackData = aCallbackData; + mWasLastPaintProgressive = aIsProgressive; #ifdef GFX_TILEDLAYER_PREF_WARNINGS long start = PR_IntervalNow(); @@ -1651,7 +1656,7 @@ ClientMultiTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion, // Paint the computed region and subtract it from the invalid region. PaintThebes(validOrStale, regionToPaint, aInvalidRegion, - aCallback, aCallbackData); + aCallback, aCallbackData, true); aInvalidRegion.Sub(aInvalidRegion, regionToPaint); } while (repeat); @@ -1691,6 +1696,7 @@ BasicTiledLayerPaintData::ResetPaintData() { mLowPrecisionPaintCount = 0; mPaintFinished = false; + mHasTransformAnimation = false; mCompositionBounds.SetEmpty(); mCriticalDisplayPort = Nothing(); } diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 3c75c8c0d4..82c103ef08 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -276,6 +276,7 @@ struct TileClient RefPtr<TextureClientAllocator> mAllocator; gfx::IntRect mUpdateRect; CompositableClient* mCompositableClient; + bool mWasPlaceholder; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY TimeStamp mLastUpdate; #endif @@ -354,6 +355,11 @@ struct BasicTiledLayerPaintData { */ bool mPaintFinished : 1; + /* + * Whether or not there is an async transform animation active + */ + bool mHasTransformAnimation : 1; + /* * Initializes/clears data to prepare for paint action. */ @@ -408,13 +414,15 @@ class ClientTiledLayerBuffer , mCompositableClient(aCompositableClient) , mLastPaintContentType(gfxContentType::COLOR) , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE) + , mWasLastPaintProgressive(false) {} virtual void PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) = 0; + void* aCallbackData, + bool aIsProgressive = false) = 0; virtual bool SupportsProgressiveUpdate() = 0; virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -449,6 +457,8 @@ class ClientTiledLayerBuffer gfxContentType mLastPaintContentType; SurfaceMode mLastPaintSurfaceMode; CSSToParentLayerScale2D mFrameResolution; + + bool mWasLastPaintProgressive; }; class ClientMultiTiledLayerBuffer @@ -475,7 +485,8 @@ class ClientMultiTiledLayerBuffer const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) override; + void* aCallbackData, + bool aIsProgressive = false) override; virtual bool SupportsProgressiveUpdate() override { return true; } /** diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index e5bd38f7df..c3afde9386 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -59,6 +59,10 @@ class ContentHost : public CompositableHost virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; } bool PaintWillResample() { return mPaintWillResample; } + // We use this to allow TiledContentHost to invalidate regions where + // tiles are fading in. + virtual void AddAnimationInvalidation(nsIntRegion& aRegion) { } + protected: explicit ContentHost(const TextureInfo& aTextureInfo) : CompositableHost(aTextureInfo) diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 73fdeedf45..35ce432398 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -853,7 +853,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi if (!mTarget && !haveLayerEffects && gfxPrefs::Composer2DCompositionEnabled() && composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot, - mCompositor->GetWidget(), + mCompositor->GetWidget()->RealWidget(), mGeometryChanged, mCompositor->HasImageHostOverlays())) { @@ -942,12 +942,13 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi js::ProfileEntry::Category::GRAPHICS); mCompositor->EndFrame(); - mCompositor->SetDispAcquireFence(mRoot, - mCompositor->GetWidget()); // Call after EndFrame() + + // Call after EndFrame() + mCompositor->SetDispAcquireFence(mRoot, mCompositor->GetWidget()->RealWidget()); } if (composer2D) { - composer2D->Render(mCompositor->GetWidget()); + composer2D->Render(mCompositor->GetWidget()->RealWidget()); } mCompositor->GetWidget()->PostRender(this); @@ -1546,7 +1547,7 @@ LayerComposite::SetLayerManager(LayerManagerComposite* aManager) bool LayerManagerComposite::AsyncPanZoomEnabled() const { - return mCompositor->GetWidget()->AsyncPanZoomEnabled(); + return mCompositor->GetWidget()->RealWidget()->AsyncPanZoomEnabled(); } nsIntRegion diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index 06f09db847..88af9e2624 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -179,5 +179,16 @@ PaintedLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix } } +const gfx::TiledIntRegion& +PaintedLayerComposite::GetInvalidRegion() +{ + if (mBuffer) { + nsIntRegion region = mInvalidRegion.GetRegion(); + mBuffer->AddAnimationInvalidation(region); + } + return mInvalidRegion; +} + + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/PaintedLayerComposite.h b/gfx/layers/composite/PaintedLayerComposite.h index c4107d6a9b..fbf86390e9 100644 --- a/gfx/layers/composite/PaintedLayerComposite.h +++ b/gfx/layers/composite/PaintedLayerComposite.h @@ -73,6 +73,8 @@ class PaintedLayerComposite : public PaintedLayer, Mutated(); } + const virtual gfx::TiledIntRegion& GetInvalidRegion() override; + MOZ_LAYER_DECL_NAME("PaintedLayerComposite", TYPE_PAINTED) protected: diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index c425cf8484..1614db9c3c 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -10,6 +10,7 @@ #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/Compositor.h" // for Compositor +//#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL @@ -27,6 +28,26 @@ namespace layers { class Layer; +float +TileHost::GetFadeInOpacity(float aOpacity) +{ + TimeStamp now = TimeStamp::Now(); + if (!gfxPrefs::LayerTileFadeInEnabled() || + mFadeStart.IsNull() || + now < mFadeStart) + { + return aOpacity; + } + + float duration = gfxPrefs::LayerTileFadeInDuration(); + float elapsed = (now - mFadeStart).ToMilliseconds(); + if (elapsed > duration) { + mFadeStart = TimeStamp(); + return aOpacity; + } + return aOpacity * (elapsed / duration); +} + TiledLayerBufferComposite::TiledLayerBufferComposite() : mFrameResolution() {} @@ -49,6 +70,21 @@ TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor) } } +void +TiledLayerBufferComposite::AddAnimationInvalidation(nsIntRegion& aRegion) +{ + // We need to invalidate rects where we have a tile that is in the + // process of fading in. + for (size_t i = 0; i < mRetainedTiles.Length(); i++) { + if (!mRetainedTiles[i].mFadeStart.IsNull()) { + TileIntPoint position = mTiles.TilePosition(i); + IntPoint offset = GetTileOffset(position); + nsIntRegion tileRegion = IntRect(offset, GetScaledTileSize()); + aRegion.OrWith(tileRegion); + } + } +} + TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo) : ContentHost(aTextureInfo) , mTiledBuffer(TiledLayerBufferComposite()) @@ -247,6 +283,14 @@ class TextureSourceRecycler } } + void RecycleTileFading(TileHost& aTile) { + for (size_t i = 0; i < mTiles.Length(); i++) { + if (mTiles[i].mTextureHost == aTile.mTextureHost) { + aTile.mFadeStart = mTiles[i].mFadeStart; + } + } + } + protected: nsTArray<TileHost> mTiles; size_t mFirstPossibility; @@ -324,6 +368,20 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles, // If this same tile texture existed in the old tile set then this will move the texture // source into our new tile. oldRetainedTiles.RecycleTextureSourceForTile(tile); + + // If this tile is in the process of fading, we need to keep that going + oldRetainedTiles.RecycleTileFading(tile); + + if (aTiles.isProgressive() && + texturedDesc.wasPlaceholder()) + { + // This is a progressive paint, and the tile used to be a placeholder. + // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled) + tile.mFadeStart = TimeStamp::Now(); + + aCompositor->CompositeUntil(tile.mFadeStart + + TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration())); + } } // Step 3, attempt to recycle unused texture sources from the old tile set into new tiles. @@ -501,6 +559,7 @@ TiledContentHost::RenderTile(TileHost& aTile, return; } + float opacity = aTile.GetFadeInOpacity(aOpacity); aEffectChain.mPrimaryEffect = effect; for (auto iter = aScreenRegion.RectIter(); !iter.Done(); iter.Next()) { @@ -513,7 +572,7 @@ TiledContentHost::RenderTile(TileHost& aTile, textureRect.y / aTextureBounds.height, textureRect.width / aTextureBounds.width, textureRect.height / aTextureBounds.height); - mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform, aVisibleRect); + mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect); } DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE; if (aTile.mTextureHostOnWhite) { @@ -649,5 +708,12 @@ TiledContentHost::Dump(std::stringstream& aStream, TextureDumpMode::DoNotCompress /* compression not supported on host side */); } +void +TiledContentHost::AddAnimationInvalidation(nsIntRegion& aRegion) +{ + return mTiledBuffer.AddAnimationInvalidation(aRegion); +} + + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index df22473a70..d8bb85866b 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -111,6 +111,14 @@ class TileHost { CompositableHost::DumpTextureHost(aStream, mTextureHost); } + /** + * This does a linear tween of the passed opacity (which is assumed + * to be between 0.0 and 1.0). The duration of the fade is controlled + * by the 'layers.tiles.fade-in.duration-ms' preference. It is enabled + * via 'layers.tiles.fade-in.enabled' + */ + float GetFadeInOpacity(float aOpacity); + RefPtr<gfxSharedReadLock> mSharedLock; CompositableTextureHostRef mTextureHost; CompositableTextureHostRef mTextureHostOnWhite; @@ -118,6 +126,7 @@ class TileHost { mutable CompositableTextureSourceRef mTextureSourceOnWhite; // This is not strictly necessary but makes debugging whole lot easier. TileIntPoint mTilePosition; + TimeStamp mFadeStart; }; class TiledLayerBufferComposite @@ -146,6 +155,7 @@ class TiledLayerBufferComposite void SetCompositor(Compositor* aCompositor); + void AddAnimationInvalidation(nsIntRegion& aRegion); protected: CSSToParentLayerScale2D mFrameResolution; @@ -263,6 +273,8 @@ class TiledContentHost : public ContentHost virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + virtual void AddAnimationInvalidation(nsIntRegion& aRegion) override; + private: void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index ce4da6bf7e..a9c4c922c0 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -17,6 +17,7 @@ #include "mozilla/layers/Effects.h" #include "nsWindowsHelpers.h" #include "gfxPrefs.h" +#include "gfxConfig.h" #include "gfxCrashReporterUtils.h" #include "gfxVR.h" #include "mozilla/gfx/StackArray.h" @@ -158,10 +159,9 @@ struct DeviceAttachmentsD3D11 bool mInitOkay; }; -CompositorD3D11::CompositorD3D11(CompositorBridgeParent* aParent, nsIWidget* aWidget) - : Compositor(aParent) +CompositorD3D11::CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget) + : Compositor(aWidget, aParent) , mAttachments(nullptr) - , mWidget(aWidget) , mHwnd(nullptr) , mDisableSequenceForNextFrame(false) , mVerifyBuffersFailed(false) @@ -196,11 +196,9 @@ CompositorD3D11::~CompositorD3D11() bool CompositorD3D11::Initialize() { - bool force = gfxPrefs::LayersAccelerationForceEnabled(); + ScopedGfxFeatureReporter reporter("D3D11 Layers"); - ScopedGfxFeatureReporter reporter("D3D11 Layers", force); - - MOZ_ASSERT(gfxPlatform::CanUseDirect3D11()); + MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)); HRESULT hr; @@ -217,7 +215,7 @@ CompositorD3D11::Initialize() mFeatureLevel = mDevice->GetFeatureLevel(); - mHwnd = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW); + mHwnd = (HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW); memset(&mVSConstants, 0, sizeof(VertexShaderConstants)); @@ -540,27 +538,31 @@ CompositorD3D11::CreateTexture(const gfx::IntRect& aRect, const CompositingRenderTargetD3D11* sourceD3D11 = static_cast<const CompositingRenderTargetD3D11*>(aSource); - D3D11_BOX srcBox; - srcBox.left = aSourcePoint.x; - srcBox.top = aSourcePoint.y; - srcBox.front = 0; - srcBox.right = aSourcePoint.x + aRect.width; - srcBox.bottom = aSourcePoint.y + aRect.height; - srcBox.back = 1; - const IntSize& srcSize = sourceD3D11->GetSize(); MOZ_ASSERT(srcSize.width >= 0 && srcSize.height >= 0, "render targets should have nonnegative sizes"); - if (srcBox.left < srcBox.right && - srcBox.top < srcBox.bottom && - srcBox.right <= static_cast<uint32_t>(srcSize.width) && - srcBox.bottom <= static_cast<uint32_t>(srcSize.height)) { + + IntRect srcRect(IntPoint(), srcSize); + IntRect copyRect(aSourcePoint, aRect.Size()); + if (!srcRect.Contains(copyRect)) { + NS_WARNING("Could not copy the whole copy rect from the render target"); + } + + copyRect = copyRect.Intersect(srcRect); + + if (!copyRect.IsEmpty()) { + D3D11_BOX copyBox; + copyBox.front = 0; + copyBox.back = 1; + copyBox.left = copyRect.x; + copyBox.top = copyRect.y; + copyBox.right = copyRect.XMost(); + copyBox.bottom = copyRect.YMost(); + mContext->CopySubresourceRegion(texture, 0, 0, 0, 0, sourceD3D11->GetD3D11Texture(), 0, - &srcBox); - } else { - NS_WARNING("Could not copy render target - source rect out of bounds"); + &copyBox); } } @@ -1283,6 +1285,19 @@ CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize) PrepareViewport(aSize, projection, 0.0f, 1.0f); } +void +CompositorD3D11::ForcePresent() +{ + LayoutDeviceIntSize size = mWidget->GetClientSize(); + + DXGI_SWAP_CHAIN_DESC desc; + mSwapChain->GetDesc(&desc); + + if (desc.BufferDesc.Width == size.width && desc.BufferDesc.Height == size.height) { + mSwapChain->Present(0, 0); + } +} + void CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize, const gfx::Matrix4x4& aProjection, @@ -1304,10 +1319,7 @@ CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize, void CompositorD3D11::EnsureSize() { - LayoutDeviceIntRect rect; - mWidget->GetClientBounds(rect); - - mSize = rect.Size(); + mSize = mWidget->GetClientSize(); } bool diff --git a/gfx/layers/d3d11/CompositorD3D11.h b/gfx/layers/d3d11/CompositorD3D11.h index 12cf8c54ba..23844f94b1 100644 --- a/gfx/layers/d3d11/CompositorD3D11.h +++ b/gfx/layers/d3d11/CompositorD3D11.h @@ -42,14 +42,13 @@ struct DeviceAttachmentsD3D11; class CompositorD3D11 : public Compositor { public: - CompositorD3D11(CompositorBridgeParent* aParent, nsIWidget* aWidget); + CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget); ~CompositorD3D11(); virtual CompositorD3D11* AsCompositorD3D11() override { return this; } virtual bool Initialize() override; virtual void Destroy() override {} - virtual void DetachWidget() override { mWidget = nullptr; } virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override; @@ -147,9 +146,7 @@ class CompositorD3D11 : public Compositor return LayersBackend::LAYERS_D3D11; } - virtual void ForcePresent() { mSwapChain->Present(0, 0); } - - virtual nsIWidget* GetWidget() const override { return mWidget; } + virtual void ForcePresent(); ID3D11Device* GetDevice() { return mDevice; } @@ -191,8 +188,6 @@ class CompositorD3D11 : public Compositor DeviceAttachmentsD3D11* mAttachments; - nsIWidget* mWidget; - LayoutDeviceIntSize mSize; HWND mHwnd; diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 7f8ab65d21..42c22cb064 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -283,11 +283,11 @@ DXGITextureData::PrepareDrawTargetInLock(OpenMode aMode) } if (mNeedsClear) { - mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); + mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height)); mNeedsClear = false; } if (mNeedsClearWhite) { - mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); + mDrawTarget->FillRect(Rect(0, 0, mSize.width, mSize.height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); mNeedsClearWhite = false; } @@ -300,6 +300,17 @@ D3D11TextureData::Unlock() UnlockD3DTexture(mTexture.get()); } + +void +DXGITextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.supportsMoz2D = true; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = mHasSynchronization; +} + void D3D11TextureData::SyncWithObject(SyncObject* aSyncObject) { @@ -498,12 +509,22 @@ DXGIYCbCrTextureData::Create(ClientIPCAllocator* aAllocator, aSize, aSizeY, aSizeCbCr); } +void +DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = gfx::SurfaceFormat::YUV; + aInfo.supportsMoz2D = false; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; +} + bool DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { aOutDescriptor = SurfaceDescriptorDXGIYCbCr( (WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2], - GetSize(), mSizeY, mSizeCbCr + mSize, mSizeY, mSizeCbCr ); return true; } diff --git a/gfx/layers/d3d11/TextureD3D11.h b/gfx/layers/d3d11/TextureD3D11.h index a844a3b932..ddaa71b38a 100644 --- a/gfx/layers/d3d11/TextureD3D11.h +++ b/gfx/layers/d3d11/TextureD3D11.h @@ -24,15 +24,7 @@ class CompositorD3D11; class DXGITextureData : public TextureData { public: - virtual gfx::IntSize GetSize() const override { return mSize; } - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } - - virtual bool SupportsMoz2D() const override { return true; } - - virtual bool HasIntermediateBuffer() const override { return false; } - - virtual bool HasSynchronization() const override { return mHasSynchronization; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Serialize(SurfaceDescriptor& aOutDescrptor) override; @@ -139,16 +131,9 @@ class DXGIYCbCrTextureData : public TextureData virtual void Unlock() override {} - virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; - - // TODO - DXGIYCbCrTextureClient returned true but that looks like a mistake - virtual bool HasIntermediateBuffer() const override{ return false; } - - virtual gfx::IntSize GetSize() const override { return mSize; } + virtual void FillInfo(TextureData::Info& aInfo) const override; - virtual gfx::SurfaceFormat GetFormat() const override { return gfx::SurfaceFormat::YUV; } - - virtual bool SupportsMoz2D() const override { return false; } + virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override { return nullptr; } diff --git a/gfx/layers/d3d9/CompositorD3D9.cpp b/gfx/layers/d3d9/CompositorD3D9.cpp index e0b5890f31..6977b0c99a 100644 --- a/gfx/layers/d3d9/CompositorD3D9.cpp +++ b/gfx/layers/d3d9/CompositorD3D9.cpp @@ -23,9 +23,8 @@ namespace layers { using namespace mozilla::gfx; -CompositorD3D9::CompositorD3D9(CompositorBridgeParent* aParent, nsIWidget *aWidget) - : Compositor(aParent) - , mWidget(aWidget) +CompositorD3D9::CompositorD3D9(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget) + : Compositor(aWidget, aParent) , mDeviceResetCount(0) , mFailedResetAttempts(0) { @@ -40,9 +39,7 @@ CompositorD3D9::~CompositorD3D9() bool CompositorD3D9::Initialize() { - bool force = gfxPrefs::LayersAccelerationForceEnabled(); - - ScopedGfxFeatureReporter reporter("D3D9 Layers", force); + ScopedGfxFeatureReporter reporter("D3D9 Layers"); MOZ_ASSERT(gfxPlatform::CanUseDirect3D9()); @@ -52,7 +49,7 @@ CompositorD3D9::Initialize() } mSwapChain = mDeviceManager-> - CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); + CreateSwapChain((HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW)); if (!mSwapChain) { return false; @@ -597,7 +594,7 @@ CompositorD3D9::EnsureSwapChain() if (!mSwapChain) { mSwapChain = mDeviceManager-> - CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); + CreateSwapChain((HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW)); // We could not create a swap chain, return false if (!mSwapChain) { // Check the state of the device too @@ -765,10 +762,7 @@ CompositorD3D9::PrepareViewport(const gfx::IntSize& aSize) void CompositorD3D9::EnsureSize() { - LayoutDeviceIntRect rect; - mWidget->GetClientBounds(rect); - - mSize = rect.Size(); + mSize = mWidget->GetClientSize(); } void diff --git a/gfx/layers/d3d9/CompositorD3D9.h b/gfx/layers/d3d9/CompositorD3D9.h index 3b67870f32..bf8da34d44 100644 --- a/gfx/layers/d3d9/CompositorD3D9.h +++ b/gfx/layers/d3d9/CompositorD3D9.h @@ -21,14 +21,13 @@ namespace layers { class CompositorD3D9 : public Compositor { public: - CompositorD3D9(CompositorBridgeParent* aParent, nsIWidget *aWidget); + CompositorD3D9(CompositorBridgeParent* aParent, widget::CompositorWidgetProxy* aWidget); ~CompositorD3D9(); virtual CompositorD3D9* AsCompositorD3D9() override { return this; } virtual bool Initialize() override; virtual void Destroy() override {} - virtual void DetachWidget() override { mWidget = nullptr; } virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override; @@ -87,8 +86,6 @@ class CompositorD3D9 : public Compositor return LayersBackend::LAYERS_D3D9; } - virtual nsIWidget* GetWidget() const override { return mWidget; } - IDirect3DDevice9* device() const { // If the reset counts don't match it means the device was lost and we are @@ -176,9 +173,6 @@ class CompositorD3D9 : public Compositor /* Swap chain associated with this compositor */ RefPtr<SwapChainD3D9> mSwapChain; - /* Widget associated with this layer manager */ - nsIWidget *mWidget; - RefPtr<CompositingRenderTargetD3D9> mDefaultRT; RefPtr<CompositingRenderTargetD3D9> mCurrentRT; diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index f27a9bb6be..be002ca632 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -592,6 +592,17 @@ D3D9TextureData::CreateSimilar(ClientIPCAllocator*, TextureFlags aFlags, Texture return D3D9TextureData::Create(mSize, mFormat, aAllocFlags); } +void +D3D9TextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.hasIntermediateBuffer = true; + aInfo.supportsMoz2D = true; + aInfo.canExposeMappedData = false; + aInfo.hasSynchronization = false; +} + bool D3D9TextureData::Lock(OpenMode aMode, FenceHandle*) { @@ -668,11 +679,11 @@ D3D9TextureData::BorrowDrawTarget() } if (mNeedsClear) { - dt->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); + dt->ClearRect(Rect(0, 0, mSize.width, mSize.height)); mNeedsClear = false; } if (mNeedsClearWhite) { - dt->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); + dt->FillRect(Rect(0, 0, mSize.width, mSize.height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); mNeedsClearWhite = false; } @@ -774,6 +785,17 @@ DXGID3D9TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, return data; } +void +DXGID3D9TextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = GetSize(); + aInfo.format = mFormat; + aInfo.supportsMoz2D = false; + aInfo.canExposeMappedData = false; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; +} + already_AddRefed<IDirect3DSurface9> DXGID3D9TextureData::GetD3D9Surface() const { diff --git a/gfx/layers/d3d9/TextureD3D9.h b/gfx/layers/d3d9/TextureD3D9.h index f31848fafe..c12a099d6c 100644 --- a/gfx/layers/d3d9/TextureD3D9.h +++ b/gfx/layers/d3d9/TextureD3D9.h @@ -182,21 +182,15 @@ class D3D9TextureData : public TextureData public: ~D3D9TextureData(); - virtual bool SupportsMoz2D() const override { return true; } - - virtual bool HasIntermediateBuffer() const override { return true; } - virtual bool Serialize(SurfaceDescriptor& aOutDescrptor) override; virtual bool Lock(OpenMode aMode, FenceHandle*) override; virtual void Unlock() override; - virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } + virtual void FillInfo(TextureData::Info& aInfo) const override; - virtual gfx::IntSize GetSize() const override { return mSize; } + virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override; @@ -236,9 +230,7 @@ class DXGID3D9TextureData : public TextureData ~DXGID3D9TextureData(); - virtual gfx::IntSize GetSize() const override { return gfx::IntSize(mDesc.Width, mDesc.Height); } - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Lock(OpenMode, FenceHandle*) override { return true; } @@ -246,8 +238,6 @@ class DXGID3D9TextureData : public TextureData virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; - virtual bool HasIntermediateBuffer() const override { return false; } - virtual void Deallocate(ClientIPCAllocator* aAllocator) override {} IDirect3DDevice9* GetD3D9Device() { return mDevice; } @@ -260,6 +250,8 @@ class DXGID3D9TextureData : public TextureData return mDesc; } + gfx::IntSize GetSize() const { return gfx::IntSize(mDesc.Width, mDesc.Height); } + protected: DXGID3D9TextureData(gfx::SurfaceFormat aFormat, IDirect3DTexture9* aTexture, HANDLE aHandle, diff --git a/gfx/layers/ipc/AsyncTransactionTracker.cpp b/gfx/layers/ipc/AsyncTransactionTracker.cpp index b72687282b..776a01702f 100755 --- a/gfx/layers/ipc/AsyncTransactionTracker.cpp +++ b/gfx/layers/ipc/AsyncTransactionTracker.cpp @@ -34,6 +34,10 @@ AsyncTransactionWaiter::WaitComplete() if (mWaitCount > 0) { printf_stderr("Timeout of waiting transaction complete."); } + + if (count == maxCount) { + gfxDevCrash(LogReason::AsyncTransactionTimeout) << "Bug 1244883: AsyncTransactionWaiter timed out."; + } } Atomic<uint64_t> AsyncTransactionTracker::sSerialCounter(0); diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index a76d819939..7d71907ecc 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -319,14 +319,8 @@ CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint LayoutDeviceIntRect visibleBounds; // If the plugin is visible update it's geometry. if (isVisible) { - // bounds (content origin) - don't pass true to Resize, it triggers a - // sync paint update to the plugin process on Windows, which happens - // prior to clipping information being applied. + // Set bounds (content origin) bounds = aPlugins[pluginsIdx].bounds(); - rv = widget->Resize(aContentOffset.x + bounds.x, - aContentOffset.y + bounds.y, - bounds.width, bounds.height, false); - NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); nsTArray<LayoutDeviceIntRect> rectsOut; // This call may change the value of isVisible CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(), @@ -336,6 +330,14 @@ CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint // content clipping region (widget origin) rv = widget->SetWindowClipRegion(rectsOut, false); NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); + // This will trigger a browser window paint event for areas uncovered + // by a child window move, and will call invalidate on the plugin + // parent window which the browser owns. The latter gets picked up in + // our OnPaint handler and forwarded over to the plugin process async. + rv = widget->Resize(aContentOffset.x + bounds.x, + aContentOffset.y + bounds.y, + bounds.width, bounds.height, true); + NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); } rv = widget->Enable(isVisible); diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 4783c89e42..8433079de4 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -684,10 +684,12 @@ CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRec mCompositorBridgeParent->CompositeToTarget(aTarget, aRect); } -CompositorBridgeParent::CompositorBridgeParent(nsIWidget* aWidget, +CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, bool aUseExternalSurfaceSize, int aSurfaceWidth, int aSurfaceHeight) - : mWidget(aWidget) + : mWidgetProxy(aWidget) , mIsTesting(false) , mPendingTransaction(0) , mPaused(false) @@ -727,15 +729,12 @@ CompositorBridgeParent::CompositorBridgeParent(nsIWidget* aWidget, sIndirectLayerTrees[mRootLayerTreeID].mParent = this; } - // The Compositor uses the APZ pref directly since it needs to know whether - // to attempt to create the APZ machinery at all. - if (gfxPlatform::AsyncPanZoomEnabled() && - (aWidget->WindowType() == eWindowType_toplevel || aWidget->WindowType() == eWindowType_child)) { + if (aUseAPZ) { mApzcTreeManager = new APZCTreeManager(); } - mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget); - LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale); + mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget->RealWidget()); + LayerScope::SetPixelScale(aScale.scale); // mSelfRef is cleared in DeferredDestroy. mSelfRef = this; @@ -1240,7 +1239,8 @@ CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRec // to local pages, hide every plugin associated with the window. if (!hasRemoteContent && BrowserTabsRemoteAutostart() && mCachedPluginData.Length()) { - Unused << SendHideAllPlugins((uintptr_t)GetWidget()); + nsIWidget* widget = GetWidgetProxy()->RealWidget(); + Unused << SendHideAllPlugins(reinterpret_cast<uintptr_t>(widget)); mCachedPluginData.Clear(); } #endif @@ -1583,24 +1583,24 @@ CompositorBridgeParent::NewCompositor(const nsTArray<LayersBackend>& aBackendHin RefPtr<Compositor> compositor; if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) { compositor = new CompositorOGL(this, - mWidget, + mWidgetProxy, mEGLSurfaceSize.width, mEGLSurfaceSize.height, mUseExternalSurfaceSize); } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) { #ifdef MOZ_WIDGET_GTK if (gfxPlatformGtk::GetPlatform()->UseXRender()) { - compositor = new X11BasicCompositor(this, mWidget); + compositor = new X11BasicCompositor(this, mWidgetProxy); } else #endif { - compositor = new BasicCompositor(this, mWidget); + compositor = new BasicCompositor(this, mWidgetProxy); } #ifdef XP_WIN } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) { - compositor = new CompositorD3D11(this, mWidget); + compositor = new CompositorD3D11(this, mWidgetProxy); } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9) { - compositor = new CompositorD3D9(this, mWidget); + compositor = new CompositorD3D9(this, mWidgetProxy); #endif } @@ -2468,13 +2468,16 @@ CompositorBridgeParent::UpdatePluginWindowState(uint64_t aId) PLUGINS_LOG("[%" PRIu64 "] nothing to hide", aId); return false; } + + nsIWidget* widget = GetWidgetProxy()->RealWidget(); + uintptr_t parentWidget = reinterpret_cast<uintptr_t>(widget); + // We will pass through here in cases where the previous shadow layer // tree contained visible plugins and the new tree does not. All we need // to do here is hide the plugins for the old tree, so don't waste time // calculating clipping. mPluginsLayerOffset = nsIntPoint(0,0); mPluginsLayerVisibleRegion.SetEmpty(); - uintptr_t parentWidget = (uintptr_t)lts.mParent->GetWidget(); Unused << lts.mParent->SendHideAllPlugins(parentWidget); lts.mUpdatedPluginDataAvailable = false; PLUGINS_LOG("[%" PRIu64 "] hide all", aId); @@ -2551,9 +2554,13 @@ CompositorBridgeParent::HideAllPluginWindows() if (!mCachedPluginData.Length() || mDeferPluginWindows) { return; } + + nsIWidget* widget = GetWidgetProxy()->RealWidget(); + uintptr_t parentWidget = reinterpret_cast<uintptr_t>(widget); + mDeferPluginWindows = true; mPluginWindowsHidden = true; - Unused << SendHideAllPlugins((uintptr_t)GetWidget()); + Unused << SendHideAllPlugins(parentWidget); ScheduleComposition(); } #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index c2841dee98..c355cc398a 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -38,6 +38,7 @@ #include "nsISupportsImpl.h" #include "ThreadSafeRefcountingWithMainThreadDestruction.h" #include "mozilla/VsyncDispatcher.h" +#include "CompositorWidgetProxy.h" class MessageLoop; class nsIWidget; @@ -227,9 +228,11 @@ class CompositorBridgeParent final : public PCompositorBridgeParent, friend class CompositorVsyncScheduler; public: - explicit CompositorBridgeParent(nsIWidget* aWidget, - bool aUseExternalSurfaceSize = false, - int aSurfaceWidth = -1, int aSurfaceHeight = -1); + explicit CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurfaceSize = false, + int aSurfaceWidth = -1, int aSurfaceHeight = -1); virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override; virtual bool RecvRequestOverfill() override; @@ -496,7 +499,7 @@ class CompositorBridgeParent final : public PCompositorBridgeParent, */ static bool IsInCompositorThread(); - nsIWidget* GetWidget() { return mWidget; } + widget::CompositorWidgetProxy* GetWidgetProxy() { return mWidgetProxy; } void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr); @@ -569,7 +572,7 @@ class CompositorBridgeParent final : public PCompositorBridgeParent, RefPtr<LayerManagerComposite> mLayerManager; RefPtr<Compositor> mCompositor; RefPtr<AsyncCompositionManager> mCompositionManager; - nsIWidget* mWidget; + widget::CompositorWidgetProxy* mWidgetProxy; TimeStamp mTestTime; bool mIsTesting; diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp index b044fb9b9b..ee2d3a3820 100644 --- a/gfx/layers/ipc/LayerTransactionChild.cpp +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -39,12 +39,9 @@ LayerTransactionChild::Destroy() const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild(); for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) { - TextureClient* texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); + RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); if (texture) { - // TODO: cf bug 1242448. - //gfxDevCrash(gfx::LogReason::TextureAliveAfterShutdown) - // << "A texture is held alive after shutdown (PCompositorBridge)"; texture->Destroy(); } } diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index f8027e2ab6..062053e13f 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -326,6 +326,7 @@ struct TexturedTileDescriptor { MaybeTexture textureOnWhite; IntRect updateRect; TileLock sharedLock; + bool wasPlaceholder; }; struct PlaceholderTileDescriptor { @@ -348,6 +349,7 @@ struct SurfaceDescriptorTiles { float resolution; float frameXResolution; float frameYResolution; + bool isProgressive; }; struct OpUseTiledLayerBuffer { diff --git a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp index af745ff3e8..52de9b0a63 100644 --- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp +++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp @@ -51,7 +51,7 @@ CompositingRenderTargetOGL::BindRenderTarget() // The main framebuffer (0) of non-offscreen contexts // might be backed by a EGLSurface that needs to be renewed. if (mFBO == 0 && !mGL->IsOffscreen()) { - mGL->RenewSurface(mCompositor->GetWidget()); + mGL->RenewSurface(mCompositor->GetWidget()->RealWidget()); result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); } if (result != LOCAL_GL_FRAMEBUFFER_COMPLETE) { diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 2b594b503c..257be9d487 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -84,10 +84,10 @@ CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum } CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent, - nsIWidget *aWidget, int aSurfaceWidth, - int aSurfaceHeight, bool aUseExternalSurfaceSize) - : Compositor(aParent) - , mWidget(aWidget) + widget::CompositorWidgetProxy* aWidget, + int aSurfaceWidth, int aSurfaceHeight, + bool aUseExternalSurfaceSize) + : Compositor(aWidget, aParent) , mWidgetSize(-1, -1) , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) , mHasBGRA(0) @@ -112,7 +112,7 @@ CompositorOGL::CreateContext() RefPtr<GLContext> context; // Used by mock widget to create an offscreen context - void* widgetOpenGLContext = mWidget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT); + void* widgetOpenGLContext = mWidget->RealWidget()->GetNativeData(NS_NATIVE_OPENGL_CONTEXT); if (widgetOpenGLContext) { GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext); return already_AddRefed<GLContext>(alreadyRefed); @@ -121,7 +121,7 @@ CompositorOGL::CreateContext() #ifdef XP_WIN if (gfxEnv::LayersPreferEGL()) { printf_stderr("Trying GL layers...\n"); - context = gl::GLContextProviderEGL::CreateForWindow(mWidget, false); + context = gl::GLContextProviderEGL::CreateForWindow(mWidget->RealWidget(), false); } #endif @@ -136,7 +136,7 @@ CompositorOGL::CreateContext() } if (!context) { - context = gl::GLContextProvider::CreateForWindow(mWidget, + context = gl::GLContextProvider::CreateForWindow(mWidget->RealWidget(), gfxPlatform::GetPlatform()->RequiresAcceleratedGLContextForCompositorOGL()); } @@ -225,9 +225,7 @@ CompositorOGL::CleanupResources() bool CompositorOGL::Initialize() { - bool force = gfxPrefs::LayersAccelerationForceEnabled(); - - ScopedGfxFeatureReporter reporter("GL Layers", force); + ScopedGfxFeatureReporter reporter("GL Layers"); // Do not allow double initialization MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL"); @@ -607,7 +605,7 @@ CompositorOGL::GetCurrentRenderTarget() const static GLenum GetFrameBufferInternalFormat(GLContext* gl, GLuint aFrameBuffer, - nsIWidget* aWidget) + mozilla::widget::CompositorWidgetProxy* aWidget) { if (aFrameBuffer == 0) { // default framebuffer return aWidget->GetGLFrameBufferFormat(); @@ -1464,13 +1462,13 @@ CompositorOGL::EndFrame() #ifdef MOZ_DUMP_PAINTING if (gfxEnv::DumpCompositorTextures()) { - LayoutDeviceIntRect rect; + LayoutDeviceIntSize size; if (mUseExternalSurfaceSize) { - rect = LayoutDeviceIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); + size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height); } else { - mWidget->GetBounds(rect); + size = mWidget->GetClientSize(); } - RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8); + RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); if (target) { CopyToTarget(target, nsIntPoint(), Matrix()); WriteSnapshotToDumpFile(this, target); @@ -1602,7 +1600,7 @@ CompositorOGL::Resume() return false; // RenewSurface internally calls MakeCurrent. - return gl()->RenewSurface(GetWidget()); + return gl()->RenewSurface(GetWidget()->RealWidget()); #endif return true; } diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index c705f41813..1568ba9749 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -194,7 +194,8 @@ class CompositorOGL final : public Compositor std::map<ShaderConfigOGL, ShaderProgramOGL*> mPrograms; public: explicit CompositorOGL(CompositorBridgeParent* aParent, - nsIWidget *aWidget, int aSurfaceWidth = -1, int aSurfaceHeight = -1, + widget::CompositorWidgetProxy* aWidget, + int aSurfaceWidth = -1, int aSurfaceHeight = -1, bool aUseExternalSurfaceSize = false); protected: @@ -210,8 +211,6 @@ class CompositorOGL final : public Compositor virtual void Destroy() override; - virtual void DetachWidget() override { mWidget = nullptr; } - virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override { TextureFactoryIdentifier result = @@ -279,8 +278,6 @@ class CompositorOGL final : public Compositor virtual void Pause() override; virtual bool Resume() override; - virtual nsIWidget* GetWidget() const override { return mWidget; } - virtual bool HasImageHostOverlays() override { #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 @@ -353,7 +350,6 @@ class CompositorOGL final : public Compositor void PrepareViewport(CompositingRenderTargetOGL *aRenderTarget); /** Widget associated with this compositor */ - nsIWidget *mWidget; LayoutDeviceIntSize mWidgetSize; RefPtr<GLContext> mGLContext; UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper; diff --git a/gfx/layers/opengl/GrallocTextureClient.cpp b/gfx/layers/opengl/GrallocTextureClient.cpp index 9fb316d1ce..209b5957b4 100644 --- a/gfx/layers/opengl/GrallocTextureClient.cpp +++ b/gfx/layers/opengl/GrallocTextureClient.cpp @@ -133,6 +133,17 @@ GrallocTextureData::Forget(ClientIPCAllocator* aAllocator) mGraphicBuffer = nullptr; } +void +GrallocTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = mFormat; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = true; + aInfo.supportsMoz2D = true; + aInfo.canExposeMappedData = true; +} + bool GrallocTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { diff --git a/gfx/layers/opengl/GrallocTextureClient.h b/gfx/layers/opengl/GrallocTextureClient.h index 82bd191221..2c4e5db6ca 100644 --- a/gfx/layers/opengl/GrallocTextureClient.h +++ b/gfx/layers/opengl/GrallocTextureClient.h @@ -45,22 +45,12 @@ class GrallocTextureData : public TextureData { virtual void Unlock() override; - virtual gfx::IntSize GetSize() const override { return mSize; } - - virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override; - virtual bool CanExposeMappedData() const override { return true; } - virtual bool BorrowMappedData(MappedTextureData& aMap) override; - virtual bool SupportsMoz2D() const override { return true; } - - virtual bool HasIntermediateBuffer() const override { return false; } - - virtual bool HasSynchronization() const override { return true; } - virtual void Deallocate(ClientIPCAllocator*) override; virtual void Forget(ClientIPCAllocator*) override; diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp index dc7c8ebae9..d396900116 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp @@ -39,16 +39,15 @@ MacIOSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) return true; } -gfx::IntSize -MacIOSurfaceTextureData::GetSize() const +void +MacIOSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const { - return gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight()); -} - -gfx::SurfaceFormat -MacIOSurfaceTextureData::GetFormat() const -{ - return mSurface->GetFormat(); + aInfo.size = gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight()); + aInfo.format = mSurface->GetFormat(); + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = false; + aInfo.canExposeMappedData = false; } already_AddRefed<gfx::DataSourceSurface> diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h index de2559c56b..5db317444e 100644 --- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h @@ -20,9 +20,7 @@ class MacIOSurfaceTextureData : public TextureData ~MacIOSurfaceTextureData(); - virtual gfx::IntSize GetSize() const override; - - virtual gfx::SurfaceFormat GetFormat() const override; + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Lock(OpenMode, FenceHandle*) override { return true; } @@ -30,8 +28,6 @@ class MacIOSurfaceTextureData : public TextureData virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; - virtual bool HasIntermediateBuffer() const override { return false; } - virtual void Deallocate(ClientIPCAllocator*) override { mSurface = nullptr; } virtual void Forget(ClientIPCAllocator*) override { mSurface = nullptr; } diff --git a/gfx/layers/opengl/TextureClientOGL.cpp b/gfx/layers/opengl/TextureClientOGL.cpp index b536d3f2d9..73d74e38b9 100644 --- a/gfx/layers/opengl/TextureClientOGL.cpp +++ b/gfx/layers/opengl/TextureClientOGL.cpp @@ -51,6 +51,17 @@ EGLImageTextureData::CreateTextureClient(EGLImageImage* aImage, gfx::IntSize aSi ); } +void +EGLImageTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = gfx::SurfaceFormat::UNKNOWN; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = false; + aInfo.canExposeMappedData = false; +} + bool EGLImageTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { @@ -100,6 +111,17 @@ AndroidSurfaceTextureData::AndroidSurfaceTextureData(AndroidSurfaceTexture* aSur AndroidSurfaceTextureData::~AndroidSurfaceTextureData() {} +void +AndroidSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = mSize; + aInfo.format = gfx::SurfaceFormat::UNKNOWN; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = false; + aInfo.canExposeMappedData = false; +} + bool AndroidSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { diff --git a/gfx/layers/opengl/TextureClientOGL.h b/gfx/layers/opengl/TextureClientOGL.h index 57bf7ba5bd..9ca311c02c 100644 --- a/gfx/layers/opengl/TextureClientOGL.h +++ b/gfx/layers/opengl/TextureClientOGL.h @@ -28,9 +28,7 @@ class EGLImageTextureData : public TextureData CreateTextureClient(EGLImageImage* aImage, gfx::IntSize aSize, ClientIPCAllocator* aAllocator, TextureFlags aFlags); - virtual bool HasIntermediateBuffer() const override { return false; } - - virtual gfx::IntSize GetSize() const override { return mSize; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; @@ -43,11 +41,6 @@ class EGLImageTextureData : public TextureData virtual void Unlock() override {} - virtual gfx::SurfaceFormat GetFormat() const override - { - return gfx::SurfaceFormat::UNKNOWN; - } - protected: EGLImageTextureData(EGLImageImage* aImage, gfx::IntSize aSize); @@ -69,9 +62,7 @@ class AndroidSurfaceTextureData : public TextureData ~AndroidSurfaceTextureData(); - virtual bool HasIntermediateBuffer() const override { return false; } - - virtual gfx::IntSize GetSize() const override { return mSize; } + virtual void FillInfo(TextureData::Info& aInfo) const override; virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; @@ -80,17 +71,11 @@ class AndroidSurfaceTextureData : public TextureData virtual void Unlock() override {} - virtual gfx::SurfaceFormat GetFormat() const override - { - return gfx::SurfaceFormat::UNKNOWN; - } - // Our data is always owned externally. virtual void Deallocate(ClientIPCAllocator*) override {} protected: - AndroidSurfaceTextureData(gl::AndroidSurfaceTexture* aSurfTex, - gfx::IntSize aSize); + AndroidSurfaceTextureData(gl::AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize); const RefPtr<gl::AndroidSurfaceTexture> mSurfTex; const gfx::IntSize mSize; diff --git a/gfx/moz.build b/gfx/moz.build index 2ed70f83a8..fb9f05b7f9 100644 --- a/gfx/moz.build +++ b/gfx/moz.build @@ -21,6 +21,7 @@ DIRS += [ 'thebes', 'ipc', 'vr', + 'config', ] if CONFIG['MOZ_ENABLE_SKIA']: diff --git a/gfx/src/gfxTelemetry.cpp b/gfx/src/gfxTelemetry.cpp index e002f134d3..52414f1e11 100644 --- a/gfx/src/gfxTelemetry.cpp +++ b/gfx/src/gfxTelemetry.cpp @@ -16,7 +16,7 @@ FeatureStatusToString(FeatureStatus aStatus) return "unused"; case FeatureStatus::Unavailable: return "unavailable"; - case FeatureStatus::Crashed: + case FeatureStatus::CrashedInHandler: return "crashed"; case FeatureStatus::Blocked: return "blocked"; @@ -28,6 +28,12 @@ FeatureStatusToString(FeatureStatus aStatus) return "disabled"; case FeatureStatus::Available: return "available"; + case FeatureStatus::ForceEnabled: + return "force_enabled"; + case FeatureStatus::CrashedOnStartup: + return "crashed_on_startup"; + case FeatureStatus::Broken: + return "broken"; default: MOZ_ASSERT_UNREACHABLE("missing status case"); return "unknown"; @@ -37,8 +43,16 @@ FeatureStatusToString(FeatureStatus aStatus) bool IsFeatureStatusFailure(FeatureStatus aStatus) { - return aStatus != FeatureStatus::Unused && - aStatus != FeatureStatus::Available; + return !(aStatus == FeatureStatus::Unused || + aStatus == FeatureStatus::Available || + aStatus == FeatureStatus::ForceEnabled); +} + +bool +IsFeatureStatusSuccess(FeatureStatus aStatus) +{ + return aStatus == FeatureStatus::Available || + aStatus == FeatureStatus::ForceEnabled; } } // namespace gfx diff --git a/gfx/src/gfxTelemetry.h b/gfx/src/gfxTelemetry.h index 1110e31c90..fd477fd0c1 100644 --- a/gfx/src/gfxTelemetry.h +++ b/gfx/src/gfxTelemetry.h @@ -17,12 +17,13 @@ enum class FeatureStatus // This feature has not been requested. Unused, - // This feature is unavailable due to Safe Mode or not being included with - // the operating system. + // This feature is unavailable due to Safe Mode, not being included with + // the operating system, or a dependent feature being disabled. Unavailable, - // This feature crashed immediately when we tried to initialize it. - Crashed, + // This feature crashed immediately when we tried to initialize it, but we + // were able to recover via SEH (or something similar). + CrashedInHandler, // This feature was blocked for reasons outside the blacklist, such as a // runtime test failing. @@ -38,11 +39,21 @@ enum class FeatureStatus Disabled, // This feature is available for use. - Available + Available, + + // This feature was explicitly force-enabled by the user. + ForceEnabled, + + // This feature was disabled due to the startup crash guard. + CrashedOnStartup, + + // This feature was attempted but later determined to be broken. + Broken }; const char* FeatureStatusToString(FeatureStatus aStatus); bool IsFeatureStatusFailure(FeatureStatus aStatus); +bool IsFeatureStatusSuccess(FeatureStatus aStatus); } // namespace gfx } // namespace mozilla diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index b2a184450a..fa9e6a3a6e 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -87,6 +87,7 @@ class MockWidget : public nsBaseWidget const InputContextAction& aAction) override {} NS_IMETHOD_(InputContext) GetInputContext() override { abort(); } NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override { return NS_OK; } + private: ~MockWidget() {} }; @@ -96,16 +97,21 @@ NS_IMPL_ISUPPORTS_INHERITED0(MockWidget, nsBaseWidget) struct LayerManagerData { RefPtr<MockWidget> mWidget; RefPtr<Compositor> mCompositor; + RefPtr<widget::CompositorWidgetProxy> mCompositorWidgetProxy; RefPtr<LayerManagerComposite> mLayerManager; - LayerManagerData(Compositor* compositor, MockWidget* widget, LayerManagerComposite* layerManager) + LayerManagerData(Compositor* compositor, + MockWidget* widget, + widget::CompositorWidgetProxy* aProxy, + LayerManagerComposite* layerManager) : mWidget(widget) , mCompositor(compositor) + , mCompositorWidgetProxy(aProxy) , mLayerManager(layerManager) {} }; -static already_AddRefed<Compositor> CreateTestCompositor(LayersBackend backend, MockWidget* widget) +static already_AddRefed<Compositor> CreateTestCompositor(LayersBackend backend, widget::CompositorWidgetProxy* widget) { gfxPrefs::GetSingleton(); @@ -149,11 +155,12 @@ static std::vector<LayerManagerData> GetLayerManagers(std::vector<LayersBackend> auto backend = aBackends[i]; RefPtr<MockWidget> widget = new MockWidget(); - RefPtr<Compositor> compositor = CreateTestCompositor(backend, widget); + RefPtr<widget::CompositorWidgetProxy> proxy = widget->NewCompositorWidgetProxy(); + RefPtr<Compositor> compositor = CreateTestCompositor(backend, proxy); RefPtr<LayerManagerComposite> layerManager = new LayerManagerComposite(compositor); - managers.push_back(LayerManagerData(compositor, widget, layerManager)); + managers.push_back(LayerManagerData(compositor, widget, proxy, layerManager)); } return managers; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 0753f49429..ce6b322e38 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -22,6 +22,7 @@ #include "gfxPrefs.h" #include "gfxEnv.h" #include "gfxTextRun.h" +#include "gfxConfig.h" #ifdef XP_WIN #include <process.h> @@ -151,6 +152,7 @@ void ShutdownTileCache(); using namespace mozilla; using namespace mozilla::layers; using namespace mozilla::gl; +using namespace mozilla::gfx; gfxPlatform *gPlatform = nullptr; static bool gEverInitialized = false; @@ -169,14 +171,16 @@ static qcms_transform *gCMSRGBATransform = nullptr; static bool gCMSInitialized = false; static eCMSMode gCMSMode = eCMSMode_Off; +// Device init data should only be used on child processes, so we protect it +// behind a getter here. +static DeviceInitData sDeviceInitDataDoNotUseDirectly; + static void ShutdownCMS(); #include "mozilla/gfx/2D.h" #include "mozilla/gfx/SourceSurfaceCairo.h" using namespace mozilla::gfx; -void InitLayersAccelerationPrefs(); - /* Class to listen for pref changes so that chrome code can dynamically force sRGB as an output profile. See Bug #452125. */ class SRGBOverrideObserver final : public nsIObserver, @@ -602,8 +606,8 @@ gfxPlatform::Init() // Layers prefs forcedPrefs.AppendPrintf("-L%d%d%d%d%d", gfxPrefs::LayersAMDSwitchableGfxEnabled(), - gfxPrefs::LayersAccelerationDisabled(), - gfxPrefs::LayersAccelerationForceEnabled(), + gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly(), + gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(), gfxPrefs::LayersD3D11DisableWARP(), gfxPrefs::LayersD3D11ForceWARP()); // WebGL prefs @@ -658,6 +662,7 @@ gfxPlatform::Init() #else #error "No gfxPlatform implementation available" #endif + gPlatform->InitAcceleration(); #ifdef USE_SKIA SkGraphics::Init(); @@ -667,7 +672,6 @@ gfxPlatform::Init() GLContext::StaticInit(); #endif - InitLayersAccelerationPrefs(); InitLayersIPC(); gPlatform->PopulateScreenInfo(); @@ -2056,7 +2060,6 @@ gfxPlatform::OptimalFormatForContent(gfxContentType aContent) * not have any effect until we restart. */ static bool sLayersSupportsD3D9 = false; -static bool sLayersSupportsD3D11 = false; bool gANGLESupportsD3D11 = false; static bool sLayersSupportsHardwareVideoDecoding = false; static bool sLayersHardwareVideoDecodingFailed = false; @@ -2066,85 +2069,103 @@ static bool sPrefBrowserTabsRemoteAutostart = false; static bool sLayersAccelerationPrefsInitialized = false; void -InitLayersAccelerationPrefs() +gfxPlatform::InitAcceleration() { - if (!sLayersAccelerationPrefsInitialized) - { - // If this is called for the first time on a non-main thread, we're screwed. - // At the moment there's no explicit guarantee that the main thread calls - // this before the compositor thread, but let's at least make the assumption - // explicit. - MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread"); + if (sLayersAccelerationPrefsInitialized) { + return; + } - gfxPrefs::GetSingleton(); - sPrefBrowserTabsRemoteAutostart = BrowserTabsRemoteAutostart(); + InitCompositorAccelerationPrefs(); - nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); - nsCString discardFailureId; - int32_t status; + // If this is called for the first time on a non-main thread, we're screwed. + // At the moment there's no explicit guarantee that the main thread calls + // this before the compositor thread, but let's at least make the assumption + // explicit. + MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread"); + + gfxPrefs::GetSingleton(); + sPrefBrowserTabsRemoteAutostart = BrowserTabsRemoteAutostart(); + + nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); + nsCString discardFailureId; + int32_t status; #ifdef XP_WIN - if (gfxPrefs::LayersAccelerationForceEnabled()) { - sLayersSupportsD3D9 = true; - sLayersSupportsD3D11 = true; - } else if (!gfxPrefs::LayersAccelerationDisabled() && gfxInfo) { - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, discardFailureId, &status))) { - if (status == nsIGfxInfo::FEATURE_STATUS_OK) { - MOZ_ASSERT(!sPrefBrowserTabsRemoteAutostart || IsVistaOrLater()); - sLayersSupportsD3D9 = true; - } - } - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, discardFailureId, &status))) { - if (status == nsIGfxInfo::FEATURE_STATUS_OK) { - sLayersSupportsD3D11 = true; - } - } - if (!gfxPrefs::LayersD3D11DisableWARP()) { - // Always support D3D11 when WARP is allowed. - sLayersSupportsD3D11 = true; + if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { + sLayersSupportsD3D9 = true; + } else if (!gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly() && gfxInfo) { + if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, discardFailureId, &status))) { + if (status == nsIGfxInfo::FEATURE_STATUS_OK) { + MOZ_ASSERT(!sPrefBrowserTabsRemoteAutostart || IsVistaOrLater()); + sLayersSupportsD3D9 = true; } - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, discardFailureId, &status))) { - if (status == nsIGfxInfo::FEATURE_STATUS_OK) { - gANGLESupportsD3D11 = true; - } + } + if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, discardFailureId, &status))) { + if (status == nsIGfxInfo::FEATURE_STATUS_OK) { + gANGLESupportsD3D11 = true; } } + } #endif - if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) && + if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) && #ifdef XP_WIN - Preferences::GetBool("media.windows-media-foundation.use-dxva", true) && + Preferences::GetBool("media.windows-media-foundation.use-dxva", true) && #endif - NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, + NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, discardFailureId, &status))) { - if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) { - sLayersSupportsHardwareVideoDecoding = true; - } + if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) { + sLayersSupportsHardwareVideoDecoding = true; } + } - Preferences::AddBoolVarCache(&sLayersHardwareVideoDecodingFailed, - "media.hardware-video-decoding.failed", - false); + Preferences::AddBoolVarCache(&sLayersHardwareVideoDecodingFailed, + "media.hardware-video-decoding.failed", + false); - sLayersAccelerationPrefsInitialized = true; - } + sLayersAccelerationPrefsInitialized = true; } -bool -gfxPlatform::CanUseDirect3D9() +void +gfxPlatform::InitCompositorAccelerationPrefs() { - // this function is called from the compositor thread, so it is not - // safe to init the prefs etc. from here. - MOZ_ASSERT(sLayersAccelerationPrefsInitialized); - return sLayersSupportsD3D9; + const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED"); + + FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING); + + // Base value - does the platform allow acceleration? + if (feature.SetDefault(AccelerateLayersByDefault(), + FeatureStatus::Blocked, + "Acceleration blocked by platform")) + { + if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) { + feature.UserDisable("Disabled by pref"); + } else if (acceleratedEnv && *acceleratedEnv == '0') { + feature.UserDisable("Disabled by envvar"); + } + } else { + if (acceleratedEnv && *acceleratedEnv == '1') { + feature.UserEnable("Enabled by envvar"); + } + } + + // This has specific meaning elsewhere, so we always record it. + if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) { + feature.UserForceEnable("Force-enabled by pref"); + } + + // Safe mode trumps everything. + if (InSafeMode()) { + feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode"); + } } bool -gfxPlatform::CanUseDirect3D11() +gfxPlatform::CanUseDirect3D9() { // this function is called from the compositor thread, so it is not // safe to init the prefs etc. from here. MOZ_ASSERT(sLayersAccelerationPrefsInitialized); - return sLayersSupportsD3D11; + return sLayersSupportsD3D9; } bool @@ -2163,28 +2184,6 @@ gfxPlatform::CanUseDirect3D11ANGLE() return gANGLESupportsD3D11; } -bool -gfxPlatform::ShouldUseLayersAcceleration() -{ - const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED"); - if (gfxPrefs::LayersAccelerationDisabled() || - InSafeMode() || - (acceleratedEnv && *acceleratedEnv == '0')) - { - return false; - } - if (gfxPrefs::LayersAccelerationForceEnabled()) { - return true; - } - if (AccelerateLayersByDefault()) { - return true; - } - if (acceleratedEnv && *acceleratedEnv != '0') { - return true; - } - return false; -} - bool gfxPlatform::AccelerateLayersByDefault() { @@ -2224,6 +2223,13 @@ gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFo return nullptr; } +/* static */ DeviceInitData& +gfxPlatform::GetParentDevicePrefs() +{ + MOZ_ASSERT(XRE_IsContentProcess()); + return sDeviceInitDataDoNotUseDirectly; +} + /* static */ bool gfxPlatform::UsesOffMainThreadCompositing() { @@ -2231,13 +2237,13 @@ gfxPlatform::UsesOffMainThreadCompositing() static bool result = false; if (firstTime) { - InitLayersAccelerationPrefs(); + MOZ_ASSERT(sLayersAccelerationPrefsInitialized); result = sPrefBrowserTabsRemoteAutostart || !gfxPrefs::LayersOffMainThreadCompositionForceDisabled(); #if defined(MOZ_WIDGET_GTK) // Linux users who chose OpenGL are being grandfathered in to OMTC - result |= gfxPrefs::LayersAccelerationForceEnabled(); + result |= gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(); #endif firstTime = false; @@ -2400,7 +2406,7 @@ AllowOpenGL(bool* aWhitelisted) } } - return gfxPrefs::LayersAccelerationForceEnabled(); + return gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING); } void @@ -2463,21 +2469,29 @@ void gfxPlatform::GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut) { MOZ_ASSERT(XRE_IsParentProcess()); - aOut->useAcceleration() = ShouldUseLayersAcceleration(); + aOut->useHwCompositing() = gfxConfig::IsEnabled(Feature::HW_COMPOSITING); } -void +bool gfxPlatform::UpdateDeviceInitData() { if (XRE_IsParentProcess()) { // The parent process figures out device initialization on its own. - return; + return false; } mozilla::gfx::DeviceInitData data; mozilla::dom::ContentChild::GetSingleton()->SendGetGraphicsDeviceInitData(&data); - SetDeviceInitData(data); + sDeviceInitDataDoNotUseDirectly = data; + + // Ensure that child processes have inherited the HW_COMPOSITING pref. + gfxConfig::InitOrUpdate( + Feature::HW_COMPOSITING, + GetParentDevicePrefs().useHwCompositing(), + FeatureStatus::Blocked, + "Hardware-accelerated compositing disabled in parent process"); + return true; } bool diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 132f91eb6d..cb2f93e7e8 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -450,14 +450,9 @@ class gfxPlatform { static bool OffMainThreadCompositingEnabled(); static bool CanUseDirect3D9(); - static bool CanUseDirect3D11(); virtual bool CanUseHardwareVideoDecoding(); static bool CanUseDirect3D11ANGLE(); - // Returns whether or not layers acceleration should be used. This should - // only be called on the parent process. - bool ShouldUseLayersAcceleration(); - // Returns a prioritized list of all available compositor backends. void GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends); @@ -665,6 +660,8 @@ class gfxPlatform { gfxPlatform(); virtual ~gfxPlatform(); + virtual void InitAcceleration(); + /** * Initialized hardware vsync based on each platform. */ @@ -686,21 +683,16 @@ class gfxPlatform { uint32_t aContentBitmask, mozilla::gfx::BackendType aContentDefault); /** - * If in a child process, triggers a refresh of device preferences. + * If in a child process, triggers a refresh of device preferences, then returns true. + * In a parent process, nothing happens and false is returned. */ - void UpdateDeviceInitData(); + virtual bool UpdateDeviceInitData(); /** * Increase the global device counter after a device has been removed/reset. */ void BumpDeviceCounter(); - /** - * Called when new device preferences are available. - */ - virtual void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData) - {} - /** * returns the first backend named in the pref gfx.canvas.azure.backends * which is a component of aBackendBitmask, a bitmask of backend types @@ -729,6 +721,8 @@ class gfxPlatform { static already_AddRefed<mozilla::gfx::ScaledFont> GetScaledFontForFontWithCairoSkia(mozilla::gfx::DrawTarget* aTarget, gfxFont* aFont); + static mozilla::gfx::DeviceInitData& GetParentDevicePrefs(); + int8_t mAllowDownloadableFonts; int8_t mGraphiteShapingEnabled; int8_t mOpenTypeSVGEnabled; @@ -778,6 +772,8 @@ class gfxPlatform { */ void PopulateScreenInfo(); + void InitCompositorAccelerationPrefs(); + RefPtr<gfxASurface> mScreenReferenceSurface; nsCOMPtr<nsIObserver> mSRGBOverrideObserver; nsCOMPtr<nsIObserver> mFontPrefsObserver; diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 3bcf53c7b2..9d312203de 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -71,6 +71,8 @@ class PreferenceAccessImpl; class gfxPrefs; class gfxPrefs final { + friend class gfxWindowsPlatform; + private: /// See Logging.h. This lets Moz2D access preference values it owns. PreferenceAccessImpl* mMoz2DPrefAccess; @@ -326,11 +328,12 @@ class gfxPrefs final DECL_GFX_PREF(Live, "image.webp.enabled", ImageWebPEnabled, bool, true); DECL_GFX_PREF(Live, "layers.child-process-shutdown", ChildProcessShutdown, bool, true); - DECL_GFX_PREF(Once, "layers.acceleration.disabled", LayersAccelerationDisabled, bool, false); + DECL_GFX_PREF(Once, "layers.acceleration.disabled", LayersAccelerationDisabledDoNotUseDirectly, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps", LayersDrawFPS, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false); - DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabled, bool, false); + DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabledDoNotUseDirectly, bool, false); + DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false); DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false); DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true); DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false); @@ -394,6 +397,8 @@ class gfxPrefs final DECL_GFX_PREF(Once, "layers.tiled-drawtarget.enabled", TiledDrawTargetEnabled, bool, false); DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true); DECL_GFX_PREF(Once, "layers.tiles.edge-padding", TileEdgePaddingEnabled, bool, true); + DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled", LayerTileFadeInEnabled, bool, false); + DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms", LayerTileFadeInDuration, uint32_t, 250); DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, true); diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 5f17220ef9..b218c2e114 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -401,8 +401,7 @@ static CompositionOp OptimalFillOp() { #ifdef XP_WIN - if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == - gfxWindowsPlatform::RENDER_DIRECT2D) { + if (gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend()) { // D2D -really- hates operator source. return CompositionOp::OP_OVER; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index a59480f485..606efc8174 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -67,6 +67,7 @@ #include "SurfaceCache.h" #include "gfxPrefs.h" +#include "gfxConfig.h" #include "VsyncSource.h" #include "DriverCrashGuard.h" @@ -356,16 +357,6 @@ class D3D9SharedTextureReporter final : public nsIMemoryReporter NS_IMPL_ISUPPORTS(D3D9SharedTextureReporter, nsIMemoryReporter) -// Device init data should only be used on child processes, so we protect it -// behind a getter here. -static DeviceInitData sDeviceInitDataDoNotUseDirectly; -static inline DeviceInitData& -GetParentDevicePrefs() -{ - MOZ_ASSERT(XRE_IsContentProcess()); - return sDeviceInitDataDoNotUseDirectly; -} - gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) , mDeviceLock("gfxWindowsPlatform.mDeviceLock") @@ -373,55 +364,58 @@ gfxWindowsPlatform::gfxWindowsPlatform() , mHasDeviceReset(false) , mHasFakeDeviceReset(false) , mCompositorD3D11TextureSharingWorks(false) - , mAcceleration(FeatureStatus::Unused) - , mD3D11Status(FeatureStatus::Unused) - , mD2D1Status(FeatureStatus::Unused) , mHasD3D9DeviceReset(false) { - mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; - mUseClearTypeAlways = UNINITIALIZED_VALUE; - - /* - * Initialize COM - */ - CoInitialize(nullptr); - - RegisterStrongMemoryReporter(new GfxD2DVramReporter()); + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + mUseClearTypeAlways = UNINITIALIZED_VALUE; - // Set up the D3D11 feature levels we can ask for. - if (IsWin8OrLater()) { - mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); - } - mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); - mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); - mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); - mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); + /* + * Initialize COM + */ + CoInitialize(nullptr); - UpdateDeviceInitData(); - InitializeDevices(); - UpdateRenderMode(); + RegisterStrongMemoryReporter(new GfxD2DVramReporter()); - RegisterStrongMemoryReporter(new GPUAdapterReporter()); - RegisterStrongMemoryReporter(new D3D11TextureReporter()); - RegisterStrongMemoryReporter(new D3D9TextureReporter()); - RegisterStrongMemoryReporter(new D3D9SharedTextureReporter()); + RegisterStrongMemoryReporter(new GPUAdapterReporter()); + RegisterStrongMemoryReporter(new D3D11TextureReporter()); + RegisterStrongMemoryReporter(new D3D9TextureReporter()); + RegisterStrongMemoryReporter(new D3D9SharedTextureReporter()); } gfxWindowsPlatform::~gfxWindowsPlatform() { - mDeviceManager = nullptr; - mD3D11Device = nullptr; - mD3D11ContentDevice = nullptr; - mD3D11ImageBridgeDevice = nullptr; + mDeviceManager = nullptr; + mD3D11Device = nullptr; + mD3D11ContentDevice = nullptr; + mD3D11ImageBridgeDevice = nullptr; + + mozilla::gfx::Factory::D2DCleanup(); + + mAdapter = nullptr; - mozilla::gfx::Factory::D2DCleanup(); + /* + * Uninitialize COM + */ + CoUninitialize(); +} + +void +gfxWindowsPlatform::InitAcceleration() +{ + gfxPlatform::InitAcceleration(); - mAdapter = nullptr; + // Set up the D3D11 feature levels we can ask for. + if (IsWin8OrLater()) { + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); + } + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); - /* - * Uninitialize COM - */ - CoUninitialize(); + InitializeConfig(); + InitializeDevices(); + UpdateRenderMode(); } bool @@ -491,9 +485,6 @@ gfxWindowsPlatform::HandleDeviceReset() imgLoader::Singleton()->ClearCache(false); gfxAlphaBoxBlur::ShutdownBlurCache(); - // Since we got a device reset, we must ask the parent process for an updated - // list of which devices to create. - UpdateDeviceInitData(); InitializeDevices(); BumpDeviceCounter(); return true; @@ -507,19 +498,23 @@ gfxWindowsPlatform::UpdateBackendPrefs() uint32_t canvasMask = BackendTypeBit(SOFTWARE_BACKEND); uint32_t contentMask = BackendTypeBit(SOFTWARE_BACKEND); BackendType defaultBackend = SOFTWARE_BACKEND; - if (GetD2D1Status() == FeatureStatus::Available) { - mRenderMode = RENDER_DIRECT2D; + if (gfxConfig::IsEnabled(Feature::DIRECT2D)) { contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1); canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1); defaultBackend = BackendType::DIRECT2D1_1; } else { - mRenderMode = RENDER_GDI; canvasMask |= BackendTypeBit(BackendType::SKIA); } contentMask |= BackendTypeBit(BackendType::SKIA); InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend); } +bool +gfxWindowsPlatform::IsDirect2DBackend() +{ + return GetDefaultContentBackend() == BackendType::DIRECT2D1_1; +} + void gfxWindowsPlatform::UpdateRenderMode() { @@ -533,9 +528,9 @@ gfxWindowsPlatform::UpdateRenderMode() if (!mScreenReferenceDrawTarget) { gfxCriticalNote << "Failed to update reference draw target after device reset" << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device()) - << ", D3D11 status:" << FeatureStatusToString(GetD3D11Status()) + << ", D3D11 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::D3D11_COMPOSITING)) << ", D2D1 device:" << hexa(Factory::GetD2D1Device()) - << ", D2D1 status:" << FeatureStatusToString(GetD2D1Status()) + << ", D2D1 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D)) << ", content:" << int(GetDefaultContentBackend()) << ", compositor:" << int(GetCompositorBackend()); MOZ_CRASH("GFX: Failed to update reference draw target after device reset"); @@ -579,7 +574,7 @@ gfxWindowsPlatform::CreatePlatformFontList() // but apparently it can - see bug 594865. // So we're going to fall back to GDI fonts & rendering. gfxPlatformFontList::Shutdown(); - DisableD2D(); + DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts"); } pfl = new gfxGDIFontList(); @@ -599,9 +594,9 @@ gfxWindowsPlatform::CreatePlatformFontList() // This is called during gfxPlatform::Init() so at this point there should be no // DrawTargetD2D/1 instances. void -gfxWindowsPlatform::DisableD2D() +gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage) { - mD2D1Status = FeatureStatus::Failed; + gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage); Factory::SetDirect3D11Device(nullptr); UpdateBackendPrefs(); } @@ -1560,7 +1555,7 @@ bool DoesD3D11DeviceWork() checked = true; if (gfxPrefs::Direct2DForceEnabled() || - gfxPrefs::LayersAccelerationForceEnabled()) + gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { result = true; return true; @@ -1759,7 +1754,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma } if (gfxPrefs::Direct2DForceEnabled() || - gfxPrefs::LayersAccelerationForceEnabled()) + gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { return true; } @@ -1802,7 +1797,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma // get a crash on Intel 8.5.10.[18xx-1994] drivers. // We can work around this issue by doing UpdateSubresource. if (!TryCreateTexture2D(device, &desc, nullptr, texture)) { - gfxCriticalError() << "DoesD3D11TextureSharingWork_TryCreateTextureFailure"; + gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure"; return false; } @@ -1920,70 +1915,111 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device) } static inline bool -CanUseWARP() +IsGfxInfoStatusOkay(int32_t aFeature) { - if (gfxPrefs::LayersD3D11ForceWARP()) { + nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); + if (!gfxInfo) { return true; } - // The child process can only use WARP if the parent process is also using - // WARP. - if (XRE_IsContentProcess()) { - return GetParentDevicePrefs().useD3D11WARP(); + int32_t status; + nsCString discardFailureId; + if (FAILED(gfxInfo->GetFeatureStatus(aFeature, discardFailureId, &status))) { + return true; } + return status == nsIGfxInfo::FEATURE_STATUS_OK; +} + +static inline bool +IsWARPStable() +{ // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703. - if (!IsWin8OrLater() || - gfxPrefs::LayersD3D11DisableWARP() || - GetModuleHandleA("nvdxgiwrap.dll")) - { + if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) { return false; } return true; } -FeatureStatus -gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware) +void +gfxWindowsPlatform::InitializeConfig() { - // Don't revive D3D11 support after a failure. - if (IsFeatureStatusFailure(mD3D11Status)) { - return mD3D11Status; + if (!XRE_IsParentProcess()) { + // Child processes init their configuration via UpdateDeviceInitData(). + return; } - if (XRE_IsContentProcess()) { - if (!GetParentDevicePrefs().useD3D11()) { - return FeatureStatus::Blocked; + InitializeD3D11Config(); + InitializeD2DConfig(); +} + +void +gfxWindowsPlatform::InitializeD3D11Config() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); + + if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { + d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled"); + return; + } + + d3d11.EnableByDefault(); + + // If the user prefers D3D9, act as though they disabled D3D11. + if (gfxPrefs::LayersPreferD3D9()) { + d3d11.UserDisable("Disabled due to user preference for Direct3D 9"); + return; + } + + if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)) { + if (IsWARPStable() && !gfxPrefs::LayersD3D11DisableWARP()) { + // We do not expect hardware D3D11 to work, so we'll try WARP. + gfxConfig::EnableFallback( + Fallback::USE_D3D11_WARP_COMPOSITOR, + "Hardware-accelerated Direct3D11 compositing is blocklisted"); + } else { + // There is little to no chance of D3D11 working, so just disable it. + d3d11.Disable(FeatureStatus::Blacklisted, "Hardware-accelerated Direct3D11 compositing is blocklisted"); } - *aCanUseHardware = !GetParentDevicePrefs().useD3D11WARP(); - return FeatureStatus::Available; } + // Check if the user really, really wants WARP. if (gfxPrefs::LayersD3D11ForceWARP()) { - *aCanUseHardware = false; - return FeatureStatus::Available; + // Force D3D11 on even if we disabled it. + d3d11.UserForceEnable("User force-enabled WARP on disabled hardware"); + + gfxConfig::EnableFallback( + Fallback::USE_D3D11_WARP_COMPOSITOR, + "Force-enabled by user preference"); } - if (gfxPrefs::LayersAccelerationForceEnabled()) { - *aCanUseHardware = true; - return FeatureStatus::Available; +} + +bool +gfxWindowsPlatform::UpdateDeviceInitData() +{ + if (!gfxPlatform::UpdateDeviceInitData()) { + return false; } - if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) { - int32_t status; - nsCString discardFailureId; - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, discardFailureId, &status))) { - if (status != nsIGfxInfo::FEATURE_STATUS_OK) { - if (CanUseWARP()) { - *aCanUseHardware = false; - return FeatureStatus::Available; - } - return FeatureStatus::Blacklisted; - } + if (gfxConfig::InitOrUpdate(Feature::D3D11_COMPOSITING, + GetParentDevicePrefs().useD3D11(), + FeatureStatus::Disabled, + "Disabled by parent process")) + { + if (GetParentDevicePrefs().useD3D11WARP()) { + gfxConfig::EnableFallback(Fallback::USE_D3D11_WARP_COMPOSITOR, "Requested by parent process"); } } - // If we've used WARP once, we continue to use it after device resets. - *aCanUseHardware = !mIsWARP; - return FeatureStatus::Available; + gfxConfig::InitOrUpdate( + Feature::DIRECT2D, + GetParentDevicePrefs().useD2D1(), + FeatureStatus::Disabled, + "Disabled by parent process"); + + return true; } // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h, @@ -2010,27 +2046,31 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreationHelper( return true; } -FeatureStatus -gfxWindowsPlatform::AttemptD3D11DeviceCreation() +void +gfxWindowsPlatform::AttemptD3D11DeviceCreation(FeatureState& d3d11) { RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter(); if (!adapter) { - return FeatureStatus::Unavailable; + d3d11.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a DXGI adapter"); + return; } HRESULT hr; RefPtr<ID3D11Device> device; if (!AttemptD3D11DeviceCreationHelper(adapter, device, hr)) { gfxCriticalError() << "Crash during D3D11 device creation"; - return FeatureStatus::Crashed; + d3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed trying to acquire a D3D11 device"); + return; } if (FAILED(hr) || !device) { gfxCriticalError() << "D3D11 device creation failed: " << hexa(hr); - return FeatureStatus::Failed; + d3d11.SetFailed(FeatureStatus::Failed, "Failed to acquire a D3D11 device"); + return; } if (!DoesD3D11DeviceWork()) { - return FeatureStatus::Blocked; + d3d11.SetFailed(FeatureStatus::Broken, "Direct3D11 device was determined to be broken"); + return; } { @@ -2042,13 +2082,12 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation() // GetDeviceRemovedReason to return weird values. mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device); - if (!mCompositorD3D11TextureSharingWorks || !DoesRenderTargetViewNeedsRecreating(mD3D11Device)) { - gANGLESupportsD3D11 = false; + if (!mCompositorD3D11TextureSharingWorks || DoesRenderTargetViewNeedsRecreating(mD3D11Device)) { + gANGLESupportsD3D11 = false; } mD3D11Device->SetExceptionMode(0); mIsWARP = false; - return FeatureStatus::Available; } bool @@ -2074,22 +2113,25 @@ gfxWindowsPlatform::AttemptWARPDeviceCreationHelper( return true; } -FeatureStatus +void gfxWindowsPlatform::AttemptWARPDeviceCreation() { ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP()); + FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); HRESULT hr; RefPtr<ID3D11Device> device; if (!AttemptWARPDeviceCreationHelper(reporterWARP, device, hr)) { gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!"; - return FeatureStatus::Crashed; + d3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed creating a D3D11 WARP device"); + return; } if (FAILED(hr) || !device) { // This should always succeed... in theory. gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr); - return FeatureStatus::Failed; + d3d11.SetFailed(FeatureStatus::Failed, "Failed to create a D3D11 WARP device"); + return; } { @@ -2104,7 +2146,6 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation() } mD3D11Device->SetExceptionMode(0); mIsWARP = true; - return FeatureStatus::Available; } bool @@ -2177,7 +2218,7 @@ gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation() if (!AttemptD3D11ContentDeviceCreationHelper(adapter, hr)) { gfxCriticalNote << "Recovered from crash while creating a D3D11 content device"; RecordContentDeviceFailure(TelemetryDeviceCode::Content); - return FeatureStatus::Crashed; + return FeatureStatus::CrashedInHandler; } if (FAILED(hr) || !mD3D11ContentDevice) { @@ -2236,7 +2277,7 @@ gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation() if (!AttemptD3D11ImageBridgeDeviceCreationHelper(GetDXGIAdapter(), hr)) { gfxCriticalNote << "Recovered from crash while creating a D3D11 image bridge device"; RecordContentDeviceFailure(TelemetryDeviceCode::Image); - return FeatureStatus::Crashed; + return FeatureStatus::CrashedInHandler; } if (FAILED(hr) || !mD3D11ImageBridgeDevice) { @@ -2257,75 +2298,50 @@ gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation() return FeatureStatus::Available; } -void -gfxWindowsPlatform::SetDeviceInitData(mozilla::gfx::DeviceInitData& aData) -{ - MOZ_ASSERT(XRE_IsContentProcess()); - sDeviceInitDataDoNotUseDirectly = aData; -} - void gfxWindowsPlatform::InitializeDevices() { + // Ask the parent process for an updated list of which devices to create. + UpdateDeviceInitData(); + // If acceleration is disabled, we refuse to initialize anything. - mAcceleration = CheckAccelerationSupport(); - if (IsFeatureStatusFailure(mAcceleration)) { + if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { return; } - // If we previously crashed initializing devices, bail out now. This is - // effectively a parent-process only check, since the content process - // cannot create a lock file. + MOZ_ASSERT(!InSafeMode()); + + // If we previously crashed initializing devices, bail out now. D3D11LayersCrashGuard detectCrashes; if (detectCrashes.Crashed()) { - mAcceleration = FeatureStatus::Blocked; - return; - } - - // If we're going to prefer D3D9, stop here. The rest of this function - // attempts to use D3D11 features. - if (gfxPrefs::LayersPreferD3D9()) { - mD3D11Status = FeatureStatus::Disabled; + gfxConfig::SetFailed(Feature::HW_COMPOSITING, + FeatureStatus::CrashedOnStartup, + "Crashed during startup in a previous session"); + gfxConfig::SetFailed(Feature::D3D11_COMPOSITING, + FeatureStatus::CrashedOnStartup, + "Harware acceleration crashed during startup in a previous session"); + gfxConfig::SetFailed(Feature::DIRECT2D, + FeatureStatus::CrashedOnStartup, + "Harware acceleration crashed during startup in a previous session"); return; } // First, initialize D3D11. If this succeeds we attempt to use Direct2D. InitializeD3D11(); + InitializeD2D(); - // Initialize Direct2D. - if (mD3D11Status == FeatureStatus::Available) { - InitializeD2D(); - } - - // Usually we want D2D in order to use DWrite, but if the users have it - // forced, we'll let them have it, as unsupported configuration. - if (gfxPrefs::DirectWriteFontRenderingForceEnabled() && - IsFeatureStatusFailure(mD2D1Status) && - !mDWriteFactory) { - gfxCriticalNote << "Attempting DWrite without D2D support"; - InitDWriteSupport(); - } -} + if (!gfxConfig::IsEnabled(Feature::DIRECT2D)) { + if (XRE_IsContentProcess() && GetParentDevicePrefs().useD2D1()) { + RecordContentDeviceFailure(TelemetryDeviceCode::D2D1); + } -FeatureStatus -gfxWindowsPlatform::CheckAccelerationSupport() -{ - // Don't retry acceleration if it failed earlier. - if (IsFeatureStatusFailure(mAcceleration)) { - return mAcceleration; - } - if (XRE_IsContentProcess()) { - return GetParentDevicePrefs().useAcceleration() - ? FeatureStatus::Available - : FeatureStatus::Blocked; - } - if (InSafeMode()) { - return FeatureStatus::Blocked; - } - if (!ShouldUseLayersAcceleration()) { - return FeatureStatus::Disabled; + // Usually we want D2D in order to use DWrite, but if the users have it + // forced, we'll let them have it, as unsupported configuration. + if (gfxPrefs::DirectWriteFontRenderingForceEnabled() && !mDWriteFactory) { + gfxCriticalNote << "Attempting DWrite without D2D support"; + InitDWriteSupport(); + } } - return FeatureStatus::Available; } bool @@ -2350,9 +2366,8 @@ gfxWindowsPlatform::InitializeD3D11() // a WARP device which should always be available on Windows 7 and higher. // Check if D3D11 is supported on this hardware. - bool canUseHardware = true; - mD3D11Status = CheckD3D11Support(&canUseHardware); - if (IsFeatureStatusFailure(mD3D11Status)) { + FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); + if (!d3d11.IsEnabled()) { return; } @@ -2362,59 +2377,66 @@ gfxWindowsPlatform::InitializeD3D11() (decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice"); if (!sD3D11CreateDeviceFn) { // We should just be on Windows Vista or XP in this case. - mD3D11Status = FeatureStatus::Unavailable; + d3d11.SetFailed(FeatureStatus::Unavailable, "Direct3D11 not available on this computer"); return; } // Check if a failure was injected for testing. if (gfxPrefs::DeviceFailForTesting()) { - mD3D11Status = FeatureStatus::Failed; + d3d11.SetFailed(FeatureStatus::Failed, "Direct3D11 device failure simulated by preference"); return; } if (XRE_IsParentProcess()) { - // First try to create a hardware accelerated device. - if (canUseHardware) { - mD3D11Status = AttemptD3D11DeviceCreation(); - if (mD3D11Status == FeatureStatus::Crashed) { + if (!gfxConfig::UseFallback(Fallback::USE_D3D11_WARP_COMPOSITOR)) { + AttemptD3D11DeviceCreation(d3d11); + if (d3d11.GetValue() == FeatureStatus::CrashedInHandler) { return; } + + // If we failed to get a device, but WARP is allowed and might work, + // re-enable D3D11 and switch to WARP. + if (!mD3D11Device && IsWARPStable() && !gfxPrefs::LayersD3D11DisableWARP()) { + gfxConfig::Reenable(Feature::D3D11_COMPOSITING, Fallback::USE_D3D11_WARP_COMPOSITOR); + } } // If that failed, see if we can use WARP. - if (!mD3D11Device) { - if (!CanUseWARP()) { - mD3D11Status = FeatureStatus::Blocked; + if (gfxConfig::UseFallback(Fallback::USE_D3D11_WARP_COMPOSITOR)) { + MOZ_ASSERT(d3d11.IsEnabled()); + MOZ_ASSERT(!mD3D11Device); + MOZ_ASSERT(IsWARPStable() || gfxPrefs::LayersD3D11ForceWARP()); + + AttemptWARPDeviceCreation(); + if (d3d11.GetValue() == FeatureStatus::CrashedInHandler) { return; } - mD3D11Status = AttemptWARPDeviceCreation(); } // If we still have no device by now, exit. if (!mD3D11Device) { - MOZ_ASSERT(IsFeatureStatusFailure(mD3D11Status)); + MOZ_ASSERT(!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)); return; } // Either device creation function should have returned Available. - MOZ_ASSERT(mD3D11Status == FeatureStatus::Available); + MOZ_ASSERT(d3d11.IsEnabled()); } else { // Child processes do not need a compositor, but they do need to know // whether the parent process is using WARP and whether or not texture // sharing works. - mIsWARP = !canUseHardware; + mIsWARP = gfxConfig::UseFallback(Fallback::USE_D3D11_WARP_COMPOSITOR); mCompositorD3D11TextureSharingWorks = GetParentDevicePrefs().d3d11TextureSharingWorks(); - mD3D11Status = FeatureStatus::Available; } if (CanUseD3D11ImageBridge()) { - if (AttemptD3D11ImageBridgeDeviceCreation() == FeatureStatus::Crashed) { + if (AttemptD3D11ImageBridgeDeviceCreation() == FeatureStatus::CrashedInHandler) { DisableD3D11AfterCrash(); return; } } - if (AttemptD3D11ContentDeviceCreation() == FeatureStatus::Crashed) { + if (AttemptD3D11ContentDeviceCreation() == FeatureStatus::CrashedInHandler) { DisableD3D11AfterCrash(); return; } @@ -2428,7 +2450,9 @@ gfxWindowsPlatform::InitializeD3D11() void gfxWindowsPlatform::DisableD3D11AfterCrash() { - mD3D11Status = FeatureStatus::Crashed; + gfxConfig::Disable(Feature::D3D11_COMPOSITING, + FeatureStatus::CrashedInHandler, + "Crashed while acquiring a Direct3D11 device"); ResetD3D11Devices(); } @@ -2459,50 +2483,29 @@ IsD2DBlacklisted() return false; } -// Check whether we can support Direct2D. Although some of these checks will -// not change after a TDR (like the OS version), we could find a driver change -// that runs us into the blacklist. -FeatureStatus -gfxWindowsPlatform::CheckD2D1Support() +void +gfxWindowsPlatform::InitializeD2DConfig() { - // Don't revive D2D1 support after a failure. - if (IsFeatureStatusFailure(mD2D1Status)) { - return mD2D1Status; - } - - if (!gfxPrefs::Direct2DForceEnabled() && IsD2DBlacklisted()) { - return FeatureStatus::Blacklisted; - } - - // Do not ever try to use D2D if it's explicitly disabled. - if (gfxPrefs::Direct2DDisabled()) { - return FeatureStatus::Disabled; - } + FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D); - // Direct2D is only Vista or higher, but we require a D3D11 compositor to - // use it. (This check may be implied by the fact that we do not get here - // without a D3D11 compositor device.) - if (!IsVistaOrLater()) { - return FeatureStatus::Unavailable; - } - - // Normally we don't use D2D content drawing when using WARP. However if - // WARP is force-enabled, we will let Direct2D use WARP as well. - if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) { - return FeatureStatus::Blocked; + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D requires Direct3D 11 compositing"); + } else if (!IsVistaOrLater()) { + d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D is not available on Windows XP"); + } else { + d2d1.SetDefaultFromPref( + gfxPrefs::GetDirect2DDisabledPrefName(), + false, + gfxPrefs::GetDirect2DDisabledPrefDefault()); } - - if (!Factory::SupportsD2D1()) { - return FeatureStatus::Unavailable; + + if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D)) { + d2d1.Disable(FeatureStatus::Blacklisted, "Direct2D is blacklisted on this hardware"); } - if (XRE_IsContentProcess()) { - return GetParentDevicePrefs().useD2D1() - ? FeatureStatus::Available - : FeatureStatus::Blocked; + if (!d2d1.IsEnabled() && gfxPrefs::Direct2DForceEnabled()) { + d2d1.UserForceEnable("Force-enabled via user-preference"); } - - return FeatureStatus::Available; } void @@ -2510,41 +2513,48 @@ gfxWindowsPlatform::InitializeD2D() { ScopedGfxFeatureReporter d2d1_1("D2D1.1"); - mD2D1Status = CheckD2D1Support(); - if (IsFeatureStatusFailure(mD2D1Status)) { - if (XRE_IsContentProcess() && GetParentDevicePrefs().useD2D1()) { - RecordContentDeviceFailure(TelemetryDeviceCode::D2D1); - } + FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D); + + // We don't know this value ahead of time, but the user can force-override + // it, so we use Disable instead of SetFailed. + if (mIsWARP) { + d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP"); + } + + // If we pass all the initial checks, we can proceed to runtime decisions. + if (!d2d1.IsEnabled()) { + return; + } + + if (!Factory::SupportsD2D1()) { + d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory"); return; } - // If we don't have a content device, don't init - // anything else below such as dwrite if (!mD3D11ContentDevice) { - mD2D1Status = FeatureStatus::Failed; + d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device"); return; } if (!mCompositorD3D11TextureSharingWorks) { - mD2D1Status = FeatureStatus::Failed; + d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing"); return; } // Using Direct2D depends on DWrite support. if (!mDWriteFactory && !InitDWriteSupport()) { - mD2D1Status = FeatureStatus::Failed; + d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support"); return; } // Verify that Direct2D device creation succeeded. if (!Factory::SetDirect3D11Device(mD3D11ContentDevice)) { - mD2D1Status = FeatureStatus::Failed; + d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device"); return; } + MOZ_ASSERT(d2d1.IsEnabled()); d2d1_1.SetSuccessful(); - - mD2D1Status = FeatureStatus::Available; } bool @@ -2888,16 +2898,18 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aB aBackends.AppendElement(LayersBackend::LAYERS_OPENGL); } + bool allowTryingD3D9 = false; if (!gfxPrefs::LayersPreferD3D9()) { - if (gfxPlatform::CanUseDirect3D11() && mD3D11Device) { + if (mD3D11Device) { aBackends.AppendElement(LayersBackend::LAYERS_D3D11); } else { + allowTryingD3D9 = gfxPrefs::LayersAllowD3D9Fallback(); NS_WARNING("Direct3D 11-accelerated layers are not supported on this system."); } } - if (gfxPrefs::LayersPreferD3D9() || !IsVistaOrLater()) { - // We don't want D3D9 except on Windows XP + if (gfxPrefs::LayersPreferD3D9() || !IsVistaOrLater() || allowTryingD3D9) { + // We don't want D3D9 except on Windows XP, unless we failed to get D3D11 if (gfxPlatform::CanUseDirect3D9()) { aBackends.AppendElement(LayersBackend::LAYERS_D3D9); } else { @@ -2906,26 +2918,6 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aB } } -// Some features are dependent on other features. If this is the case, we -// try to propagate the status of the parent feature if it wasn't available. -FeatureStatus -gfxWindowsPlatform::GetD3D11Status() const -{ - if (mAcceleration != FeatureStatus::Available) { - return mAcceleration; - } - return mD3D11Status; -} - -FeatureStatus -gfxWindowsPlatform::GetD2D1Status() const -{ - if (GetD3D11Status() != FeatureStatus::Available) { - return FeatureStatus::Unavailable; - } - return mD2D1Status; -} - unsigned gfxWindowsPlatform::GetD3D11Version() { @@ -2945,7 +2937,7 @@ gfxWindowsPlatform::GetDeviceInitData(DeviceInitData* aOut) gfxPlatform::GetDeviceInitData(aOut); // IPDL initializes each field to false for us so we can early return. - if (GetD3D11Status() != FeatureStatus::Available) { + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { return; } @@ -2953,7 +2945,7 @@ gfxWindowsPlatform::GetDeviceInitData(DeviceInitData* aOut) aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice; aOut->d3d11TextureSharingWorks() = mCompositorD3D11TextureSharingWorks; aOut->useD3D11WARP() = mIsWARP; - aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available); + aOut->useD2D1() = gfxConfig::IsEnabled(Feature::DIRECT2D); if (mD3D11Device) { DXGI_ADAPTER_DESC desc; diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index baf3367bdc..725cade47a 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -46,6 +46,7 @@ namespace mozilla { namespace gfx { class DrawTarget; +class FeatureState; } namespace layers { class DeviceManagerD3D9; @@ -137,8 +138,7 @@ class gfxWindowsPlatform : public gfxPlatform { RENDER_MODE_MAX }; - RenderMode GetRenderMode() { return mRenderMode; } - void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; } + bool IsDirect2DBackend(); /** * Updates render mode with relation to the current preferences and @@ -244,11 +244,6 @@ class gfxWindowsPlatform : public gfxPlatform { bool HandleDeviceReset(); void UpdateBackendPrefs(); - // Return the diagnostic status of DirectX initialization. If - // initialization has not been attempted, this returns - // FeatureStatus::Unused. - mozilla::gfx::FeatureStatus GetD3D11Status() const; - mozilla::gfx::FeatureStatus GetD2D1Status() const; unsigned GetD3D11Version(); void TestDeviceReset(DeviceResetReason aReason); @@ -271,7 +266,7 @@ class gfxWindowsPlatform : public gfxPlatform { } void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends) override; virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override; - void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData) override; + bool UpdateDeviceInitData() override; protected: RenderMode mRenderMode; @@ -281,25 +276,26 @@ class gfxWindowsPlatform : public gfxPlatform { private: void Init(); + void InitAcceleration() override; void InitializeDevices(); void InitializeD3D11(); void InitializeD2D(); bool InitDWriteSupport(); - void DisableD2D(); + void DisableD2D(mozilla::gfx::FeatureStatus aStatus, const char* aMessage); - mozilla::gfx::FeatureStatus CheckAccelerationSupport(); - mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware); - mozilla::gfx::FeatureStatus CheckD2D1Support(); + void InitializeConfig(); + void InitializeD3D11Config(); + void InitializeD2DConfig(); - mozilla::gfx::FeatureStatus AttemptD3D11DeviceCreation(); + void AttemptD3D11DeviceCreation(mozilla::gfx::FeatureState& d3d11); bool AttemptD3D11DeviceCreationHelper( IDXGIAdapter1* aAdapter, RefPtr<ID3D11Device>& aOutDevice, HRESULT& aResOut); - mozilla::gfx::FeatureStatus AttemptWARPDeviceCreation(); + void AttemptWARPDeviceCreation(); bool AttemptWARPDeviceCreationHelper( mozilla::ScopedGfxFeatureReporter& aReporterWARP, RefPtr<ID3D11Device>& aOutDevice, @@ -313,6 +309,7 @@ class gfxWindowsPlatform : public gfxPlatform { bool AttemptD3D11ContentDeviceCreationHelper( IDXGIAdapter1* aAdapter, HRESULT& aResOut); + bool CanUseWARP(); bool CanUseD3D11ImageBridge(); bool ContentAdapterIsParentAdapter(ID3D11Device* device); @@ -341,12 +338,6 @@ class gfxWindowsPlatform : public gfxPlatform { RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager; - // These should not be accessed directly. Use the Get[Feature]Status - // accessors instead. - mozilla::gfx::FeatureStatus mAcceleration; - mozilla::gfx::FeatureStatus mD3D11Status; - mozilla::gfx::FeatureStatus mD2D1Status; - nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels; }; diff --git a/layout/forms/nsMeterFrame.h b/layout/forms/nsMeterFrame.h index fcdac620de..6a5c149cbd 100644 --- a/layout/forms/nsMeterFrame.h +++ b/layout/forms/nsMeterFrame.h @@ -10,6 +10,7 @@ #include "nsContainerFrame.h" #include "nsIAnonymousContentCreator.h" #include "nsCOMPtr.h" +#include "nsCSSPseudoElements.h" class nsMeterFrame : public nsContainerFrame, public nsIAnonymousContentCreator @@ -75,7 +76,7 @@ class nsMeterFrame : public nsContainerFrame, */ bool ShouldUseNativeStyle() const; - virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; + virtual Element* GetPseudoElement(mozilla::CSSPseudoElementType aType) override; protected: // Helper function which reflow the anonymous div frame. diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index 7dacc82182..0cff35869e 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -26,6 +26,7 @@ #undef GetBinaryType #undef RemoveDirectory #undef LoadIcon +#undef GetObject #endif class nsPresContext; diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index a9a3c5931b..3994f11425 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -670,6 +670,7 @@ BrotliDecoderDecompressStream BrotliDecoderIsFinished #ifdef MOZ_WEBRTC downmix_int +tonality_analysis_init #ifdef MOZ_SAMPLE_TYPE_FLOAT32 run_analysis #endif diff --git a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp index a962976945..cfddff38bf 100644 --- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp +++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp @@ -2082,13 +2082,27 @@ void JsepSessionImpl::SetupDefaultCodecs() { // Supported audio codecs. + // Per jmspeex on IRC: + // For 32KHz sampling, 28 is ok, 32 is good, 40 should be really good + // quality. Note that 1-2Kbps will be wasted on a stereo Opus channel + // with mono input compared to configuring it for mono. + // If we reduce bitrate enough Opus will low-pass us; 16000 will kill a + // 9KHz tone. This should be adaptive when we're at the low-end of video + // bandwidth (say <100Kbps), and if we're audio-only, down to 8 or + // 12Kbps. mSupportedCodecs.values.push_back(new JsepAudioCodecDescription( "109", "opus", 48000, 2, 960, - 16000)); +#ifdef WEBRTC_GONK + // TODO Move this elsewhere to be adaptive to rate - Bug 1207925 + 16000 // B2G uses lower capture sampling rate +#else + 40000 +#endif + )); mSupportedCodecs.values.push_back(new JsepAudioCodecDescription( "9", @@ -2430,4 +2444,5 @@ JsepSessionImpl::AllLocalTracksAreAssigned() const return true; } + } // namespace mozilla diff --git a/media/webrtc/signaling/src/jsep/JsepTrack.cpp b/media/webrtc/signaling/src/jsep/JsepTrack.cpp index e7b8111eb7..d867f6ced9 100644 --- a/media/webrtc/signaling/src/jsep/JsepTrack.cpp +++ b/media/webrtc/signaling/src/jsep/JsepTrack.cpp @@ -317,7 +317,6 @@ void JsepTrack::NegotiateCodecs( const SdpMediaSection& remote, std::vector<JsepCodecDescription*>* codecs, - const SdpMediaSection* answer, std::map<std::string, std::string>* formatChanges) const { PtrVector<JsepCodecDescription> unnegotiatedCodecs; @@ -335,15 +334,6 @@ JsepTrack::NegotiateCodecs( if(codec->Negotiate(fmt, remote)) { codecs->push_back(codec); unnegotiatedCodecs.values[i] = nullptr; - if (answer) { - // Answer's formats are authoritative, and they might be different - for (const std::string& answerFmt : answer->GetFormats()) { - if (codec->Matches(answerFmt, *answer)) { - codec->mDefaultPt = answerFmt; - break; // We found the corresponding format in |answer|, bail - } - } - } if (formatChanges) { (*formatChanges)[originalFormat] = codec->mDefaultPt; } @@ -377,7 +367,6 @@ JsepTrack::Negotiate(const SdpMediaSection& answer, std::map<std::string, std::string> formatChanges; NegotiateCodecs(remote, &negotiatedCodecs.values, - &answer, &formatChanges); // Use |formatChanges| to update mPrototypeCodecs diff --git a/media/webrtc/signaling/src/jsep/JsepTrack.h b/media/webrtc/signaling/src/jsep/JsepTrack.h index db6bcf000a..9e60d9a093 100644 --- a/media/webrtc/signaling/src/jsep/JsepTrack.h +++ b/media/webrtc/signaling/src/jsep/JsepTrack.h @@ -233,15 +233,12 @@ class JsepTrack const std::vector<JsepCodecDescription*>& negotiatedCodecs, JsepTrackNegotiatedDetails* details); - // |answer| is set when performing the final negotiation on completion of - // offer/answer, and is used to update the formats in |codecs|, since the - // answer is authoritative. |formatChanges| is also set on completion of - // offer/answer, and records how the formats in |codecs| were changed, which - // is used by |Negotiate| to update |mPrototypeCodecs|. + // |formatChanges| is set on completion of offer/answer, and records how the + // formats in |codecs| were changed, which is used by |Negotiate| to update + // |mPrototypeCodecs|. virtual void NegotiateCodecs( const SdpMediaSection& remote, std::vector<JsepCodecDescription*>* codecs, - const SdpMediaSection* answer = nullptr, std::map<std::string, std::string>* formatChanges = nullptr) const; JsConstraints* FindConstraints( diff --git a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp index 04a6855874..929ec233e5 100644 --- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp @@ -25,6 +25,7 @@ #include "webrtc/common.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" +#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" #include "webrtc/voice_engine/include/voe_errors.h" #include "webrtc/system_wrappers/interface/clock.h" @@ -204,16 +205,20 @@ bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, unsigned int* packetsSent, uint64_t* bytesSent) { - struct webrtc::SenderInfo senderInfo; - bool result = !mPtrRTP->GetRemoteRTCPSenderInfo(mChannel, &senderInfo); - if (result) { - *timestamp = NTPtoDOMHighResTimeStamp(senderInfo.NTP_timestamp_high, - senderInfo.NTP_timestamp_low); - *packetsSent = senderInfo.sender_packet_count; - *bytesSent = senderInfo.sender_octet_count; - } - return result; -} + webrtc::RTCPSenderInfo senderInfo; + webrtc::RtpRtcp * rtpRtcpModule; + webrtc::RtpReceiver * rtp_receiver; + bool result = + !mPtrVoEVideoSync->GetRtpRtcp(mChannel,&rtpRtcpModule,&rtp_receiver) && + !rtpRtcpModule->RemoteRTCPStat(&senderInfo); + if (result){ + *timestamp = NTPtoDOMHighResTimeStamp(senderInfo.NTPseconds, + senderInfo.NTPfraction); + *packetsSent = senderInfo.sendPacketCount; + *bytesSent = senderInfo.sendOctetCount; + } + return result; + } /* * WebRTCAudioConduit Implementation diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index 4ccd7fb1da..f9b9ef5c40 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -15,6 +15,7 @@ #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "mozilla/media/MediaUtils.h" +#include "mozilla/TemplateLib.h" #include "webrtc/common_types.h" #include "webrtc/common_video/interface/native_handle.h" @@ -1007,7 +1008,7 @@ static ResolutionAndBitrateLimits kResolutionAndBitrateLimits[] = { {MB_OF(1920, 1200), 1500, 2000, 10000}, // >HD (3K, 4K, etc) {MB_OF(1280, 720), 1200, 1500, 5000}, // HD ~1080-1200 {MB_OF(800, 480), 600, 800, 2500}, // HD ~720 - {std::max(MB_OF(400, 240), MB_OF(352, 288)), 200, 300, 1300}, // VGA, WVGA + {tl::Max<MB_OF(400, 240), MB_OF(352, 288)>::value, 200, 300, 1300}, // VGA, WVGA {MB_OF(176, 144), 100, 150, 500}, // WQVGA, CIF {0 , 40, 80, 250} // QCIF and below }; @@ -1287,6 +1288,13 @@ WebrtcVideoConduit::ReconfigureSendCodec(unsigned short width, vie_codec.startBitrate, vie_codec.maxBitrate); + // These are based on lowest-fidelity, because if there is insufficient + // bandwidth for all streams, only the lowest fidelity one will be sent. + uint32_t minMinBitrate = 0; + uint32_t minStartBitrate = 0; + // Total for all simulcast streams. + uint32_t totalMaxBitrate = 0; + for (size_t i = vie_codec.numberOfSimulcastStreams; i > 0; --i) { webrtc::SimulcastStream& stream(vie_codec.simulcastStream[i - 1]); stream.width = width; @@ -1309,25 +1317,30 @@ WebrtcVideoConduit::ReconfigureSendCodec(unsigned short width, } // Give each layer default appropriate bandwidth limits based on the // resolution/framerate of that layer - SelectBitrates(stream.width, stream.height, stream.jsMaxBitrate, + SelectBitrates(stream.width, stream.height, + MinIgnoreZero(stream.jsMaxBitrate, vie_codec.maxBitrate), mLastFramerateTenths, stream.minBitrate, stream.targetBitrate, stream.maxBitrate); - vie_codec.minBitrate = std::min(stream.minBitrate, vie_codec.minBitrate); - vie_codec.startBitrate += stream.targetBitrate; - vie_codec.maxBitrate = std::max(stream.maxBitrate, vie_codec.maxBitrate); - // webrtc.org expects the last, highest fidelity, simulcast stream to // always have the same resolution as vie_codec + // Also set the least user-constrained of the stream bitrates on vie_codec. if (i == vie_codec.numberOfSimulcastStreams) { vie_codec.width = stream.width; vie_codec.height = stream.height; } + minMinBitrate = MinIgnoreZero(stream.minBitrate, minMinBitrate); + minStartBitrate = MinIgnoreZero(stream.targetBitrate, minStartBitrate); + totalMaxBitrate += stream.maxBitrate; } if (vie_codec.numberOfSimulcastStreams != 0) { - vie_codec.startBitrate /= vie_codec.numberOfSimulcastStreams; + vie_codec.minBitrate = std::max(minMinBitrate, vie_codec.minBitrate); + vie_codec.maxBitrate = std::min(totalMaxBitrate, vie_codec.maxBitrate); + vie_codec.startBitrate = std::max(vie_codec.minBitrate, + std::min(minStartBitrate, + vie_codec.maxBitrate)); } if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0) { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp index e4444e7f79..f8955fc9ee 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp @@ -173,9 +173,6 @@ class WebrtcAndroidMediaCodec { CSFLogDebug(logTag, "%s ", __FUNCTION__); } - virtual ~WebrtcAndroidMediaCodec() { - } - nsresult Configure(uint32_t width, uint32_t height, const jobject aSurface, @@ -197,7 +194,7 @@ class WebrtcAndroidMediaCodec { &format); if (NS_FAILED(res)) { - CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateVideoFormat failed err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateVideoFormat failed err = %d", __FUNCTION__, (int)res); return NS_ERROR_FAILURE; } @@ -205,7 +202,7 @@ class WebrtcAndroidMediaCodec { mCoder = CreateEncoder(mime); if (NS_FAILED(res)) { - CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateEncoderByType failed err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateEncoderByType failed err = %d", __FUNCTION__, (int)res); return NS_ERROR_FAILURE; } @@ -218,13 +215,13 @@ class WebrtcAndroidMediaCodec { } else { mCoder = CreateDecoder(mime); if (NS_FAILED(res)) { - CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateDecoderByType failed err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, CreateDecoderByType failed err = %d", __FUNCTION__, (int)res); return NS_ERROR_FAILURE; } } res = mCoder->Configure(format, nullptr, nullptr, flags); if (NS_FAILED(res)) { - CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, err = %d", __FUNCTION__, (int)res); } } @@ -244,7 +241,7 @@ class WebrtcAndroidMediaCodec { res = mCoder->Start(); if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, mCoder->start() return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return res; } isStarted = true; @@ -363,7 +360,7 @@ class WebrtcAndroidMediaCodec { res = BufferInfo::New(&bufferInfo); if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, BufferInfo::New return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return res; } int32_t outputIndex = DequeueOutputBuffer(bufferInfo); @@ -423,7 +420,7 @@ class WebrtcAndroidMediaCodec { if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, mCoder->DequeueInputBuffer() return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return -1; } return inputIndex; @@ -435,7 +432,7 @@ class WebrtcAndroidMediaCodec { if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, mCoder->QueueInputBuffer() return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); } } @@ -447,7 +444,7 @@ class WebrtcAndroidMediaCodec { if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, mCoder->DequeueOutputBuffer() return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return -1; } @@ -471,7 +468,7 @@ class WebrtcAndroidMediaCodec { mInputBuffers = (jobjectArray) env->NewGlobalRef(inputBuffers.Get()); if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, GetInputBuffers return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return nullptr; } @@ -491,7 +488,7 @@ class WebrtcAndroidMediaCodec { mOutputBuffers = (jobjectArray) env->NewGlobalRef(outputBuffers.Get()); if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcAndroidMediaCodec::%s, GetOutputBuffers return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return nullptr; } @@ -506,6 +503,10 @@ class WebrtcAndroidMediaCodec { mEncoderCallback = aCallback; } +protected: + virtual ~WebrtcAndroidMediaCodec() { + } + private: class OutputDrain : public MediaCodecOutputDrain { @@ -621,7 +622,7 @@ WebrtcMediaCodecVP8VideoEncoder::VerifyAndAllocate(const uint32_t minimumSize) int32_t WebrtcMediaCodecVP8VideoEncoder::InitEncode( const webrtc::VideoCodec* codecSettings, int32_t numberOfCores, - uint32_t maxPayloadSize) { + size_t maxPayloadSize) { mMaxPayloadSize = maxPayloadSize; CSFLogDebug(logTag, "%s, w = %d, h = %d", __FUNCTION__, codecSettings->width, codecSettings->height); @@ -651,7 +652,7 @@ int32_t WebrtcMediaCodecVP8VideoEncoder::Encode( if (res != NS_OK) { CSFLogDebug(logTag, "%s, encoder configure return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -659,7 +660,7 @@ int32_t WebrtcMediaCodecVP8VideoEncoder::Encode( if (NS_FAILED(res)) { mMediaCodecEncoder->isStarted = false; - CSFLogDebug(logTag, "%s start encoder. err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "%s start encoder. err = %d", __FUNCTION__, (int)res); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -730,7 +731,7 @@ int32_t WebrtcMediaCodecVP8VideoEncoder::Encode( res = BufferInfo::New(&bufferInfo); if (NS_FAILED(res)) { CSFLogDebug(logTag, "WebrtcMediaCodecVP8VideoEncoder::%s, BufferInfo::New return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return -1; } @@ -926,7 +927,7 @@ int32_t WebrtcMediaCodecVP8VideoDecoder::Decode( if (res != NS_OK) { CSFLogDebug(logTag, "%s, decoder configure return err = %d", - __FUNCTION__, res); + __FUNCTION__, (int)res); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -934,7 +935,7 @@ int32_t WebrtcMediaCodecVP8VideoDecoder::Decode( if (NS_FAILED(res)) { mMediaCodecDecoder->isStarted = false; - CSFLogDebug(logTag, "%s start decoder. err = %d", __FUNCTION__, res); + CSFLogDebug(logTag, "%s start decoder. err = %d", __FUNCTION__, (int)res); return WEBRTC_VIDEO_CODEC_ERROR; } diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.h index c8e57c0587..9d7e900fec 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.h @@ -34,8 +34,8 @@ class WebrtcMediaCodecVP8VideoEncoder : public WebrtcVideoEncoder { virtual uint64_t PluginID() const override { return 0; } virtual int32_t InitEncode(const webrtc::VideoCodec* codecSettings, - int32_t numberOfCores, - uint32_t maxPayloadSize) override; + int32_t numberOfCores, + size_t maxPayloadSize) override; virtual int32_t Encode(const webrtc::I420VideoFrame& inputImage, const webrtc::CodecSpecificInfo* codecSpecificInfo, diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp index 49aed35cd4..d4018c01b4 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp @@ -841,7 +841,7 @@ WebrtcOMXH264VideoEncoder::WebrtcOMXH264VideoEncoder() int32_t WebrtcOMXH264VideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumOfCores, - uint32_t aMaxPayloadSize) + size_t aMaxPayloadSize) { CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p init", this); diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h index 940c6270ad..71cf5c6815 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h @@ -40,7 +40,7 @@ class WebrtcOMXH264VideoEncoder : public WebrtcVideoEncoder virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumOfCores, - uint32_t aMaxPayloadSize) override; + size_t aMaxPayloadSize) override; virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage, const webrtc::CodecSpecificInfo* aCodecSpecificInfo, diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index f7689d0f1d..c262fab714 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -44,6 +44,7 @@ #include "libyuv/convert.h" #if !defined(MOZILLA_EXTERNAL_LINKAGE) #include "mozilla/PeerIdentity.h" +#include "mozilla/TaskQueue.h" #endif #include "mozilla/gfx/Point.h" #include "mozilla/gfx/Types.h" @@ -70,6 +71,410 @@ MOZ_MTLOG_MODULE("mediapipeline") namespace mozilla { +#if !defined(MOZILLA_EXTERNAL_LINKAGE) +class VideoConverterListener +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoConverterListener) + + virtual void OnVideoFrameConverted(unsigned char* aVideoFrame, + unsigned int aVideoFrameLength, + unsigned short aWidth, + unsigned short aHeight, + VideoType aVideoType, + uint64_t aCaptureTime) = 0; + + virtual void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) = 0; + +protected: + virtual ~VideoConverterListener() {} +}; + +// I420 buffer size macros +#define YSIZE(x,y) ((x)*(y)) +#define CRSIZE(x,y) ((((x)+1) >> 1) * (((y)+1) >> 1)) +#define I420SIZE(x,y) (YSIZE((x),(y)) + 2 * CRSIZE((x),(y))) + +// An async video frame format converter. +// +// Input is typically a MediaStream(Track)Listener driven by MediaStreamGraph. +// +// We keep track of the size of the TaskQueue so we can drop frames if +// conversion is taking too long. +// +// Output is passed through to all added VideoConverterListeners on a TaskQueue +// thread whenever a frame is converted. +class VideoFrameConverter +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoFrameConverter) + + VideoFrameConverter() + : mLength(0) + , last_img_(-1) // -1 is not a guaranteed invalid serial. See bug 1262134. + , disabled_frame_sent_(false) +#ifdef DEBUG + , mThrottleCount(0) + , mThrottleRecord(0) +#endif + , mMutex("VideoFrameConverter") + { + MOZ_COUNT_CTOR(VideoFrameConverter); + + RefPtr<SharedThreadPool> pool = + SharedThreadPool::Get(NS_LITERAL_CSTRING("VideoFrameConverter")); + + mTaskQueue = MakeAndAddRef<TaskQueue>(pool.forget()); + } + + void QueueVideoChunk(VideoChunk& aChunk, bool aForceBlack) + { + if (aChunk.IsNull()) { + return; + } + + // We get passed duplicate frames every ~10ms even with no frame change. + int32_t serial = aChunk.mFrame.GetImage()->GetSerial(); + if (serial == last_img_) { + return; + } + last_img_ = serial; + + // A throttling limit of 1 allows us to convert 2 frames concurrently. + // It's short enough to not build up too significant a delay, while + // giving us a margin to not cause some machines to drop every other frame. + const int32_t queueThrottlingLimit = 1; + if (mLength > queueThrottlingLimit) { + MOZ_MTLOG(ML_DEBUG, "VideoFrameConverter " << this << " queue is full." << + " Throttling by throwing away a frame."); +#ifdef DEBUG + ++mThrottleCount; + mThrottleRecord = std::max(mThrottleCount, mThrottleRecord); +#endif + return; + } + +#ifdef DEBUG + if (mThrottleCount > 0) { + auto level = ML_DEBUG; + if (mThrottleCount > 5) { + // Log at a higher level when we have large drops. + level = ML_INFO; + } + MOZ_MTLOG(level, "VideoFrameConverter " << this << " stopped" << + " throttling after throwing away " << mThrottleCount << + " frames. Longest throttle so far was " << + mThrottleRecord << " frames."); + mThrottleCount = 0; + } +#endif + + bool forceBlack = aForceBlack || aChunk.mFrame.GetForceBlack(); + + if (forceBlack) { + // Reset the last-img check. + // -1 is not a guaranteed invalid serial. See bug 1262134. + last_img_ = -1; + + if (disabled_frame_sent_) { + // After disabling we just pass one black frame to the encoder. + // Allocating and setting it to black steals some performance + // that can be avoided. We don't handle resolution changes while + // disabled for now. + return; + } + + disabled_frame_sent_ = true; + } else { + disabled_frame_sent_ = false; + } + + ++mLength; // Atomic + + nsCOMPtr<nsIRunnable> runnable = + NS_NewRunnableMethodWithArgs<StorensRefPtrPassByPtr<Image>, bool>( + this, &VideoFrameConverter::ProcessVideoFrame, + aChunk.mFrame.GetImage(), forceBlack); + mTaskQueue->Dispatch(runnable.forget()); + } + + void AddListener(VideoConverterListener* aListener) + { + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(!mListeners.Contains(aListener)); + mListeners.AppendElement(aListener); + } + + bool RemoveListener(VideoConverterListener* aListener) + { + MutexAutoLock lock(mMutex); + + return mListeners.RemoveElement(aListener); + } + +protected: + virtual ~VideoFrameConverter() + { + MOZ_COUNT_DTOR(VideoFrameConverter); + + mTaskQueue->BeginShutdown(); + mTaskQueue->AwaitShutdownAndIdle(); + } + + void VideoFrameConverted(unsigned char* aVideoFrame, + unsigned int aVideoFrameLength, + unsigned short aWidth, + unsigned short aHeight, + VideoType aVideoType, + uint64_t aCaptureTime) + { + MutexAutoLock lock(mMutex); + + for (RefPtr<VideoConverterListener>& listener : mListeners) { + listener->OnVideoFrameConverted(aVideoFrame, aVideoFrameLength, + aWidth, aHeight, aVideoType, aCaptureTime); + } + } + + void VideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) + { + MutexAutoLock lock(mMutex); + + for (RefPtr<VideoConverterListener>& listener : mListeners) { + listener->OnVideoFrameConverted(aVideoFrame); + } + } + + void ProcessVideoFrame(Image* aImage, bool aForceBlack) + { + --mLength; // Atomic + MOZ_ASSERT(mLength >= 0); + + if (aForceBlack) { + IntSize size = aImage->GetSize(); + uint32_t yPlaneLen = YSIZE(size.width, size.height); + uint32_t cbcrPlaneLen = 2 * CRSIZE(size.width, size.height); + uint32_t length = yPlaneLen + cbcrPlaneLen; + + // Send a black image. + auto pixelData = MakeUniqueFallible<uint8_t[]>(length); + if (pixelData) { + // YCrCb black = 0x10 0x80 0x80 + memset(pixelData.get(), 0x10, yPlaneLen); + // Fill Cb/Cr planes + memset(pixelData.get() + yPlaneLen, 0x80, cbcrPlaneLen); + + MOZ_MTLOG(ML_DEBUG, "Sending a black video frame"); + VideoFrameConverted(pixelData.get(), length, size.width, size.height, + mozilla::kVideoI420, 0); + } + return; + } + + ImageFormat format = aImage->GetFormat(); +#ifdef WEBRTC_GONK + GrallocImage* nativeImage = aImage->AsGrallocImage(); + if (nativeImage) { + android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer(); + int pixelFormat = graphicBuffer->getPixelFormat(); /* PixelFormat is an enum == int */ + mozilla::VideoType destFormat; + switch (pixelFormat) { + case HAL_PIXEL_FORMAT_YV12: + // all android must support this + destFormat = mozilla::kVideoYV12; + break; + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP: + destFormat = mozilla::kVideoNV21; + break; + case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_P: + destFormat = mozilla::kVideoI420; + break; + default: + // XXX Bug NNNNNNN + // use http://mxr.mozilla.org/mozilla-central/source/content/media/omx/I420ColorConverterHelper.cpp + // to convert unknown types (OEM-specific) to I420 + MOZ_MTLOG(ML_ERROR, "Un-handled GRALLOC buffer type:" << pixelFormat); + MOZ_CRASH(); + } + void *basePtr; + graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &basePtr); + uint32_t width = graphicBuffer->getWidth(); + uint32_t height = graphicBuffer->getHeight(); + // XXX gralloc buffer's width and stride could be different depends on implementations. + + if (destFormat != mozilla::kVideoI420) { + unsigned char *video_frame = static_cast<unsigned char*>(basePtr); + webrtc::I420VideoFrame i420_frame; + int stride_y = width; + int stride_uv = (width + 1) / 2; + int target_width = width; + int target_height = height; + if (i420_frame.CreateEmptyFrame(target_width, + abs(target_height), + stride_y, + stride_uv, stride_uv) < 0) { + MOZ_ASSERT(false, "Can't allocate empty i420frame"); + return; + } + webrtc::VideoType commonVideoType = + webrtc::RawVideoTypeToCommonVideoVideoType( + static_cast<webrtc::RawVideoType>((int)destFormat)); + if (ConvertToI420(commonVideoType, video_frame, 0, 0, width, height, + I420SIZE(width, height), webrtc::kVideoRotation_0, + &i420_frame)) { + MOZ_ASSERT(false, "Can't convert video type for sending to I420"); + return; + } + i420_frame.set_ntp_time_ms(0); + VideoFrameConverted(i420_frame); + } else { + VideoFrameConverted(static_cast<unsigned char*>(basePtr), + I420SIZE(width, height), + width, + height, + destFormat, 0); + } + graphicBuffer->unlock(); + return; + } else +#endif + if (format == ImageFormat::PLANAR_YCBCR) { + // Cast away constness b/c some of the accessors are non-const + PlanarYCbCrImage* yuv = const_cast<PlanarYCbCrImage *>( + static_cast<const PlanarYCbCrImage *>(aImage)); + + const PlanarYCbCrData *data = yuv->GetData(); + if (data) { + uint8_t *y = data->mYChannel; + uint8_t *cb = data->mCbChannel; + uint8_t *cr = data->mCrChannel; + uint32_t width = yuv->GetSize().width; + uint32_t height = yuv->GetSize().height; + uint32_t length = yuv->GetDataSize(); + // NOTE: length may be rounded up or include 'other' data (see + // YCbCrImageDataDeserializerBase::ComputeMinBufferSize()) + + // XXX Consider modifying these checks if we ever implement + // any subclasses of PlanarYCbCrImage that allow disjoint buffers such + // that y+3(width*height)/2 might go outside the allocation or there are + // pads between y, cr and cb. + // GrallocImage can have wider strides, and so in some cases + // would encode as garbage. If we need to encode it we'll either want to + // modify SendVideoFrame or copy/move the data in the buffer. + if (cb == (y + YSIZE(width, height)) && + cr == (cb + CRSIZE(width, height)) && + length >= I420SIZE(width, height)) { + MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame"); + VideoFrameConverted(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0); + return; + } else { + MOZ_MTLOG(ML_ERROR, "Unsupported PlanarYCbCrImage format: " + "width=" << width << ", height=" << height << ", y=" << y + << "\n Expected: cb=y+" << YSIZE(width, height) + << ", cr=y+" << YSIZE(width, height) + + CRSIZE(width, height) + << "\n Observed: cb=y+" << cb - y + << ", cr=y+" << cr - y + << "\n ystride=" << data->mYStride + << ", yskip=" << data->mYSkip + << "\n cbcrstride=" << data->mCbCrStride + << ", cbskip=" << data->mCbSkip + << ", crskip=" << data->mCrSkip + << "\n ywidth=" << data->mYSize.width + << ", yheight=" << data->mYSize.height + << "\n cbcrwidth=" << data->mCbCrSize.width + << ", cbcrheight=" << data->mCbCrSize.height); + NS_ASSERTION(false, "Unsupported PlanarYCbCrImage format"); + } + } + } + + RefPtr<SourceSurface> surf = aImage->GetAsSourceSurface(); + if (!surf) { + MOZ_MTLOG(ML_ERROR, "Getting surface from " << Stringify(format) << " image failed"); + return; + } + + RefPtr<DataSourceSurface> data = surf->GetDataSurface(); + if (!data) { + MOZ_MTLOG(ML_ERROR, "Getting data surface from " << Stringify(format) + << " image with " << Stringify(surf->GetType()) << "(" + << Stringify(surf->GetFormat()) << ") surface failed"); + return; + } + + IntSize size = aImage->GetSize(); + int half_width = (size.width + 1) >> 1; + int half_height = (size.height + 1) >> 1; + int c_size = half_width * half_height; + int buffer_size = YSIZE(size.width, size.height) + 2 * c_size; + auto yuv_scoped = MakeUniqueFallible<uint8[]>(buffer_size); + if (!yuv_scoped) { + return; + } + uint8* yuv = yuv_scoped.get(); + + DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); + if (!map.IsMapped()) { + MOZ_MTLOG(ML_ERROR, "Reading DataSourceSurface from " << Stringify(format) + << " image with " << Stringify(surf->GetType()) << "(" + << Stringify(surf->GetFormat()) << ") surface failed"); + return; + } + + int rv; + int cb_offset = YSIZE(size.width, size.height); + int cr_offset = cb_offset + c_size; + switch (surf->GetFormat()) { + case SurfaceFormat::B8G8R8A8: + case SurfaceFormat::B8G8R8X8: + rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()), + map.GetStride(), + yuv, size.width, + yuv + cb_offset, half_width, + yuv + cr_offset, half_width, + size.width, size.height); + break; + case SurfaceFormat::R5G6B5_UINT16: + rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()), + map.GetStride(), + yuv, size.width, + yuv + cb_offset, half_width, + yuv + cr_offset, half_width, + size.width, size.height); + break; + default: + MOZ_MTLOG(ML_ERROR, "Unsupported RGB video format" << Stringify(surf->GetFormat())); + MOZ_ASSERT(PR_FALSE); + return; + } + if (rv != 0) { + MOZ_MTLOG(ML_ERROR, Stringify(surf->GetFormat()) << " to I420 conversion failed"); + return; + } + MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame converted from " << + Stringify(surf->GetFormat())); + VideoFrameConverted(yuv, buffer_size, size.width, size.height, mozilla::kVideoI420, 0); + } + + Atomic<int32_t, Relaxed> mLength; + RefPtr<TaskQueue> mTaskQueue; + + // Written and read from the queueing thread (normally MSG). + int32_t last_img_; // serial number of last Image + bool disabled_frame_sent_; // If a black frame has been sent after disabling. +#ifdef DEBUG + uint32_t mThrottleCount; + uint32_t mThrottleRecord; +#endif + + // mMutex guards the below variables. + Mutex mMutex; + nsTArray<RefPtr<VideoConverterListener>> mListeners; +}; +#endif + static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp"; MediaPipeline::MediaPipeline(const std::string& pc, @@ -696,9 +1101,6 @@ friend class MediaPipelineTransmit; enabled_(false), direct_connect_(false), packetizer_(nullptr) -#if !defined(MOZILLA_EXTERNAL_LINKAGE) - , last_img_(-1) -#endif // MOZILLA_EXTERNAL_LINKAGE { } @@ -726,6 +1128,31 @@ friend class MediaPipelineTransmit; void SetActive(bool active) { active_ = active; } void SetEnabled(bool enabled) { enabled_ = enabled; } +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + void SetVideoFrameConverter(const RefPtr<VideoFrameConverter>& converter) + { + converter_ = converter; + } + + void OnVideoFrameConverted(unsigned char* aVideoFrame, + unsigned int aVideoFrameLength, + unsigned short aWidth, + unsigned short aHeight, + VideoType aVideoType, + uint64_t aCaptureTime) + { + MOZ_ASSERT(conduit_->type() == MediaSessionConduit::VIDEO); + static_cast<VideoSessionConduit*>(conduit_.get())->SendVideoFrame( + aVideoFrame, aVideoFrameLength, aWidth, aHeight, aVideoType, aCaptureTime); + } + + void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) + { + MOZ_ASSERT(conduit_->type() == MediaSessionConduit::VIDEO); + static_cast<VideoSessionConduit*>(conduit_.get())->SendVideoFrame(aVideoFrame); + } +#endif + // Implement MediaStreamTrackListener void NotifyQueuedChanges(MediaStreamGraph* aGraph, StreamTime aTrackOffset, @@ -750,11 +1177,11 @@ friend class MediaPipelineTransmit; virtual void ProcessAudioChunk(AudioSessionConduit *conduit, TrackRate rate, AudioChunk& chunk); -#if !defined(MOZILLA_EXTERNAL_LINKAGE) - virtual void ProcessVideoChunk(VideoSessionConduit *conduit, - VideoChunk& chunk); -#endif // MOZILLA_EXTERNAL_LINKAGE + RefPtr<MediaSessionConduit> conduit_; +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + RefPtr<VideoFrameConverter> converter_; +#endif // May be TRACK_INVALID until we see data from the track TrackID track_id_; // this is the current TrackID this listener is attached to @@ -773,10 +1200,71 @@ friend class MediaPipelineTransmit; bool direct_connect_; nsAutoPtr<AudioPacketizer<int16_t, int16_t>> packetizer_; +}; + #if !defined(MOZILLA_EXTERNAL_LINKAGE) - int32_t last_img_; // serial number of last Image -#endif // MOZILLA_EXTERNAL_LINKAGE +// Implements VideoConverterListener for MediaPipeline. +// +// We pass converted frames on to MediaPipelineTransmit::PipelineListener +// where they are further forwarded to VideoConduit. +// MediaPipelineTransmit calls Detach() during shutdown to ensure there is +// no cyclic dependencies between us and PipelineListener. +class MediaPipelineTransmit::VideoFrameFeeder + : public VideoConverterListener +{ +public: + explicit VideoFrameFeeder(const RefPtr<PipelineListener>& listener) + : listener_(listener), + mutex_("VideoFrameFeeder") + { + MOZ_COUNT_CTOR(VideoFrameFeeder); + } + + void Detach() + { + MutexAutoLock lock(mutex_); + + listener_ = nullptr; + } + + void OnVideoFrameConverted(unsigned char* aVideoFrame, + unsigned int aVideoFrameLength, + unsigned short aWidth, + unsigned short aHeight, + VideoType aVideoType, + uint64_t aCaptureTime) override + { + MutexAutoLock lock(mutex_); + + if (!listener_) { + return; + } + + listener_->OnVideoFrameConverted(aVideoFrame, aVideoFrameLength, + aWidth, aHeight, aVideoType, aCaptureTime); + } + + void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) override + { + MutexAutoLock lock(mutex_); + + if (!listener_) { + return; + } + + listener_->OnVideoFrameConverted(aVideoFrame); + } + +protected: + virtual ~VideoFrameFeeder() + { + MOZ_COUNT_DTOR(VideoFrameFeeder); + } + + RefPtr<PipelineListener> listener_; + Mutex mutex_; }; +#endif MediaPipelineTransmit::MediaPipelineTransmit( const std::string& pc, @@ -793,7 +1281,30 @@ MediaPipelineTransmit::MediaPipelineTransmit( conduit, rtp_transport, rtcp_transport, filter), listener_(new PipelineListener(conduit)), domtrack_(domtrack) -{} +{ +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + if (IsVideo()) { + // For video we send frames to an async VideoFrameConverter that calls + // back to a VideoFrameFeeder that feeds I420 frames to VideoConduit. + + feeder_ = MakeAndAddRef<VideoFrameFeeder>(listener_); + + converter_ = MakeAndAddRef<VideoFrameConverter>(); + converter_->AddListener(feeder_); + + listener_->SetVideoFrameConverter(converter_); + } +#endif +} + +MediaPipelineTransmit::~MediaPipelineTransmit() +{ +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + if (feeder_) { + feeder_->Detach(); + } +#endif +} nsresult MediaPipelineTransmit::Init() { AttachToTrack(track_id_); @@ -1104,11 +1615,6 @@ NotifyDirectListenerUninstalled() { direct_connect_ = false; } -// I420 buffer size macros -#define YSIZE(x,y) ((x)*(y)) -#define CRSIZE(x,y) ((((x)+1) >> 1) * (((y)+1) >> 1)) -#define I420SIZE(x,y) (YSIZE((x),(y)) + 2 * CRSIZE((x),(y))) - void MediaPipelineTransmit::PipelineListener:: NewData(MediaStreamGraph* graph, StreamTime offset, @@ -1152,8 +1658,7 @@ NewData(MediaStreamGraph* graph, VideoSegment::ChunkIterator iter(*video); while(!iter.IsEnded()) { - ProcessVideoChunk(static_cast<VideoSessionConduit*>(conduit_.get()), - *iter); + converter_->QueueVideoChunk(*iter, !enabled_); iter.Next(); } #endif @@ -1174,34 +1679,25 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( const int16_t* samples = nullptr; UniquePtr<int16_t[]> convertedSamples; - // If this track is not enabled, simply ignore the data in the chunk. - if (!enabled_) { - chunk.mBufferFormat = AUDIO_FORMAT_SILENCE; - } - // We take advantage of the fact that the common case (microphone directly to // PeerConnection, that is, a normal call), the samples are already 16-bits // mono, so the representation in interleaved and planar is the same, and we // can just use that. - if (outputChannels == 1 && chunk.mBufferFormat == AUDIO_FORMAT_S16) { + if (enabled_ && outputChannels == 1 && chunk.mBufferFormat == AUDIO_FORMAT_S16) { samples = chunk.ChannelData<int16_t>().Elements()[0]; } else { convertedSamples = MakeUnique<int16_t[]>(chunk.mDuration * outputChannels); - switch (chunk.mBufferFormat) { - case AUDIO_FORMAT_FLOAT32: - DownmixAndInterleave(chunk.ChannelData<float>(), - chunk.mDuration, chunk.mVolume, outputChannels, - convertedSamples.get()); - break; - case AUDIO_FORMAT_S16: - DownmixAndInterleave(chunk.ChannelData<int16_t>(), - chunk.mDuration, chunk.mVolume, outputChannels, - convertedSamples.get()); - break; - case AUDIO_FORMAT_SILENCE: - PodZero(convertedSamples.get(), chunk.mDuration * outputChannels); - break; + if (!enabled_ || chunk.mBufferFormat == AUDIO_FORMAT_SILENCE) { + PodZero(convertedSamples.get(), chunk.mDuration * outputChannels); + } else if (chunk.mBufferFormat == AUDIO_FORMAT_FLOAT32) { + DownmixAndInterleave(chunk.ChannelData<float>(), + chunk.mDuration, chunk.mVolume, outputChannels, + convertedSamples.get()); + } else if (chunk.mBufferFormat == AUDIO_FORMAT_S16) { + DownmixAndInterleave(chunk.ChannelData<int16_t>(), + chunk.mDuration, chunk.mVolume, outputChannels, + convertedSamples.get()); } samples = convertedSamples.get(); } @@ -1242,232 +1738,6 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( } } -#if !defined(MOZILLA_EXTERNAL_LINKAGE) -void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( - VideoSessionConduit* conduit, - VideoChunk& chunk) { - Image *img = chunk.mFrame.GetImage(); - - // We now need to send the video frame to the other side - if (!img) { - // segment.AppendFrame() allows null images, which show up here as null - return; - } - - if (!enabled_ || chunk.mFrame.GetForceBlack()) { - IntSize size = img->GetSize(); - uint32_t yPlaneLen = YSIZE(size.width, size.height); - uint32_t cbcrPlaneLen = 2 * CRSIZE(size.width, size.height); - uint32_t length = yPlaneLen + cbcrPlaneLen; - - // Send a black image. - auto pixelData = MakeUniqueFallible<uint8_t[]>(length); - if (pixelData) { - // YCrCb black = 0x10 0x80 0x80 - memset(pixelData.get(), 0x10, yPlaneLen); - // Fill Cb/Cr planes - memset(pixelData.get() + yPlaneLen, 0x80, cbcrPlaneLen); - - MOZ_MTLOG(ML_DEBUG, "Sending a black video frame"); - conduit->SendVideoFrame(pixelData.get(), length, size.width, size.height, - mozilla::kVideoI420, 0); - } - return; - } - - // We get passed duplicate frames every ~10ms even if there's no frame change! - int32_t serial = img->GetSerial(); - if (serial == last_img_) { - return; - } - last_img_ = serial; - - ImageFormat format = img->GetFormat(); -#ifdef WEBRTC_GONK - GrallocImage* nativeImage = img->AsGrallocImage(); - if (nativeImage) { - android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer(); - int pixelFormat = graphicBuffer->getPixelFormat(); /* PixelFormat is an enum == int */ - mozilla::VideoType destFormat; - switch (pixelFormat) { - case HAL_PIXEL_FORMAT_YV12: - // all android must support this - destFormat = mozilla::kVideoYV12; - break; - case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP: - destFormat = mozilla::kVideoNV21; - break; - case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_P: - destFormat = mozilla::kVideoI420; - break; - default: - // XXX Bug NNNNNNN - // use http://mxr.mozilla.org/mozilla-central/source/content/media/omx/I420ColorConverterHelper.cpp - // to convert unknown types (OEM-specific) to I420 - MOZ_MTLOG(ML_ERROR, "Un-handled GRALLOC buffer type:" << pixelFormat); - MOZ_CRASH(); - } - void *basePtr; - graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &basePtr); - uint32_t width = graphicBuffer->getWidth(); - uint32_t height = graphicBuffer->getHeight(); - // XXX gralloc buffer's width and stride could be different depends on implementations. - - if (destFormat != mozilla::kVideoI420) { - unsigned char *video_frame = static_cast<unsigned char*>(basePtr); - webrtc::I420VideoFrame i420_frame; - int stride_y = width; - int stride_uv = (width + 1) / 2; - int target_width = width; - int target_height = height; - if (i420_frame.CreateEmptyFrame(target_width, - abs(target_height), - stride_y, - stride_uv, stride_uv) < 0) { - MOZ_ASSERT(false, "Can't allocate empty i420frame"); - return; - } - webrtc::VideoType commonVideoType = - webrtc::RawVideoTypeToCommonVideoVideoType( - static_cast<webrtc::RawVideoType>((int)destFormat)); - if (ConvertToI420(commonVideoType, video_frame, 0, 0, width, height, - I420SIZE(width, height), webrtc::kVideoRotation_0, - &i420_frame)) { - MOZ_ASSERT(false, "Can't convert video type for sending to I420"); - return; - } - i420_frame.set_ntp_time_ms(0); - conduit->SendVideoFrame(i420_frame); - } else { - conduit->SendVideoFrame(static_cast<unsigned char*>(basePtr), - I420SIZE(width, height), - width, - height, - destFormat, 0); - } - graphicBuffer->unlock(); - return; - } else -#endif - if (format == ImageFormat::PLANAR_YCBCR) { - // Cast away constness b/c some of the accessors are non-const - PlanarYCbCrImage* yuv = const_cast<PlanarYCbCrImage *>( - static_cast<const PlanarYCbCrImage *>(img)); - - const PlanarYCbCrData *data = yuv->GetData(); - if (data) { - uint8_t *y = data->mYChannel; - uint8_t *cb = data->mCbChannel; - uint8_t *cr = data->mCrChannel; - uint32_t width = yuv->GetSize().width; - uint32_t height = yuv->GetSize().height; - uint32_t length = yuv->GetDataSize(); - // NOTE: length may be rounded up or include 'other' data (see - // YCbCrImageDataDeserializerBase::ComputeMinBufferSize()) - - // XXX Consider modifying these checks if we ever implement - // any subclasses of PlanarYCbCrImage that allow disjoint buffers such - // that y+3(width*height)/2 might go outside the allocation or there are - // pads between y, cr and cb. - // GrallocImage can have wider strides, and so in some cases - // would encode as garbage. If we need to encode it we'll either want to - // modify SendVideoFrame or copy/move the data in the buffer. - if (cb == (y + YSIZE(width, height)) && - cr == (cb + CRSIZE(width, height)) && - length >= I420SIZE(width, height)) { - MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame"); - conduit->SendVideoFrame(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0); - return; - } else { - MOZ_MTLOG(ML_ERROR, "Unsupported PlanarYCbCrImage format: " - "width=" << width << ", height=" << height << ", y=" << y - << "\n Expected: cb=y+" << YSIZE(width, height) - << ", cr=y+" << YSIZE(width, height) - + CRSIZE(width, height) - << "\n Observed: cb=y+" << cb - y - << ", cr=y+" << cr - y - << "\n ystride=" << data->mYStride - << ", yskip=" << data->mYSkip - << "\n cbcrstride=" << data->mCbCrStride - << ", cbskip=" << data->mCbSkip - << ", crskip=" << data->mCrSkip - << "\n ywidth=" << data->mYSize.width - << ", yheight=" << data->mYSize.height - << "\n cbcrwidth=" << data->mCbCrSize.width - << ", cbcrheight=" << data->mCbCrSize.height); - NS_ASSERTION(false, "Unsupported PlanarYCbCrImage format"); - } - } - } - - RefPtr<SourceSurface> surf = img->GetAsSourceSurface(); - if (!surf) { - MOZ_MTLOG(ML_ERROR, "Getting surface from " << Stringify(format) << " image failed"); - return; - } - - RefPtr<DataSourceSurface> data = surf->GetDataSurface(); - if (!data) { - MOZ_MTLOG(ML_ERROR, "Getting data surface from " << Stringify(format) - << " image with " << Stringify(surf->GetType()) << "(" - << Stringify(surf->GetFormat()) << ") surface failed"); - return; - } - - IntSize size = img->GetSize(); - int half_width = (size.width + 1) >> 1; - int half_height = (size.height + 1) >> 1; - int c_size = half_width * half_height; - int buffer_size = YSIZE(size.width, size.height) + 2 * c_size; - auto yuv_scoped = MakeUniqueFallible<uint8[]>(buffer_size); - if (!yuv_scoped) - return; - uint8* yuv = yuv_scoped.get(); - - DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); - if (!map.IsMapped()) { - MOZ_MTLOG(ML_ERROR, "Reading DataSourceSurface from " << Stringify(format) - << " image with " << Stringify(surf->GetType()) << "(" - << Stringify(surf->GetFormat()) << ") surface failed"); - return; - } - - int rv; - int cb_offset = YSIZE(size.width, size.height); - int cr_offset = cb_offset + c_size; - switch (surf->GetFormat()) { - case SurfaceFormat::B8G8R8A8: - case SurfaceFormat::B8G8R8X8: - rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()), - map.GetStride(), - yuv, size.width, - yuv + cb_offset, half_width, - yuv + cr_offset, half_width, - size.width, size.height); - break; - case SurfaceFormat::R5G6B5_UINT16: - rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()), - map.GetStride(), - yuv, size.width, - yuv + cb_offset, half_width, - yuv + cr_offset, half_width, - size.width, size.height); - break; - default: - MOZ_MTLOG(ML_ERROR, "Unsupported RGB video format" << Stringify(surf->GetFormat())); - MOZ_ASSERT(PR_FALSE); - return; - } - if (rv != 0) { - MOZ_MTLOG(ML_ERROR, Stringify(surf->GetFormat()) << " to I420 conversion failed"); - return; - } - MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame converted from " << - Stringify(surf->GetFormat())); - conduit->SendVideoFrame(yuv, buffer_size, size.width, size.height, mozilla::kVideoI420, 0); -} -#endif - class TrackAddedCallback { public: virtual void TrackAdded(TrackTicks current_ticks) = 0; @@ -1513,7 +1783,7 @@ static void AddTrackAndListener(MediaStream* source, completed_(completed) {} virtual void Run() override { - StreamTime current_end = mStream->GetBufferEnd(); + StreamTime current_end = mStream->GetTracksEnd(); TrackTicks current_ticks = mStream->TimeToTicksRoundUp(track_rate_, current_end); @@ -1531,13 +1801,11 @@ static void AddTrackAndListener(MediaStream* source, // to the "start" time for the track segment_->AppendNullData(current_ticks); if (segment_->GetType() == MediaSegment::AUDIO) { - mStream->AsSourceStream()->AddAudioTrack(track_id_, track_rate_, - current_ticks, + mStream->AsSourceStream()->AddAudioTrack(track_id_, track_rate_, 0, static_cast<AudioSegment*>(segment_.forget())); } else { NS_ASSERTION(mStream->GraphRate() == track_rate_, "Rate mismatch"); - mStream->AsSourceStream()->AddTrack(track_id_, - current_ticks, segment_.forget()); + mStream->AsSourceStream()->AddTrack(track_id_, 0, segment_.forget()); } // We need to know how much has been "inserted" because we're given absolute diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h index ba8a477a3a..e220008be9 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h @@ -21,7 +21,7 @@ #include "runnable_utils.h" #include "transportflow.h" #include "AudioPacketizer.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" @@ -30,6 +30,9 @@ class nsIPrincipal; namespace mozilla { class MediaPipelineFilter; class PeerIdentity; +#if !defined(MOZILLA_EXTERNAL_LINKAGE) +class VideoFrameConverter; +#endif #ifndef USE_FAKE_MEDIA_STREAMS namespace dom { @@ -332,11 +335,19 @@ class MediaPipelineTransmit : public MediaPipeline { // multiple tracks of a type in a stream yet). bug 1056650 virtual nsresult ReplaceTrack(dom::MediaStreamTrack& domtrack); - // Separate class to allow ref counting + // Separate classes to allow ref counting class PipelineListener; + class VideoFrameFeeder; + + protected: + ~MediaPipelineTransmit(); private: RefPtr<PipelineListener> listener_; +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + RefPtr<VideoFrameFeeder> feeder_; + RefPtr<VideoFrameConverter> converter_; +#endif dom::MediaStreamTrack* domtrack_; }; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index c3727aef2c..097057ec75 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -494,7 +494,7 @@ PeerConnectionImpl::MakeMediaStream() AudioChannel::Normal); RefPtr<DOMMediaStream> stream = - DOMMediaStream::CreateSourceStream(GetWindow(), graph); + DOMMediaStream::CreateSourceStreamAsInput(GetWindow(), graph); CSFLogDebug(logTag, "Created media stream %p, inner: %p", stream.get(), stream->GetInputStream()); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 019f2a946f..8dd60166b7 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -32,7 +32,7 @@ #include "mozilla/ErrorResult.h" #include "mozilla/dom/PeerConnectionImplEnumsBinding.h" #include "PrincipalChangeObserver.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #if !defined(MOZILLA_EXTERNAL_LINKAGE) #include "mozilla/TimeStamp.h" diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index 6ec2cdb306..9d6041098c 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -1177,6 +1177,7 @@ PeerConnectionMedia::OnCandidateFound_s(NrIceMediaStream *aStream, { ASSERT_ON_THREAD(mSTSThread); MOZ_ASSERT(aStream); + MOZ_RELEASE_ASSERT(mIceCtxHdlr); CSFLogDebug(logTag, "%s: %s", __FUNCTION__, aStream->name().c_str()); diff --git a/media/webrtc/signaling/src/sdp/SdpAttribute.cpp b/media/webrtc/signaling/src/sdp/SdpAttribute.cpp index 1d1952239c..73e9d8cb4f 100644 --- a/media/webrtc/signaling/src/sdp/SdpAttribute.cpp +++ b/media/webrtc/signaling/src/sdp/SdpAttribute.cpp @@ -1125,11 +1125,8 @@ void SdpSctpmapAttributeList::Serialize(std::ostream& os) const { for (auto i = mSctpmaps.begin(); i != mSctpmaps.end(); ++i) { - os << "a=" << mType << ":" << i->pt << " " << i->name; - if (i->streams) { - os << " " << i->streams; - } - os << CRLF; + os << "a=" << mType << ":" << i->pt << " " << i->name << " " << i->streams + << CRLF; } } diff --git a/media/webrtc/signaling/src/sdp/SdpHelper.cpp b/media/webrtc/signaling/src/sdp/SdpHelper.cpp index 32ab18b354..17d46e5ee2 100644 --- a/media/webrtc/signaling/src/sdp/SdpHelper.cpp +++ b/media/webrtc/signaling/src/sdp/SdpHelper.cpp @@ -159,8 +159,22 @@ SdpHelper::DisableMsection(Sdp* sdp, SdpMediaSection* msection) msection->ClearCodecs(); - // We need to have something here to fit the grammar, this seems safe. - msection->AddCodec("0", "PCMU", 8000, 1); + auto mediaType = msection->GetMediaType(); + switch (mediaType) { + case SdpMediaSection::kAudio: + msection->AddCodec("0", "PCMU", 8000, 1); + break; + case SdpMediaSection::kVideo: + msection->AddCodec("120", "VP8", 90000, 1); + break; + case SdpMediaSection::kApplication: + msection->AddDataChannel("5000", "rejected", 0); + break; + default: + // We need to have something here to fit the grammar, this seems safe + // and 19 is a reserved payload type which should not be used by anyone. + msection->AddCodec("19", "reserved", 8000, 1); + } } void @@ -288,10 +302,34 @@ SdpHelper::AddCandidateToSdp(Sdp* sdp, std::string candidate = candidateUntrimmed.substr(begin); - // TODO(bug 1095793): mid + // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-11#section-3.4.2.1 + // Implementations receiving an ICE Candidate object MUST use the MID if + // present, or the m= line index, if not (as it could have come from a + // non-JSEP endpoint). (bug 1095793) + SdpMediaSection* msection = 0; + if (!mid.empty()) { + // FindMsectionByMid could return nullptr + msection = FindMsectionByMid(*sdp, mid); + + // Check to make sure mid matches what we'd get by + // looking up the m= line using the level. (mjf) + std::string checkMid; + nsresult rv = GetMidFromLevel(*sdp, level, &checkMid); + if (NS_FAILED(rv)) { + return rv; + } + if (mid != checkMid) { + SDP_SET_ERROR("Mismatch between mid and level - \"" << mid + << "\" is not the mid for level " << level + << "; \"" << checkMid << "\" is"); + return NS_ERROR_INVALID_ARG; + } + } + if (!msection) { + msection = &(sdp->GetMediaSection(level)); + } - SdpMediaSection& msection = sdp->GetMediaSection(level); - SdpAttributeList& attrList = msection.GetAttributeList(); + SdpAttributeList& attrList = msection->GetAttributeList(); UniquePtr<SdpMultiStringAttribute> candidates; if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) { diff --git a/media/webrtc/signaling/src/sdp/SdpMediaSection.h b/media/webrtc/signaling/src/sdp/SdpMediaSection.h index ed70bd072d..6f120f3d63 100644 --- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h +++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h @@ -12,7 +12,7 @@ #include "signaling/src/sdp/SdpAttributeList.h" #include <string> #include <vector> -#include <iostream> +#include <sstream> namespace mozilla { diff --git a/media/webrtc/signaling/src/sdp/SipccSdp.cpp b/media/webrtc/signaling/src/sdp/SipccSdp.cpp index e769304e3c..c23fcf7e9d 100644 --- a/media/webrtc/signaling/src/sdp/SipccSdp.cpp +++ b/media/webrtc/signaling/src/sdp/SipccSdp.cpp @@ -74,8 +74,8 @@ bool SipccSdp::LoadOrigin(sdp_t* sdp, SdpErrorHolder& errorHolder) { std::string username = sdp_get_owner_username(sdp); - uint64_t sessId = strtoul(sdp_get_owner_sessionid(sdp), nullptr, 10); - uint64_t sessVer = strtoul(sdp_get_owner_version(sdp), nullptr, 10); + uint64_t sessId = strtoull(sdp_get_owner_sessionid(sdp), nullptr, 10); + uint64_t sessVer = strtoull(sdp_get_owner_version(sdp), nullptr, 10); sdp_nettype_e type = sdp_get_owner_network_type(sdp); if (type != SDP_NT_INTERNET) { diff --git a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp index 76c6522031..0ed209877b 100644 --- a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp +++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp @@ -106,8 +106,6 @@ SipccSdpAttributeList::LoadSimpleStrings(sdp_t* sdp, uint16_t level, errorHolder); LoadSimpleString(sdp, level, SDP_ATTR_LABEL, SdpAttribute::kLabelAttribute, errorHolder); - LoadSimpleString(sdp, level, SDP_ATTR_IDENTITY, - SdpAttribute::kIdentityAttribute, errorHolder); } void @@ -647,6 +645,16 @@ SipccSdpAttributeList::LoadMsidSemantics(sdp_t* sdp, uint16_t level, return true; } +void +SipccSdpAttributeList::LoadIdentity(sdp_t* sdp, uint16_t level) +{ + const char* val = sdp_attr_get_long_string(sdp, SDP_ATTR_IDENTITY, level, 0, 1); + if (val) { + SetAttribute(new SdpStringAttribute(SdpAttribute::kIdentityAttribute, + std::string(val))); + } +} + void SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level) { @@ -684,14 +692,7 @@ SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level) !!(fmtp->level_asymmetry_allowed); h264Parameters->packetization_mode = fmtp->packetization_mode; -// Copied from VcmSIPCCBinding -#ifdef _WIN32 - sscanf_s(fmtp->profile_level_id, "%x", - &h264Parameters->profile_level_id, sizeof(unsigned*)); -#else - sscanf(fmtp->profile_level_id, "%xu", - &h264Parameters->profile_level_id); -#endif + sscanf(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id); h264Parameters->max_mbps = fmtp->max_mbps; h264Parameters->max_fs = fmtp->max_fs; h264Parameters->max_cpb = fmtp->max_cpb; @@ -1003,6 +1004,8 @@ SipccSdpAttributeList::Load(sdp_t* sdp, uint16_t level, if (!LoadMsidSemantics(sdp, level, errorHolder)) { return false; } + + LoadIdentity(sdp, level); } else { sdp_media_e mtype = sdp_get_media_type(sdp, level); if (mtype == SDP_MEDIA_APPLICATION) { diff --git a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h index 0c092f68c2..0b8fc5153e 100644 --- a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h +++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h @@ -113,6 +113,7 @@ class SipccSdpAttributeList : public SdpAttributeList bool LoadMsidSemantics(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder); + void LoadIdentity(sdp_t* sdp, uint16_t level); void LoadFmtp(sdp_t* sdp, uint16_t level); void LoadMsids(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder); bool LoadRid(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder); diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp.h b/media/webrtc/signaling/src/sdp/sipcc/sdp.h index 9d744d910e..d8d3009b2a 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp.h +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp.h @@ -534,6 +534,7 @@ typedef enum sdp_srtp_crypto_suite_t_ { /* SDP Defines */ +#define SDP_MAX_LONG_STRING_LEN 4096 /* Max len for long SDP strings */ #define SDP_MAX_STRING_LEN 256 /* Max len for SDP string */ #define SDP_MAX_SHORT_STRING_LEN 12 /* Max len for a short SDP string */ #define SDP_MAX_PAYLOAD_TYPES 23 /* Max payload types in m= line */ @@ -1000,6 +1001,7 @@ typedef struct sdp_attr { tinybool boolean_val; uint32_t u32_val; char string_val[SDP_MAX_STRING_LEN+1]; + char *stringp; char ice_attr[SDP_MAX_STRING_LEN+1]; sdp_fmtp_t fmtp; sdp_sctpmap_t sctpmap; @@ -1275,6 +1277,8 @@ extern uint32_t sdp_attr_line_number(sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); extern const char *sdp_attr_get_simple_string(sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_long_string(sdp_t *sdp_p, + sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); extern uint32_t sdp_attr_get_simple_u32(sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); extern tinybool sdp_attr_get_simple_boolean(sdp_t *sdp_p, diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c index ab475fd73f..bf23c84e79 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c @@ -4900,13 +4900,11 @@ sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p, return (SDP_SUCCESS); } +static sdp_result_e sdp_parse_attr_line(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr, char *buf, size_t buf_len) { + sdp_result_e result; -sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p, - const char *ptr) -{ - sdp_result_e result; - - ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val, sizeof(attr_p->attr.string_val), "\r\n", &result); + (void)sdp_getnextstrtok(ptr, buf, buf_len, "\r\n", &result); if (result != SDP_SUCCESS) { sdp_parse_error(sdp_p, @@ -4918,12 +4916,42 @@ sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p, if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), - attr_p->attr.string_val); + buf); } return (SDP_SUCCESS); } } +sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + return sdp_parse_attr_line(sdp_p, attr_p, ptr, + attr_p->attr.string_val, + sizeof(attr_p->attr.string_val)); +} + +sdp_result_e sdp_parse_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char buffer[SDP_MAX_LONG_STRING_LEN]; + + result = sdp_parse_attr_line(sdp_p, attr_p, ptr, + buffer, sizeof(buffer)); + if (result == SDP_SUCCESS) { + attr_p->attr.stringp = cpr_strdup(buffer); + } + return result; +} + +sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name, + attr_p->attr.stringp); + return SDP_SUCCESS; +} + sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) @@ -5518,4 +5546,3 @@ sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p, attr_p->attr.ssrc.attribute); return SDP_SUCCESS; } - diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c index a95de2ad5e..f236b986a6 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c @@ -387,10 +387,11 @@ void sdp_free_attr (sdp_attr_t *attr_p) } } else if ((attr_p->type == SDP_ATTR_SDESCRIPTIONS) || (attr_p->type == SDP_ATTR_SRTP_CONTEXT)) { - SDP_FREE(attr_p->attr.srtp_context.session_parameters); + SDP_FREE(attr_p->attr.srtp_context.session_parameters); + } else if (attr_p->type == SDP_ATTR_IDENTITY) { + SDP_FREE(attr_p->attr.stringp); } - if (attr_p->type == SDP_ATTR_GROUP) { for (i = 0; i < attr_p->attr.stream_data.num_group_id; i++) { SDP_FREE(attr_p->attr.stream_data.group_ids[i]); @@ -681,7 +682,6 @@ static boolean sdp_attr_is_simple_string(sdp_attr_e attr_type) { (attr_type != SDP_ATTR_X_SIDOUT)&& (attr_type != SDP_ATTR_X_CONFID) && (attr_type != SDP_ATTR_LABEL) && - (attr_type != SDP_ATTR_IDENTITY) && (attr_type != SDP_ATTR_ICE_OPTIONS) && (attr_type != SDP_ATTR_IMAGEATTR) && (attr_type != SDP_ATTR_SIMULCAST) && @@ -736,6 +736,39 @@ const char *sdp_attr_get_simple_string (sdp_t *sdp_p, sdp_attr_e attr_type, } } +static boolean sdp_attr_is_long_string(sdp_attr_e attr_type) { + return attr_type == SDP_ATTR_IDENTITY; +} + +/* Identical in usage to sdp_attr_get_simple_string() */ +const char *sdp_attr_get_long_string (sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (!sdp_attr_is_long_string(attr_type)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + CSFLogError(logTag, "%s Attribute type is not a long string (%s)", + sdp_p->debug_str, sdp_get_attr_name(attr_type)); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.stringp); + } +} + static boolean sdp_attr_is_simple_u32(sdp_attr_e attr_type) { if ((attr_type != SDP_ATTR_EECID) && (attr_type != SDP_ATTR_PTIME) && diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c index 31e123179e..bca73182f3 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c @@ -181,7 +181,7 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] = {"extmap", sizeof("extmap"), sdp_parse_attr_extmap, sdp_build_attr_extmap}, {"identity", sizeof("identity"), - sdp_parse_attr_simple_string, sdp_build_attr_simple_string}, + sdp_parse_attr_long_line, sdp_build_attr_long_line}, {"msid", sizeof("msid"), sdp_parse_attr_msid, sdp_build_attr_msid}, {"msid-semantic", sizeof("msid-semantic"), diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h b/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h index 94c41a2efc..a98f4b119f 100644 --- a/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h +++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h @@ -240,6 +240,10 @@ extern sdp_result_e sdp_parse_attr_simple_flag ( extern sdp_result_e sdp_parse_attr_complete_line ( sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_parse_attr_long_line(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_long_line(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); /* sdp_attr_access.c */ extern void sdp_free_attr(sdp_attr_t *attr_p); diff --git a/media/webrtc/signaling/test/FakeMediaStreams.h b/media/webrtc/signaling/test/FakeMediaStreams.h index d326098f78..5ee5979b31 100644 --- a/media/webrtc/signaling/test/FakeMediaStreams.h +++ b/media/webrtc/signaling/test/FakeMediaStreams.h @@ -16,13 +16,14 @@ #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" #include "nsISupportsImpl.h" +#include "nsPIDOMWindow.h" #include "nsServiceManagerUtils.h" // #includes from MediaStream.h #include "mozilla/Mutex.h" #include "AudioSegment.h" #include "MediaSegment.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "nsTArray.h" #include "nsIRunnable.h" #include "nsISupportsImpl.h" @@ -447,7 +448,9 @@ class Fake_DOMMediaStream : public nsISupports NS_DECL_THREADSAFE_ISUPPORTS static already_AddRefed<Fake_DOMMediaStream> - CreateSourceStream(nsIDOMWindow* aWindow, mozilla::MediaStreamGraph* aGraph, uint32_t aHintContents = 0) { + CreateSourceStreamAsInput(nsPIDOMWindow* aWindow, + mozilla::MediaStreamGraph* aGraph, + uint32_t aHintContents = 0) { Fake_SourceMediaStream *source = new Fake_SourceMediaStream(); RefPtr<Fake_DOMMediaStream> ds = new Fake_DOMMediaStream(source); diff --git a/media/webrtc/signaling/test/FakePCObserver.h b/media/webrtc/signaling/test/FakePCObserver.h index f56973b914..bcad670717 100644 --- a/media/webrtc/signaling/test/FakePCObserver.h +++ b/media/webrtc/signaling/test/FakePCObserver.h @@ -14,7 +14,7 @@ #include "mozilla/Mutex.h" #include "AudioSegment.h" #include "MediaSegment.h" -#include "StreamBuffer.h" +#include "StreamTracks.h" #include "nsTArray.h" #include "nsIRunnable.h" #include "nsISupportsImpl.h" diff --git a/media/webrtc/signaling/test/jsep_session_unittest.cpp b/media/webrtc/signaling/test/jsep_session_unittest.cpp index 7db311a0e0..fabab2af24 100644 --- a/media/webrtc/signaling/test/jsep_session_unittest.cpp +++ b/media/webrtc/signaling/test/jsep_session_unittest.cpp @@ -12,6 +12,7 @@ #include "ssl.h" #include "mozilla/RefPtr.h" +#include "mozilla/Tuple.h" #define GTEST_HAS_RTTI 0 #include "gtest/gtest.h" @@ -620,10 +621,9 @@ class JsepSessionTest : public JsepSessionTestBase, session.AddLocalIceCandidate(kAEqualsCandidate + candidate.str(), level, &mid, &skipped); if (!skipped) { - // TODO (bug 1095793): Need to add mid to mCandidatesToTrickle mCandidatesToTrickle.push_back( - std::pair<uint16_t, std::string>( - level, kAEqualsCandidate + candidate.str())); + Tuple<Level, Mid, Candidate>( + level, mid, kAEqualsCandidate + candidate.str())); candidates.push_back(candidate.str()); } } @@ -665,10 +665,12 @@ class JsepSessionTest : public JsepSessionTestBase, void Trickle(JsepSession& session) { - for (const auto& levelAndCandidate : mCandidatesToTrickle) { - session.AddRemoteIceCandidate(levelAndCandidate.second, - "", - levelAndCandidate.first); + for (const auto& levelMidAndCandidate : mCandidatesToTrickle) { + Level level; + Mid mid; + Candidate candidate; + Tie(level, mid, candidate) = levelMidAndCandidate; + session.AddRemoteIceCandidate(candidate, mid, level); } mCandidatesToTrickle.clear(); } @@ -779,6 +781,7 @@ class JsepSessionTest : public JsepSessionTestBase, private: typedef size_t Level; + typedef std::string Mid; typedef std::string Candidate; typedef std::string Address; typedef uint16_t Port; @@ -790,8 +793,8 @@ class JsepSessionTest : public JsepSessionTestBase, std::map<Level, std::map<ComponentType, std::vector<Candidate>>> mCandidates; - // Level/candidate pairs that need to be trickled - std::vector<std::pair<Level, Candidate>> mCandidatesToTrickle; + // Level/mid/candidate tuples that need to be trickled + std::vector<Tuple<Level, Mid, Candidate>> mCandidatesToTrickle; }; // For streaming parse errors @@ -859,6 +862,43 @@ class JsepSessionTest : public JsepSessionTestBase, (*sdp) = parsed->ToString(); } + void + ValidateDisabledMSection(const SdpMediaSection* msection) + { + ASSERT_EQ(1U, msection->GetFormats().size()); + // Maybe validate that no attributes are present except rtpmap and + // inactive? How? + ASSERT_EQ(SdpDirectionAttribute::kInactive, + msection->GetDirectionAttribute().mValue); + if (msection->GetMediaType() == SdpMediaSection::kAudio) { + ASSERT_EQ("0", msection->GetFormats()[0]); + const SdpRtpmapAttributeList::Rtpmap* rtpmap(msection->FindRtpmap("0")); + ASSERT_TRUE(rtpmap); + ASSERT_EQ("0", rtpmap->pt); + ASSERT_EQ("PCMU", rtpmap->name); + } else if (msection->GetMediaType() == SdpMediaSection::kVideo) { + ASSERT_EQ("120", msection->GetFormats()[0]); + const SdpRtpmapAttributeList::Rtpmap* rtpmap(msection->FindRtpmap("120")); + ASSERT_TRUE(rtpmap); + ASSERT_EQ("120", rtpmap->pt); + ASSERT_EQ("VP8", rtpmap->name); + } else if (msection->GetMediaType() == SdpMediaSection::kApplication) { + ASSERT_EQ("5000", msection->GetFormats()[0]); + const SdpSctpmapAttributeList::Sctpmap* sctpmap(msection->FindSctpmap("5000")); + ASSERT_TRUE(sctpmap); + ASSERT_EQ("5000", sctpmap->pt); + ASSERT_EQ("rejected", sctpmap->name); + ASSERT_EQ(0U, sctpmap->streams); + } else { + // Not that we would have any test which tests this... + ASSERT_EQ("19", msection->GetFormats()[0]); + const SdpRtpmapAttributeList::Rtpmap* rtpmap(msection->FindRtpmap("19")); + ASSERT_TRUE(rtpmap); + ASSERT_EQ("19", rtpmap->pt); + ASSERT_EQ("reserved", rtpmap->name); + } + } + void DumpTrack(const JsepTrack& track) { @@ -925,10 +965,7 @@ class JsepSessionTest : public JsepSessionTestBase, } if (msection.GetPort() == 0) { - ASSERT_EQ(SdpDirectionAttribute::kInactive, - msection.GetDirectionAttribute().mValue); - // Maybe validate that no attributes are present except rtpmap and - // inactive? + ValidateDisabledMSection(&msection); continue; } const SdpAttributeList& attrs = msection.GetAttributeList(); diff --git a/media/webrtc/signaling/test/sdp_unittests.cpp b/media/webrtc/signaling/test/sdp_unittests.cpp index eece651232..db049ec0c2 100644 --- a/media/webrtc/signaling/test/sdp_unittests.cpp +++ b/media/webrtc/signaling/test/sdp_unittests.cpp @@ -271,7 +271,7 @@ class SdpTest : public ::testing::Test { static const std::string kVideoSdp = "v=0\r\n" - "o=- 137331303 2 IN IP4 127.0.0.1\r\n" + "o=- 4294967296 2 IN IP4 127.0.0.1\r\n" "s=SIP Call\r\n" "c=IN IP4 198.51.100.7\r\n" "t=0 0\r\n" @@ -819,7 +819,7 @@ TEST_F(SdpTest, addFmtpMaxFsFr) { static const std::string kBrokenFmtp = "v=0\r\n" - "o=- 137331303 2 IN IP4 127.0.0.1\r\n" + "o=- 4294967296 2 IN IP4 127.0.0.1\r\n" "s=SIP Call\r\n" "t=0 0\r\n" "m=video 56436 RTP/SAVPF 120\r\n" @@ -852,7 +852,7 @@ TEST_F(SdpTest, addIceLite) { TEST_F(SdpTest, parseIceLite) { std::string sdp = "v=0\r\n" - "o=- 137331303 2 IN IP4 127.0.0.1\r\n" + "o=- 4294967296 2 IN IP4 127.0.0.1\r\n" "s=SIP Call\r\n" "t=0 0\r\n" "a=ice-lite\r\n"; @@ -1012,7 +1012,7 @@ TEST_P(NewSdpTest, CheckOriginGetUsername) { TEST_P(NewSdpTest, CheckOriginGetSessionId) { ParseSdp(kVideoSdp); - ASSERT_EQ(137331303U, mSdp->GetOrigin().GetSessionId()) + ASSERT_EQ(4294967296U, mSdp->GetOrigin().GetSessionId()) << "Wrong session id in origin"; } @@ -1042,7 +1042,7 @@ TEST_P(NewSdpTest, CheckGetMissingBandwidth) { TEST_P(NewSdpTest, CheckGetBandwidth) { ParseSdp("v=0" CRLF - "o=- 137331303 2 IN IP4 127.0.0.1" CRLF + "o=- 4294967296 2 IN IP4 127.0.0.1" CRLF "s=SIP Call" CRLF "c=IN IP4 198.51.100.7" CRLF "b=CT:5000" CRLF @@ -1110,7 +1110,7 @@ TEST_P(NewSdpTest, CheckMediaSectionGetMissingBandwidth) { TEST_P(NewSdpTest, CheckMediaSectionGetBandwidth) { ParseSdp("v=0\r\n" - "o=- 137331303 2 IN IP4 127.0.0.1\r\n" + "o=- 4294967296 2 IN IP4 127.0.0.1\r\n" "c=IN IP4 198.51.100.7\r\n" "t=0 0\r\n" "m=video 56436 RTP/SAVPF 120\r\n" @@ -1120,6 +1120,12 @@ TEST_P(NewSdpTest, CheckMediaSectionGetBandwidth) { << "Wrong bandwidth in media section"; } +// Define a string that is 258 characters long. We use a long string here so +// that we can test that we are able to parse and handle a string longer than +// the default maximum length of 256 in sipcc. +#define ID_A "1234567890abcdef" +#define ID_B ID_A ID_A ID_A ID_A +#define LONG_IDENTITY ID_B ID_B ID_B ID_B "xx" // SDP from a basic A/V apprtc call FFX/FFX const std::string kBasicAudioVideoOffer = @@ -1135,7 +1141,7 @@ const std::string kBasicAudioVideoOffer = "a=msid-semantic:WMS stream streama" CRLF "a=msid-semantic:foo stream" CRLF "a=fingerprint:sha-256 DF:2E:AC:8A:FD:0A:8E:99:BF:5D:E8:3C:E7:FA:FB:08:3B:3C:54:1D:D7:D4:05:77:A0:72:9B:14:08:6D:0F:4C" CRLF -"a=identity:blahblahblah foo;bar" CRLF +"a=identity:" LONG_IDENTITY CRLF "a=group:BUNDLE first second" CRLF "a=group:BUNDLE third" CRLF "a=group:LS first third" CRLF @@ -1330,7 +1336,7 @@ TEST_P(NewSdpTest, CheckIdentity) { ASSERT_TRUE(mSdp->GetAttributeList().HasAttribute( SdpAttribute::kIdentityAttribute)); auto identity = mSdp->GetAttributeList().GetIdentity(); - ASSERT_EQ("blahblahblah", identity) << "Wrong identity assertion"; + ASSERT_EQ(LONG_IDENTITY, identity) << "Wrong identity assertion"; } TEST_P(NewSdpTest, CheckNumberOfMediaSections) { diff --git a/media/webrtc/trunk/webrtc/build/common.gypi b/media/webrtc/trunk/webrtc/build/common.gypi index 4e46b60d43..02aae44375 100644 --- a/media/webrtc/trunk/webrtc/build/common.gypi +++ b/media/webrtc/trunk/webrtc/build/common.gypi @@ -320,7 +320,7 @@ ['arm_neon==1', { 'defines': ['WEBRTC_ARCH_ARM_NEON',], }], - ['arm_neon==0 and (OS=="android" or moz_widget_toolkit_gonk==1)', { + ['arm_neon==0 and arm_neon_optional==1', { 'defines': ['WEBRTC_DETECT_ARM_NEON',], }], ], diff --git a/media/webrtc/trunk/webrtc/modules/audio_coding/neteq/audio_classifier.cc b/media/webrtc/trunk/webrtc/modules/audio_coding/neteq/audio_classifier.cc index f3e3fb2f34..5356774fe3 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_coding/neteq/audio_classifier.cc +++ b/media/webrtc/trunk/webrtc/modules/audio_coding/neteq/audio_classifier.cc @@ -30,9 +30,9 @@ AudioClassifier::AudioClassifier() // to be deleted. celt_mode_(opus_custom_mode_create(kDefaultSampleRateHz, kDefaultFrameSizeSamples, - NULL)), - analysis_state_() { + NULL)) { assert(celt_mode_); + tonality_analysis_init(&analysis_state_); } AudioClassifier::~AudioClassifier() {} diff --git a/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc b/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc index e2ffefe2f1..6a851dac69 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc +++ b/media/webrtc/trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc @@ -572,6 +572,9 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() Terminate(); + // Recording thread should be shut down before this! + assert(_hRecThread == NULL); + // The IMMDeviceEnumerator is created during construction. Must release // it here and not in Terminate() since we don't recreate it in Init(). SAFE_RELEASE(_ptrEnumerator); diff --git a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c index c9db853702..6c624e75a5 100644 --- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c +++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c @@ -1492,6 +1492,9 @@ AecCore* WebRtcAec_CreateAec() { return NULL; } + // set the mem with 0 in order to prevent garbage data + memset(aec, 0, sizeof(*aec)); + aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float)); if (!aec->nearFrBuf) { WebRtcAec_FreeAec(aec); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc index ae92a5bcd9..b008ff900b 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_device_info.cc @@ -96,6 +96,21 @@ DesktopApplication::DesktopApplication() { } DesktopApplication::~DesktopApplication() { + if (processPathNameUTF8_) { + delete [] processPathNameUTF8_; + } + + if (applicationNameUTF8_) { + delete [] applicationNameUTF8_; + } + + if (processUniqueIdUTF8_) { + delete [] processUniqueIdUTF8_; + } + + processPathNameUTF8_= NULL; + applicationNameUTF8_= NULL; + processUniqueIdUTF8_= NULL; } void DesktopApplication::setProcessId(const ProcessId processId) { diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc index 02813082da..3d4a1ea13f 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc @@ -5,6 +5,7 @@ #include "webrtc/modules/desktop_capture/win/desktop_device_info_win.h" #include "webrtc/modules/desktop_capture/win/win_shared.h" #include <stdio.h> +#include <VersionHelpers.h> // Duplicating declaration so that it always resolves in decltype use // typedef BOOL (WINAPI *QueryFullProcessImageNameProc)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize); @@ -68,6 +69,17 @@ void DesktopDeviceInfoWin::InitializeApplicationList() { continue; } + // Win8 introduced "Modern Apps" whose associated window is + // non-shareable. We want to filter them out. + const int classLength = 256; + WCHAR class_name[classLength] = {0}; + GetClassName(hWnd, class_name, classLength); + if (IsWindows8OrGreater() && + (wcscmp(class_name, L"ApplicationFrameWindow") == 0 || + wcscmp(class_name, L"Windows.UI.Core.CoreWindow") == 0)) { + continue; + } + // filter out already-seen processes, after updating the window count DesktopApplicationList::iterator itr = desktop_application_list_.find(dwProcessId); if (itr != desktop_application_list_.end()) { diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm index daa9fc7858..54c8c79276 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm @@ -102,6 +102,18 @@ explicit WindowCapturerMac( CFNumberRef window_layer = reinterpret_cast<CFNumberRef>( CFDictionaryGetValue(window, kCGWindowLayer)); if (window_title && window_id && window_layer) { + //Skip windows of zero area + CFDictionaryRef bounds_ref = reinterpret_cast<CFDictionaryRef>( + CFDictionaryGetValue(window,kCGWindowBounds)); + CGRect bounds_rect; + if(!(bounds_ref) || + !(CGRectMakeWithDictionaryRepresentation(bounds_ref,&bounds_rect))){ + continue; + } + bounds_rect = CGRectStandardize(bounds_rect); + if((bounds_rect.size.width <= 0) || (bounds_rect.size.height <= 0)){ + continue; + } // Skip windows with layer=0 (menu, dock). int layer; CFNumberGetValue(window_layer, kCFNumberIntType, &layer); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc index 22f14a85a7..132e2a373f 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc @@ -17,6 +17,7 @@ #include "webrtc/modules/desktop_capture/desktop_frame_win.h" #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" #include "webrtc/system_wrappers/interface/logging.h" +#include <VersionHelpers.h> namespace webrtc { @@ -49,6 +50,14 @@ BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0) return TRUE; + // Win8 introduced "Modern Apps" whose associated window is + // non-shareable. We want to filter them out. + if (IsWindows8OrGreater() && + (wcscmp(class_name, L"ApplicationFrameWindow") == 0 || + wcscmp(class_name, L"Windows.UI.Core.CoreWindow") == 0)) { + return TRUE; + } + WindowCapturer::Window window; window.id = reinterpret_cast<WindowCapturer::WindowId>(hwnd); @@ -61,6 +70,12 @@ BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { // Skip windows when we failed to convert the title or it is empty. if (window.title.empty()) return TRUE; + // Skip windows of zero visible area, except IconicWindows + RECT bounds; + if(GetClientRect(hwnd,&bounds) && !IsIconic(hwnd) + && IsRectEmpty(&bounds)){ + return TRUE; + } list->push_back(window); diff --git a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc index a7ba0c1d41..f78051b2b9 100644 --- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc +++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc @@ -134,6 +134,16 @@ bool WindowCapturerLinux::GetWindowList(WindowList* windows) { if (app_window && !IsDesktopElement(app_window)) { Window w; w.id = app_window; + + XWindowAttributes window_attr; + if(!XGetWindowAttributes(display(),w.id,&window_attr)){ + LOG(LS_ERROR)<<"Bad request for attributes for window ID:"<<w.id; + continue; + } + if((window_attr.width <= 0) || (window_attr.height <=0)){ + continue; + } + if (GetWindowTitle(app_window, &w.title)) result.push_back(w); } diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.cc b/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.cc index 693e2b26ee..8fc1bbdace 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.cc +++ b/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.cc @@ -15,6 +15,7 @@ #include <sstream> #include <vector> +#include "webrtc/modules/utility/interface/helpers_android.h" #include "webrtc/modules/video_capture/android/video_capture_android.h" #include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/ref_count.h" @@ -60,10 +61,11 @@ struct AndroidCameraInfo { } }; -// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable -// thereafter. +// Camera info; populated during DeviceInfoAndroid::Refresh() static std::vector<AndroidCameraInfo>* g_camera_info = NULL; +static JavaVM* g_jvm = NULL; + // Set |*index| to the index of |name| in g_camera_info or return false if no // match found. static bool FindCameraIndexByName(const std::string& name, size_t* index) { @@ -86,7 +88,7 @@ static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) { } // static -void DeviceInfoAndroid::Initialize(JNIEnv* jni) { +void DeviceInfoAndroid::Initialize(JavaVM* javaVM) { // TODO(henrike): this "if" would make a lot more sense as an assert, but // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to @@ -96,6 +98,17 @@ void DeviceInfoAndroid::Initialize(JNIEnv* jni) { if (g_camera_info) return; + g_jvm = javaVM; +} + +void DeviceInfoAndroid::BuildDeviceList() { + if (!g_jvm) { + return; + } + + AttachThreadScoped ats(g_jvm); + JNIEnv* jni = ats.env(); + g_camera_info = new std::vector<AndroidCameraInfo>(); jclass j_info_class = jsjni_GetGlobalClassRef("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid"); @@ -179,6 +192,13 @@ void DeviceInfoAndroid::DeInitialize() { } } +int32_t DeviceInfoAndroid::Refresh() { + if (!g_camera_info || g_camera_info->size() == 0) { + DeviceInfoAndroid::BuildDeviceList(); + } + return 0; +} + VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo( const int32_t id) { return new videocapturemodule::DeviceInfoAndroid(id); diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.h b/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.h index c52abb8d1f..72c0acc4f5 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.h +++ b/media/webrtc/trunk/webrtc/modules/video_capture/android/device_info_android.h @@ -26,7 +26,7 @@ namespace videocapturemodule class DeviceInfoAndroid : public DeviceInfoImpl { public: - static void Initialize(JNIEnv* env); + static void Initialize(JavaVM* javaVM); static void DeInitialize(); DeviceInfoAndroid(int32_t id); @@ -38,6 +38,7 @@ class DeviceInfoAndroid : public DeviceInfoImpl { virtual int32_t Init(); virtual uint32_t NumberOfDevices(); + virtual int32_t Refresh(); virtual int32_t GetDeviceName( uint32_t deviceNumber, char* deviceNameUTF8, @@ -66,6 +67,7 @@ class DeviceInfoAndroid : public DeviceInfoImpl { private: enum { kExpectedCaptureDelay = 190}; + static void BuildDeviceList(); }; } // namespace videocapturemodule diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java b/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java index eff139538f..22a3dce98c 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java +++ b/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java @@ -13,13 +13,17 @@ import java.util.ArrayList; import java.util.List; +import android.Manifest; +import android.app.Activity; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; import android.hardware.Camera; import android.util.Log; +import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.annotation.WebRTCJNITarget; +import org.mozilla.gecko.permissions.Permissions; public class VideoCaptureDeviceInfoAndroid { private final static String TAG = "WEBRTC-JC"; @@ -71,6 +75,17 @@ public static List<int[]> getFpsRangesRobust(Camera.Parameters parameters) { // marked "private" as it is only called by native code. @WebRTCJNITarget private static CaptureCapabilityAndroid[] getDeviceInfo() { + final boolean hasPermissions = Permissions.waitFor( + (Activity) GeckoAppShell.getContext(), Manifest.permission.CAMERA); + + if (hasPermissions) { + return createDeviceList(); + } else { + return new CaptureCapabilityAndroid[0]; + } + } + + private static CaptureCapabilityAndroid[] createDeviceList() { ArrayList<CaptureCapabilityAndroid> allDevices = new ArrayList<CaptureCapabilityAndroid>(); int numCameras = 1; if (android.os.Build.VERSION.SDK_INT >= 9) { @@ -163,5 +178,4 @@ private static CaptureCapabilityAndroid[] getDeviceInfo() { } return allDevices.toArray(new CaptureCapabilityAndroid[0]); } - } diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/android/video_capture_android.cc b/media/webrtc/trunk/webrtc/modules/video_capture/android/video_capture_android.cc index cab83908ba..e03493f247 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/android/video_capture_android.cc +++ b/media/webrtc/trunk/webrtc/modules/video_capture/android/video_capture_android.cc @@ -63,7 +63,7 @@ int32_t SetCaptureAndroidVM(JavaVM* javaVM) { g_context = jsjni_GetGlobalContextRef(); - videocapturemodule::DeviceInfoAndroid::Initialize(ats.env()); + videocapturemodule::DeviceInfoAndroid::Initialize(g_jvm); g_java_capturer_class = jsjni_GetGlobalClassRef("org/webrtc/videoengine/VideoCaptureAndroid"); diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc index 5f714d5ead..f86323960b 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -738,8 +738,8 @@ int VP8EncoderImpl::Encode( const I420VideoFrame& input_image = use_quality_scaler ? quality_scaler_.GetScaledFrame(frame) : frame; - if (use_quality_scaler && (input_image.width() != codec_.width || - input_image.height() != codec_.height)) { + if (input_image.width() != codec_.width || + input_image.height() != codec_.height) { int ret = UpdateCodecFrameSize(input_image); if (ret < 0) return ret; diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc index 850403e60e..dcfd10113b 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -153,6 +153,7 @@ bool VP9EncoderImpl::SetSvcRates() { float rate_ratio[VPX_MAX_LAYERS] = {0}; float total = 0; +#ifdef LIBVPX_SVC for (i = 0; i < num_spatial_layers_; ++i) { if (svc_internal_.svc_params.scaling_factor_num[i] <= 0 || svc_internal_.svc_params.scaling_factor_den[i] <= 0) { @@ -164,6 +165,10 @@ bool VP9EncoderImpl::SetSvcRates() { svc_internal_.svc_params.scaling_factor_den[i]; total += rate_ratio[i]; } +#else + rate_ratio[0] = 1; + total = 1; +#endif for (i = 0; i < num_spatial_layers_; ++i) { config_->ss_target_bitrate[i] = static_cast<unsigned int>( @@ -397,8 +402,8 @@ int VP9EncoderImpl::NumberOfThreads(int width, int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { config_->ss_number_layers = num_spatial_layers_; - if (ExplicitlyConfiguredSpatialLayers()) { #ifdef LIBVPX_SVC + if (ExplicitlyConfiguredSpatialLayers()) { for (int i = 0; i < num_spatial_layers_; ++i) { const auto& layer = codec_.spatialLayers[i]; svc_internal_.svc_params.max_quantizers[i] = config_->rc_max_quantizer; @@ -406,7 +411,6 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { svc_internal_.svc_params.scaling_factor_num[i] = layer.scaling_factor_num; svc_internal_.svc_params.scaling_factor_den[i] = layer.scaling_factor_den; } -#endif } else { int scaling_factor_num = 256; for (int i = num_spatial_layers_ - 1; i >= 0; --i) { @@ -419,6 +423,7 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { scaling_factor_num /= 2; } } +#endif if (!SetSvcRates()) { return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; @@ -433,6 +438,7 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { vpx_codec_control(encoder_, VP9E_SET_AQ_MODE, inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0); +#ifdef LIBVPX_SVC vpx_codec_control( encoder_, VP9E_SET_SVC, (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) ? 1 : 0); @@ -440,6 +446,8 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS, &svc_internal_.svc_params); } +#endif + // Register callback for getting each spatial layer. vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = { VP9EncoderImpl::EncoderOutputCodedPacketCallback, (void*)(this)}; @@ -645,6 +653,7 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, vp9_info->temporal_up_switch = gof_.temporal_up_switch[vp9_info->gof_idx]; } +#ifdef LIBVPX_SVC if (vp9_info->ss_data_available) { vp9_info->spatial_layer_resolution_present = true; for (size_t i = 0; i < vp9_info->num_spatial_layers; ++i) { @@ -659,6 +668,7 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, vp9_info->gof.CopyGofInfoVP9(gof_); } } +#endif } int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h index 49e756ad43..c3ff63b55d 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h +++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h @@ -15,7 +15,9 @@ #include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h" #include "webrtc/modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h" +#ifdef LIBVPX_SVC #include "vpx/svc_context.h" +#endif #include "vpx/vpx_decoder.h" #include "vpx/vpx_encoder.h" @@ -109,7 +111,9 @@ class VP9EncoderImpl : public VP9Encoder { vpx_codec_ctx_t* encoder_; vpx_codec_enc_cfg_t* config_; vpx_image_t* raw_; +#ifdef LIBVPX_SVC SvcInternal_t svc_internal_; +#endif const I420VideoFrame* input_image_; GofInfoVP9 gof_; // Contains each frame's temporal information for // non-flexible mode. diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/codec_database.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/codec_database.cc index 2c268185a2..9a32fd27ed 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/codec_database.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/codec_database.cc @@ -614,7 +614,8 @@ bool VCMCodecDataBase::SupportsRenderScheduling() const { const VCMExtDecoderMapItem* ext_item = FindExternalDecoderItem( receive_codec_.plType); if (ext_item == nullptr) { - LOG(LS_ERROR) << "Unknown payload type: " << receive_codec_.plType; + // Assume the receive_codec_ is internal and as an internal codec + // by definition it supports scheduling. return true; } return ext_item->internal_render_timing; diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/generic_encoder.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/generic_encoder.cc index e8f05c7fc2..1cebd4a842 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/generic_encoder.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/generic_encoder.cc @@ -113,6 +113,7 @@ int32_t VCMGenericEncoder::Release() rtc::CritScope lock(&rates_lock_); bit_rate_ = 0; frame_rate_ = 0; + encoder_->RegisterEncodeCompleteCallback(nullptr); vcm_encoded_frame_callback_ = nullptr; } diff --git a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/video_sender.cc b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/video_sender.cc index ea219dbfcd..3b7463cc33 100644 --- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/video_sender.cc +++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/video_sender.cc @@ -373,7 +373,9 @@ int32_t VideoSender::AddVideoFrame(const I420VideoFrame& videoFrame, if (_mediaOpt.DropFrame()) { return VCM_OK; } + _mediaOpt.UpdateContentData(contentMetrics); +#ifdef VERIFY_FRAME_SIZE_VS_DATABASE // TODO(pbos): Make sure setting send codec is synchronized with video // processing so frame size always matches. if (!_codecDataBase.MatchesCurrentResolution(videoFrame.width(), @@ -381,9 +383,11 @@ int32_t VideoSender::AddVideoFrame(const I420VideoFrame& videoFrame, LOG(LS_ERROR) << "Incoming frame doesn't match set resolution. Dropping."; return VCM_PARAMETER_ERROR; } +#endif int32_t ret = _encoder->Encode(videoFrame, codecSpecificInfo, _nextFrameTypes); recorder_->Add(videoFrame); + if (ret < 0) { LOG(LS_ERROR) << "Failed to encode frame. Error code: " << ret; return ret; diff --git a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement.cc b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement.cc index aaa3a46225..f4812016ff 100644 --- a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement.cc +++ b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement.cc @@ -17,6 +17,11 @@ namespace webrtc { namespace VideoProcessing { int32_t ColorEnhancement(I420VideoFrame* frame) { + // MOZILLA: we don't use this function and by stubbing it out we can avoid + // storing colorTable[], which is 64 KiB of static data. + assert(false); + return VPM_GENERAL_ERROR; +#if 0 assert(frame); // Pointers to U and V color pixels. uint8_t* ptr_u; @@ -44,6 +49,7 @@ int32_t ColorEnhancement(I420VideoFrame* frame) { ptr_v++; } return VPM_OK; +#endif } } // namespace VideoProcessing diff --git a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement_private.h b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement_private.h index e5789105a8..d36390ec83 100644 --- a/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement_private.h +++ b/media/webrtc/trunk/webrtc/modules/video_processing/main/source/color_enhancement_private.h @@ -16,6 +16,9 @@ namespace webrtc { namespace VideoProcessing { +// MOZILLA: comment this out because it's 64 KiB of static data and we don't +// used the function it's used by. +#if 0 // Table created with Matlab script createTable.m // Usage: // Umod=colorTable[U][V] @@ -278,6 +281,7 @@ static const uint8_t colorTable[256][256] = { {254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254}, {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} }; +#endif } // namespace VideoProcessing diff --git a/media/webrtc/trunk/webrtc/voice_engine/index.html b/media/webrtc/trunk/webrtc/voice_engine/index.html deleted file mode 100644 index 0c50c07828..0000000000 --- a/media/webrtc/trunk/webrtc/voice_engine/index.html +++ /dev/null @@ -1,11 +0,0 @@ -<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="it"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="iT8XClq4+XYjXr36xn/8ug==">(function(){window.google={kEI:'yjHrXpjSFpiQ1fAP9te3qA4',kEXPI:'0,18167,183956,3,4,32,1151585,5662,731,223,5104,207,3204,10,1226,364,1119,380,155,421,241,383,246,5,1354,196,790,176,532,54,1796,334,137,97,185,117,3,726,163,1122460,1197736,413,90,302723,26255,1344,12383,4855,32692,15247,867,28684,9188,8384,4858,1362,3471,5820,3026,4741,11033,1808,4020,978,2981,1,4949,5297,2054,920,873,1217,2975,6430,11306,3222,4517,2777,919,2277,8,2796,885,708,1279,390,1822,530,149,1103,840,517,1466,56,4222,36,109,203,1137,2,2063,606,1839,184,1777,520,1946,2230,93,328,1284,16,2927,2247,473,1339,748,1039,3227,2845,7,6068,6286,4455,641,600,1849,2459,1226,1742,3654,1275,108,1456,1951,908,2,941,552,511,1551,881,934,582,5419,2891,1337,1098,3,576,970,865,3,375,3540,707,148,189,2837,476,1227,1261,28,2224,3989,83,913,105,643,4,1337,191,17,925,353,1009,1236,271,874,405,42,1798,20,177,68,2181,841,917,10,42,73,4,1339,1424,460,43,1299,213,499,641,92,482,16,1593,743,1,254,138,285,709,608,271,86,3,509,28,216,740,237,1024,100,426,160,1266,71,91,745,90,1189,461,37,602,1144,54,521,204,5,27,8,246,1407,364,672,981,987,2,177,98,248,139,259,2,2,181,3,62,820,198,385,4,1396,801,136,2,5800786,1873,1503,8798540,549,333,444,1,2,80,1,900,896,1,8,1,2,2551,1,748,141,59,742,557,1,4265,1,1,1,1,137,1,879,9,305,1351,99,1232,41,16,4,1,28,3502971,17238640,3220021',kBL:'ebyt'};google.sn='webhp';google.kHL='it';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var c;a&&(!a.getAttribute||!(c=a.getAttribute("eid")));)a=a.parentNode;return c||google.kEI};google.getLEI=function(a){for(var c=null;a&&(!a.getAttribute||!(c=a.getAttribute("leid")));)a=a.parentNode;return c};google.ml=function(){return null};google.time=function(){return Date.now()};google.log=function(a,c,b,d,g){if(b=google.logUrl(a,c,b,d,g)){a=new Image;var e=google.lc,f=google.li;e[f]=a;a.onerror=a.onload=a.onabort=function(){delete e[f]};google.vel&&google.vel.lu&&google.vel.lu(b);a.src=b;google.li=f+1}};google.logUrl=function(a,c,b,d,g){var e="",f=google.ls||"";b||-1!=c.search("&ei=")||(e="&ei="+google.getEI(d),-1==c.search("&lei=")&&(d=google.getLEI(d))&&(e+="&lei="+d));d="";!b&&google.cshid&&-1==c.search("&cshid=")&&"slh"!=a&&(d="&cshid="+google.cshid);b=b||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+c+e+f+"&zx="+google.time()+d;/^http:/i.test(b)&&"https:"==window.location.protocol&&(google.ml(Error("a"),!1,{src:b,glmm:1}),b="");return b};}).call(this);(function(){google.y={};google.x=function(a,b){if(a)var c=a.id;else{do c=Math.random();while(google.y[c])}google.y[c]=[a,b];return!1};google.lm=[];google.plm=function(a){google.lm.push.apply(google.lm,a)};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};}).call(this);google.f={};(function(){ -document.documentElement.addEventListener("submit",function(b){var a;if(a=b.target){var c=a.getAttribute("data-submitfalse");a="1"==c||"q"==c&&!a.elements.q.value?!0:!1}else a=!1;a&&(b.preventDefault(),b.stopPropagation())},!0);document.documentElement.addEventListener("click",function(b){var a;a:{for(a=b.target;a&&a!=document.documentElement;a=a.parentElement)if("A"==a.tagName){a="1"==a.getAttribute("data-nohref");break a}a=!1}a&&b.preventDefault()},!0);}).call(this); -var a=window.location,b=a.href.indexOf("#");if(0<=b){var c=a.href.substring(b+1);/(^|&)q=/.test(c)&&-1==c.indexOf("#")&&a.replace("/search?"+c.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h")};</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important} -</style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}body{background:#fff;color:#000}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}</style><script nonce="iT8XClq4+XYjXr36xn/8ug=="></script></head><body bgcolor="#fff"><script nonce="iT8XClq4+XYjXr36xn/8ug==">(function(){var src='/images/nav_logo229.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;} -if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();} -} -})();</script><div id="mngb"> <div id=gbar><nobr><b class=gb1>Ricerca</b> <a class=gb1 href="https://www.google.it/imghp?hl=it&tab=wi">Immagini</a> <a class=gb1 href="https://maps.google.it/maps?hl=it&tab=wl">Maps</a> <a class=gb1 href="https://play.google.com/?hl=it&tab=w8">Play</a> <a class=gb1 href="https://www.youtube.com/?gl=IT&tab=w1">YouTube</a> <a class=gb1 href="https://news.google.it/nwshp?hl=it&tab=wn">News</a> <a class=gb1 href="https://mail.google.com/mail/?tab=wm">Gmail</a> <a class=gb1 href="https://drive.google.com/?tab=wo">Drive</a> <a class=gb1 style="text-decoration:none" href="https://www.google.it/intl/it/about/products?tab=wh"><u>Altro</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="http://www.google.it/history/optout?hl=it" class=gb4>Cronologia web</a> | <a href="/preferences?hl=it" class=gb4>Impostazioni</a> | <a target=_top id=gb_70 href="https://accounts.google.com/ServiceLogin?hl=it&passive=true&continue=https://www.google.com/" class=gb4>Accedi</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div> </div><center><br clear="all" id="lgpd"><div id="lga"><img alt="Google" height="92" src="/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png" style="padding:28px 0 14px" width="272" id="hplogo"><br><br></div><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tr valign="top"><td width="25%">&nbsp;</td><td align="center" nowrap=""><input name="ie" value="ISO-8859-1" type="hidden"><input value="it" name="hl" type="hidden"><input name="source" type="hidden" value="hp"><input name="biw" type="hidden"><input name="bih" type="hidden"><div class="ds" style="height:32px;margin:4px 0"><input class="lst" style="margin:0;padding:5px 8px 0 6px;vertical-align:top;color:#000" autocomplete="off" value="" title="Cerca con Google" maxlength="2048" name="q" size="57"></div><br style="line-height:0"><span class="ds"><span class="lsbb"><input class="lsb" value="Cerca con Google" name="btnG" type="submit"></span></span><span class="ds"><span class="lsbb"><input class="lsb" id="tsuid1" value="Mi sento fortunato" name="btnI" type="submit"><script nonce="iT8XClq4+XYjXr36xn/8ug==">(function(){var id='tsuid1';document.getElementById(id).onclick = function(){if (this.form.q.value){this.checked = 1;if (this.form.iflsig)this.form.iflsig.disabled = false;} -else top.location='/doodles/';};})();</script><input value="AINFCbYAAAAAXus_2u9gzMvdJy0ivspzwFlQM1YDuMe3" name="iflsig" type="hidden"></span></span></td><td class="fl sblc" align="left" nowrap="" width="25%"><a href="/advanced_search?hl=it&amp;authuser=0">Ricerca avanzata</a></td></tr></table><input id="gbv" name="gbv" type="hidden" value="1"><script nonce="iT8XClq4+XYjXr36xn/8ug==">(function(){var a,b="1";if(document&&document.getElementById)if("undefined"!=typeof XMLHttpRequest)b="2";else if("undefined"!=typeof ActiveXObject){var c,d,e=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];for(c=0;d=e[c++];)try{new ActiveXObject(d),b="2"}catch(h){}}a=b;if("2"==a&&-1==location.search.indexOf("&gbv=2")){var f=google.gbvu,g=document.getElementById("gbv");g&&(g.value=a);f&&window.setTimeout(function(){location.href=f},0)};}).call(this);</script></form><div id="gac_scont"></div><div style="font-size:83%;min-height:3.5em"><br><div id="prm"><style>.szppmdbYutt__middle-slot-promo{font-size:small;margin-bottom:32px}.szppmdbYutt__middle-slot-promo a.ZIeIlb{display:inline-block;text-decoration:none}.szppmdbYutt__middle-slot-promo img{border:none;margin-right:5px;vertical-align:middle}</style><div class="szppmdbYutt__middle-slot-promo" data-ved="0ahUKEwiY3_jDhIvqAhUYSBUIHfbrDeUQnIcBCAQ"><a class="NKcBbd" href="https://www.google.com/url?q=https://apps.google.com/meet%3Futm_source%3Dgoogle%26utm_medium%3Det%26utm_content%3D%26utm_campaign%3DFY20-Q2-global-hpp-search-meet-desktop&amp;source=hpp&amp;id=19018299&amp;ct=3&amp;usg=AFQjCNECjPS4M9aaMcfnmITiZ9-bKPWkeA&amp;sa=X&amp;ved=0ahUKEwiY3_jDhIvqAhUYSBUIHfbrDeUQ8IcBCAU" rel="nofollow">Le funzionalità premium di Google per le riunioni video ora gratuite per tutti</a></div></div></div><span id="footer"><div style="font-size:10pt"><div style="margin:19px auto;text-align:center" id="fll"><a href="/intl/it/ads/">Pubblicità</a><a href="http://www.google.it/intl/it/services/">Soluzioni aziendali</a><a href="/intl/it/about.html">Tutto su Google</a><a href="https://www.google.com/setprefdomain?prefdom=IT&amp;prev=https://www.google.it/&amp;sig=K_a3T9nmNByUH53wGwJ1O1YkyiYqM%3D">Google.it</a></div></div><p style="font-size:8pt;color:#767676">&copy; 2020 - <a href="/intl/it/policies/privacy/">Privacy</a> - <a href="/intl/it/policies/terms/">Termini</a></p></span></center><script nonce="iT8XClq4+XYjXr36xn/8ug==">(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b){var c=window.document,d="CSS1Compat"==c.compatMode?c.documentElement:c.body;a=d.clientWidth;b=d.clientHeight}a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log("","","/client_204?&atyp=i&biw="+a+"&bih="+b+"&ei="+google.kEI);}).call(this);})();(function(){var u='/xjs/_/js/k\x3dxjs.hp.en.gXIbnxsdgOk.O/m\x3dsb_he,d/am\x3dAC8ENgc/d\x3d1/rs\x3dACT90oHjVCKhLjAM8wLnw2o1SrQwj_1ybA'; -setTimeout(function(){var b=document;var a="SCRIPT";"application/xhtml+xml"===b.contentType&&(a=a.toLowerCase());a=b.createElement(a);a.src=u;google.timers&&google.timers.load&&google.tick&&google.tick("load","xjsls");document.body.appendChild(a)},0);})();(function(){window.google.xjsu='/xjs/_/js/k\x3dxjs.hp.en.gXIbnxsdgOk.O/m\x3dsb_he,d/am\x3dAC8ENgc/d\x3d1/rs\x3dACT90oHjVCKhLjAM8wLnw2o1SrQwj_1ybA';})();function _DumpException(e){throw e;} -function _F_installCss(c){} -(function(){google.jl={dw:false,em:[],emw:false,lls:'default',pdt:0,snet:true,uwp:true};})();(function(){var pmc='{\x22d\x22:{},\x22sb_he\x22:{\x22agen\x22:true,\x22cgen\x22:true,\x22client\x22:\x22heirloom-hp\x22,\x22dh\x22:true,\x22dhqt\x22:true,\x22ds\x22:\x22\x22,\x22ffql\x22:\x22it\x22,\x22fl\x22:true,\x22host\x22:\x22google.com\x22,\x22isbh\x22:28,\x22jsonp\x22:true,\x22lm\x22:true,\x22msgs\x22:{\x22cibl\x22:\x22Cancella ricerca\x22,\x22dym\x22:\x22Forse cercavi:\x22,\x22lcky\x22:\x22Mi sento fortunato\x22,\x22lml\x22:\x22Ulteriori informazioni\x22,\x22oskt\x22:\x22Strumenti di immissione\x22,\x22psrc\x22:\x22Questa ricerca è stata rimossa dalla tua \\u003Ca href\x3d\\\x22/history\\\x22\\u003ECronologia web\\u003C/a\\u003E\x22,\x22psrl\x22:\x22Rimuovi\x22,\x22sbit\x22:\x22Ricerca tramite immagine\x22,\x22srch\x22:\x22Cerca con Google\x22},\x22ovr\x22:{},\x22pq\x22:\x22\x22,\x22refpd\x22:true,\x22rfs\x22:[],\x22sbpl\x22:16,\x22sbpr\x22:16,\x22scd\x22:10,\x22stok\x22:\x223YvOBi8coD3RdIQWH0x-LHCWea4\x22,\x22uhde\x22:false}}';google.pmc=JSON.parse(pmc);})();</script> </body></html> \ No newline at end of file diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 115bee0e7e..be9d99d204 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4841,6 +4841,7 @@ pref("gfx.direct2d.force-enabled", false); pref("layers.prefer-opengl", false); pref("layers.prefer-d3d9", false); +pref("layers.allow-d3d9-fallback", true); pref("layers.d3d11.force-warp", false); pref("layers.d3d11.disable-warp", false); @@ -4859,6 +4860,9 @@ pref("layers.compositor-lru-size", 0); // Enable/Disable the geolocation API for content pref("geo.enabled", true); +// Timeout for outbound network geolocation provider XHR +pref("geo.wifi.xhr.timeout", 60000); + // Enable/Disable the orientation API for content pref("device.sensors.enabled", true); diff --git a/parser/htmlparser/nsHTMLTagList.h b/parser/htmlparser/nsHTMLTagList.h index 76fe3b83c8..829cad96dd 100644 --- a/parser/htmlparser/nsHTMLTagList.h +++ b/parser/htmlparser/nsHTMLTagList.h @@ -105,7 +105,7 @@ HTML_TAG(label, Label) HTML_TAG(legend, Legend) HTML_TAG(li, LI) HTML_TAG(link, Link) -HTML_HTMLELEMENT_TAG(listing) +HTML_TAG(listing, Pre) HTML_HTMLELEMENT_TAG(main) HTML_TAG(map, Map) HTML_HTMLELEMENT_TAG(mark) @@ -170,7 +170,7 @@ HTML_TAG(ul, SharedList) HTML_HTMLELEMENT_TAG(var) HTML_TAG(video, Video) HTML_HTMLELEMENT_TAG(wbr) -HTML_HTMLELEMENT_TAG(xmp) +HTML_TAG(xmp, Pre) /* These are not for tags. But they will be included in the nsHTMLTag diff --git a/security/manager/pki/resources/content/exceptionDialog.xul b/security/manager/pki/resources/content/exceptionDialog.xul index 61f3148911..6d417f360c 100644 --- a/security/manager/pki/resources/content/exceptionDialog.xul +++ b/security/manager/pki/resources/content/exceptionDialog.xul @@ -9,12 +9,12 @@ <dialog id="exceptiondialog" windowtype="mozilla:exceptiondialog" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="&exceptionMgr.title;" buttons="cancel,extra1,extra2" buttonlabelextra1="&exceptionMgr.exceptionButton.label;" buttonaccesskeyextra1="&exceptionMgr.exceptionButton.accesskey;" - style="width: 500px; height: 480px;" + style="width: 46em; min-height: 38em;" onload="initExceptionDialog();" ondialogextra1="addException();" ondialogextra2="checkCert();" @@ -28,7 +28,7 @@ <script type="application/javascript" src="chrome://pippki/content/pippki.js"/> <script type="application/javascript" src="chrome://pippki/content/exceptionDialog.js"/> - + <hbox> <vbox> #ifdef MOZ_WIDGET_GTK @@ -63,27 +63,25 @@ <groupbox id="certStatusGroupBox" flex="1"> <caption label="&exceptionMgr.certstatus.caption;"/> - <vbox style="overflow: auto;" flex="1"> - <hbox> - <description id="headerDescription" style="white-space: pre-wrap;" - flex="1"/> - <vbox> - <button id="viewCertButton" label="&exceptionMgr.certstatus.viewCert;" - accesskey="&exceptionMgr.certstatus.accesskey;" - disabled="true" oncommand="viewCertButtonClick();"/> - </vbox> - </hbox> - <description id="statusDescription" - style="font-weight: bold; padding-bottom: 1em;"/> - <description id="statusLongDescription" style="white-space: pre-wrap;"/> - <description id="status2Description" - style="font-weight: bold; padding-bottom: 1em;"/> - <description id="status2LongDescription" style="white-space: pre-wrap;"/> - <description id="status3Description" - style="font-weight: bold; padding-bottom: 1em;"/> - <description id="status3LongDescription" style="white-space: pre-wrap;"/> - <spacer flex="1"/> - </vbox> + <hbox> + <description id="headerDescription" style="white-space: pre-wrap;" + flex="1"/> + <vbox> + <button id="viewCertButton" label="&exceptionMgr.certstatus.viewCert;" + accesskey="&exceptionMgr.certstatus.accesskey;" + disabled="true" oncommand="viewCertButtonClick();"/> + </vbox> + </hbox> + <description id="statusDescription" + style="font-weight: bold; padding-bottom: 1em;"/> + <description id="statusLongDescription" style="white-space: pre-wrap;"/> + <description id="status2Description" + style="font-weight: bold; padding-bottom: 1em;"/> + <description id="status2LongDescription" style="white-space: pre-wrap;"/> + <description id="status3Description" + style="font-weight: bold; padding-bottom: 1em;"/> + <description id="status3LongDescription" style="white-space: pre-wrap;"/> + <spacer flex="1"/> <checkbox id="permanent" disabled="true" label="&exceptionMgr.permanent.label;" accesskey="&exceptionMgr.permanent.accesskey;"/> diff --git a/security/manager/pki/resources/content/pippki.js b/security/manager/pki/resources/content/pippki.js index a8e5eacbd1..b4db052562 100644 --- a/security/manager/pki/resources/content/pippki.js +++ b/security/manager/pki/resources/content/pippki.js @@ -73,32 +73,50 @@ function alertPromptService(title, message) ps.alert(window, title, message); } +const DEFAULT_CERT_EXTENSION = "crt"; + +/** + * Generates a filename for a cert suitable to set as the |defaultString| + * attribute on an nsIFilePicker. + * + * @param {nsIX509Cert} cert + * The cert to generate a filename for. + * @returns {String} + * Generated filename. + */ +function certToFilename(cert) { + let filename = cert.commonName; + if (!filename) { + filename = cert.windowTitle; + } + + // Remove unneeded and/or unsafe characters. + filename = filename.replace(/\s/g, "") + .replace(/\./g, "") + .replace(/\\/g, "") + .replace(/\//g, ""); + + // nsIFilePicker.defaultExtension is more of a suggestion to some + // implementations, so we include the extension in the file name as well. This + // is what the documentation for nsIFilePicker.defaultString says we should do + // anyways. + return `${filename}.${DEFAULT_CERT_EXTENSION}`; +} + function exportToFile(parent, cert) { var bundle = document.getElementById("pippki_bundle"); - if (!cert) + if (!cert) { return; + } var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"]. createInstance(nsIFilePicker); fp.init(parent, bundle.getString("SaveCertAs"), nsIFilePicker.modeSave); - - var filename = cert.commonName; - if (!filename) - filename = cert.windowTitle; - // Remove undesired characters and whitespace from the default filename - fp.defaultString = filename.replace(/\s/g, "") - .replace(/\./g, "") - .replace(/\\/g, "") - .replace(/\//g, "") - + ".crt"; - // nsIFilePicker.defaultExtension is more of a suggestion to some filepicker - // implementations, so we include the extension in the file name as well. This - // is what the documentation for nsIFilePicker.defaultString says we should do - // anyway. - fp.defaultExtension = "crt"; + fp.defaultString = certToFilename(cert); + fp.defaultExtension = DEFAULT_CERT_EXTENSION; fp.appendFilter(bundle.getString("CertFormatBase64"), "*.crt; *.pem"); fp.appendFilter(bundle.getString("CertFormatBase64Chain"), "*.crt; *.pem"); fp.appendFilter(bundle.getString("CertFormatDER"), "*.der"); @@ -106,8 +124,9 @@ function exportToFile(parent, cert) fp.appendFilter(bundle.getString("CertFormatPKCS7Chain"), "*.p7c"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); - if (res != nsIFilePicker.returnOK && res != nsIFilePicker.returnReplace) + if (res != nsIFilePicker.returnOK && res != nsIFilePicker.returnReplace) { return; + } var content = ''; switch (fp.filterIndex) { diff --git a/security/manager/tools/makeCNNICHashes.js b/security/manager/tools/makeCNNICHashes.js index a52de0810a..07519f89ae 100644 --- a/security/manager/tools/makeCNNICHashes.js +++ b/security/manager/tools/makeCNNICHashes.js @@ -15,9 +15,9 @@ // where certlist is a file containing a list of paths to certificates to // be included in the whitelist -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; var gCertDB = Cc["@mozilla.org/security/x509certdb;1"] .getService(Ci.nsIX509CertDB); diff --git a/services/common/async.js b/services/common/async.js index 2c2b818f6c..aa977cbef5 100644 --- a/services/common/async.js +++ b/services/common/async.js @@ -207,4 +207,14 @@ this.Async = { query.executeAsync(storageCallback); return Async.waitForSyncCallback(storageCallback.syncCb); }, + + promiseSpinningly(promise) { + let cb = Async.makeSpinningCallback(); + promise.then(result => { + cb(null, result); + }, err => { + cb(err || new Error("Promise rejected without explicit error")); + }); + return cb.wait(); + }, }; diff --git a/services/common/logmanager.js b/services/common/logmanager.js index 219b0e3aa5..73c9d9fc63 100644 --- a/services/common/logmanager.js +++ b/services/common/logmanager.js @@ -114,12 +114,6 @@ LogManager.prototype = { // now attach the appenders to all our logs. for (let logName of logNames) { let log = Log.repository.getLogger(logName); - // Set all of the logs themselves to log all messages, and rely on the - // more restrictive levels on the appenders to restrict what is seen. - // (We possibly could find the smallest appender level and set the logs - // to that, but that gets tricky when we consider a singe log might end - // up being managed by multiple log managers - so this is fine for now.) - log.level = Log.Level.All; for (let appender of [fapp, dumpAppender, consoleAppender]) { log.addAppender(appender); } diff --git a/services/common/rest.js b/services/common/rest.js index 74a2537eab..6ddb8fb0af 100644 --- a/services/common/rest.js +++ b/services/common/rest.js @@ -20,7 +20,7 @@ Cu.import("resource://services-common/utils.js"); XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils", "resource://services-crypto/utils.js"); -const Prefs = new Preferences("services.common.rest."); +const Prefs = new Preferences("services.common."); /** * Single use HTTP requests to RESTish resources. @@ -316,6 +316,7 @@ RESTRequest.prototype = { channel.loadFlags |= this.loadFlags; channel.notificationCallbacks = this; + this._log.debug(`${method} request to ${this.uri.spec}`); // Set request headers. let headers = this._headers; for (let key in headers) { @@ -642,7 +643,7 @@ this.RESTResponse = function RESTResponse() { } RESTResponse.prototype = { - _logName: "Sync.RESTResponse", + _logName: "Services.Common.RESTResponse", /** * Corresponding REST request diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 6e80457ac1..695ef79480 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -272,69 +272,69 @@ BookmarksEngine.prototype = { _guidMapFailed: false, _buildGUIDMap: function _buildGUIDMap() { let guidMap = {}; - for (let guid in this._store.getAllIDs()) { - // Figure out with which key to store the mapping. - let key; - let id = this._store.idForGUID(guid); - let itemType; - try { - itemType = PlacesUtils.bookmarks.getItemType(id); - } catch (ex) { - this._log.warn("Deleting invalid bookmark record with id", id); - try { - PlacesUtils.bookmarks.removeItem(id); - } catch (ex) { - this._log.warn("Failed to delete invalid bookmark", ex); + let tree = Async.promiseSpinningly(PlacesUtils.promiseBookmarksTree("", { + includeItemIds: true + })); + function* walkBookmarksTree(tree, parent=null) { + if (tree) { + // Skip root node + if (parent) { + yield [tree, parent]; + } + if (tree.children) { + for (let child of tree.children) { + yield* walkBookmarksTree(child, tree); + } + } + } + } + + function* walkBookmarksRoots(tree, rootGUIDs) { + for (let guid of rootGUIDs) { + let id = kSpecialIds.specialIdForGUID(guid, false); + let bookmarkRoot = id === null ? null : + tree.children.find(child => child.id === id); + if (bookmarkRoot === null) { + continue; } - continue; + yield* walkBookmarksTree(bookmarkRoot, tree); } - switch (itemType) { - case PlacesUtils.bookmarks.TYPE_BOOKMARK: - - // Smart bookmarks map to their annotation value. - let queryId; - try { - queryId = PlacesUtils.annotations.getItemAnnotation( - id, SMART_BOOKMARKS_ANNO); - } catch(ex) {} - - if (queryId) { - key = "q" + queryId; + } + + let rootsToWalk = kSpecialIds.guids.filter(guid => + guid !== 'places' && guid !== 'tags'); + + for (let [node, parent] of walkBookmarksRoots(tree, rootsToWalk)) { + let {guid, id, type: placeType} = node; + guid = kSpecialIds.specialGUIDForId(id) || guid; + let key; + switch (placeType) { + case PlacesUtils.TYPE_X_MOZ_PLACE: + // Bookmark + let query = null; + if (node.annos && node.uri.startsWith("place:")) { + query = node.annos.find(({name}) => name === SMART_BOOKMARKS_ANNO); + } + if (query && query.value) { + key = "q" + query.value; } else { - let uri; - try { - uri = PlacesUtils.bookmarks.getBookmarkURI(id); - } catch (ex) { - // Bug 1182366 - NS_ERROR_MALFORMED_URI here stops bookmarks sync. - // Try and get the string value of the URL for diagnostic purposes. - let url = this._getStringUrlForId(id); - this._log.warn(`Deleting bookmark with invalid URI. url="${url}", id=${id}`); - try { - PlacesUtils.bookmarks.removeItem(id); - } catch (ex) { - this._log.warn("Failed to delete invalid bookmark", ex); - } - continue; - } - key = "b" + uri.spec + ":" + PlacesUtils.bookmarks.getItemTitle(id); + key = "b" + node.uri + ":" + node.title; } break; - case PlacesUtils.bookmarks.TYPE_FOLDER: - key = "f" + PlacesUtils.bookmarks.getItemTitle(id); + case PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER: + // Folder + key = "f" + node.title; break; - case PlacesUtils.bookmarks.TYPE_SEPARATOR: - key = "s" + PlacesUtils.bookmarks.getItemIndex(id); + case PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR: + // Separator + key = "s" + node.index; break; default: + this._log.error("Unknown place type: '"+placeType+"'"); continue; } - // The mapping is on a per parent-folder-name basis. - let parent = PlacesUtils.bookmarks.getFolderIdForItem(id); - if (parent <= 0) - continue; - - let parentName = PlacesUtils.bookmarks.getItemTitle(parent); + let parentName = parent.title; if (guidMap[parentName] == null) guidMap[parentName] = {}; diff --git a/services/sync/modules/policies.js b/services/sync/modules/policies.js index ecb94cca8a..e358ea306f 100644 --- a/services/sync/modules/policies.js +++ b/services/sync/modules/policies.js @@ -599,7 +599,8 @@ ErrorHandler.prototype = { root.level = Log.Level[Svc.Prefs.get("log.rootLogger")]; let logs = ["Sync", "FirefoxAccounts", "Hawk", "Common.TokenServerClient", - "Sync.SyncMigration"]; + "Sync.SyncMigration", "Services.Common.RESTRequest", "Services.Common.RESTRequest", + ]; this._logManager = new LogManager(Svc.Prefs, logs, "sync"); }, diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js index 97af659ae6..5473608b21 100644 --- a/services/sync/tests/unit/test_bookmark_engine.js +++ b/services/sync/tests/unit/test_bookmark_engine.js @@ -396,7 +396,9 @@ add_test(function test_bookmark_guidMap_fail() { engine.lastSync = 1; // So we don't back up. // Make building the GUID map fail. - store.getAllIDs = function () { throw "Nooo"; }; + + let pbt = PlacesUtils.promiseBookmarksTree; + PlacesUtils.promiseBookmarksTree = function() { return Promise.reject("Nooo"); }; // Ensure that we throw when accessing _guidMap. engine._syncStartup(); @@ -422,6 +424,7 @@ add_test(function test_bookmark_guidMap_fail() { } do_check_eq(err, "Nooo"); + PlacesUtils.promiseBookmarksTree = pbt; server.stop(run_next_test); }); diff --git a/services/sync/tests/unit/test_bookmark_invalid.js b/services/sync/tests/unit/test_bookmark_invalid.js index 5d0ac420da..365a11fac6 100644 --- a/services/sync/tests/unit/test_bookmark_invalid.js +++ b/services/sync/tests/unit/test_bookmark_invalid.js @@ -12,46 +12,6 @@ var engine = Service.engineManager.get("bookmarks"); var store = engine._store; var tracker = engine._tracker; -// Return a promise resolved when the specified message is written to the -// bookmarks engine log. -function promiseLogMessage(messagePortion) { - return new Promise(resolve => { - let appender; - let log = Log.repository.getLogger("Sync.Engine.Bookmarks"); - - function TestAppender() { - Log.Appender.call(this); - } - TestAppender.prototype = Object.create(Log.Appender.prototype); - TestAppender.prototype.doAppend = function(message) { - if (message.indexOf(messagePortion) >= 0) { - log.removeAppender(appender); - resolve(); - } - }; - TestAppender.prototype.level = Log.Level.Debug; - appender = new TestAppender(); - log.addAppender(appender); - }); -} - -// Returns a promise that resolves if the specified ID does *not* exist and -// rejects if it does. -function promiseNoItem(itemId) { - return new Promise((resolve, reject) => { - try { - PlacesUtils.bookmarks.getFolderIdForItem(itemId); - reject("fetching the item didn't fail"); - } catch (ex) { - if (ex.result == Cr.NS_ERROR_ILLEGAL_VALUE) { - resolve("item doesn't exist"); - } else { - reject("unexpected exception: " + ex); - } - } - }); -} - add_task(function* test_ignore_invalid_uri() { _("Ensure that we don't die with invalid bookmarks."); @@ -70,13 +30,9 @@ add_task(function* test_ignore_invalid_uri() { { id: bmid, url: "<invalid url>" }); })); - // DB is now "corrupt" - setup a log appender to capture what we log. - let promiseMessage = promiseLogMessage('Deleting bookmark with invalid URI. url="<invalid url>"'); - // This should work and log our invalid id. + // Ensure that this doesn't throw even though the DB is now in a bad state (a + // bookmark has an illegal url). engine._buildGUIDMap(); - yield promiseMessage; - // And we should have deleted the item. - yield promiseNoItem(bmid); }); add_task(function* test_ignore_missing_uri() { @@ -96,13 +52,9 @@ add_task(function* test_ignore_missing_uri() { , { id: bmid }); })); - // DB is now "corrupt" - bookmarks will fail to locate a string url to log - // and use "<not found>" as a placeholder. - let promiseMessage = promiseLogMessage('Deleting bookmark with invalid URI. url="<not found>"'); + // Ensure that this doesn't throw even though the DB is now in a bad state (a + // bookmark has an illegal url). engine._buildGUIDMap(); - yield promiseMessage; - // And we should have deleted the item. - yield promiseNoItem(bmid); }); function run_test() { diff --git a/storage/test/unit/test_js_helpers.js b/storage/test/unit/test_js_helpers.js index c5dde3410d..f2af16978b 100644 --- a/storage/test/unit/test_js_helpers.js +++ b/storage/test/unit/test_js_helpers.js @@ -104,7 +104,7 @@ function test_params_gets_async() //////////////////////////////////////////////////////////////////////////////// //// Test Runner -let tests = [ +var tests = [ test_params_enumerate, test_params_prototype, test_row_prototype, diff --git a/storage/test/unit/test_locale_collation.js b/storage/test/unit/test_locale_collation.js index 402fd8b458..b134390d8d 100644 --- a/storage/test/unit/test_locale_collation.js +++ b/storage/test/unit/test_locale_collation.js @@ -254,7 +254,7 @@ function setup() /////////////////////////////////////////////////////////////////////////////// //// Test Runs -let gTests = [ +var gTests = [ { desc: "Case and accent sensitive UTF-8", run: () => runUtf8Test("locale_case_accent_sensitive") diff --git a/storage/test/unit/test_statement_executeAsync.js b/storage/test/unit/test_statement_executeAsync.js index 592e576ccc..8cf0c38676 100644 --- a/storage/test/unit/test_statement_executeAsync.js +++ b/storage/test/unit/test_statement_executeAsync.js @@ -889,7 +889,7 @@ const TEST_PASS_ASYNC = 1; * dispatching, some tests are sync/async specific. These functions are marked * with 'syncOnly' or 'asyncOnly' attributes and run_next_test knows what to do. */ -let testPass = TEST_PASS_SYNC; +var testPass = TEST_PASS_SYNC; /** * Create a statement of the type under test per testPass. @@ -940,10 +940,10 @@ var tests = [ test_not_right_owning_statement, test_multiple_results, ]; -let index = 0; +var index = 0; const STARTING_UNIQUE_ID = 2; -let nextUniqueId = STARTING_UNIQUE_ID; +var nextUniqueId = STARTING_UNIQUE_ID; function run_next_test() { diff --git a/storage/test/unit/test_storage_connection.js b/storage/test/unit/test_storage_connection.js index d12ecc9f6b..da03bbe531 100644 --- a/storage/test/unit/test_storage_connection.js +++ b/storage/test/unit/test_storage_connection.js @@ -68,12 +68,8 @@ add_task(function* test_indexExists_created() { add_task(function* test_createTable_already_created() { var msc = getOpenedDatabase(); do_check_true(msc.tableExists("test")); - try { - msc.createTable("test", "id INTEGER PRIMARY KEY, name TEXT"); - do_throw("We shouldn't get here!"); - } catch (e) { - do_check_eq(Cr.NS_ERROR_FAILURE, e.result); - } + Assert.throws(() => msc.createTable("test", "id INTEGER PRIMARY KEY, name TEXT"), + /NS_ERROR_FAILURE/); }); add_task(function* test_attach_createTable_tableExists_indexExists() { @@ -85,15 +81,8 @@ add_task(function* test_attach_createTable_tableExists_indexExists() { do_check_false(msc.tableExists("sample.test")); msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT"); do_check_true(msc.tableExists("sample.test")); - try { - msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT"); - do_throw("We shouldn't get here!"); - } catch (e) { - if (e.result != Components.results.NS_ERROR_FAILURE) { - throw e; - } - // we expect to fail because this table should exist already. - } + Assert.throws(() => msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT"), + /NS_ERROR_FAILURE/); do_check_false(msc.indexExists("sample.test_ind")); msc.executeSimpleSQL("CREATE INDEX sample.test_ind ON test (name)"); @@ -135,23 +124,13 @@ add_task(function* test_transactionInProgress_yes() { add_task(function* test_commitTransaction_no_transaction() { var msc = getOpenedDatabase(); do_check_false(msc.transactionInProgress); - try { - msc.commitTransaction(); - do_throw("We should not get here!"); - } catch (e) { - do_check_eq(Cr.NS_ERROR_UNEXPECTED, e.result); - } + Assert.throws(() => msc.commitTransaction(), /NS_ERROR_UNEXPECTED/); }); add_task(function* test_rollbackTransaction_no_transaction() { var msc = getOpenedDatabase(); do_check_false(msc.transactionInProgress); - try { - msc.rollbackTransaction(); - do_throw("We should not get here!"); - } catch (e) { - do_check_eq(Cr.NS_ERROR_UNEXPECTED, e.result); - } + Assert.throws(() => msc.rollbackTransaction(), /NS_ERROR_UNEXPECTED/); }); add_task(function* test_get_schemaVersion_not_set() { @@ -292,21 +271,15 @@ add_task(function* test_close_fails_with_async_statement_ran() { stmt.finalize(); let db = getOpenedDatabase(); - try { - db.close(); - do_throw("should have thrown"); - } - catch (e) { - do_check_eq(e.result, Cr.NS_ERROR_UNEXPECTED); - } - finally { - // Clean up after ourselves. - db.asyncClose(function () { - // Reset gDBConn so that later tests will get a new connection object. - gDBConn = null; - deferred.resolve(); - }); - } + Assert.throws(() => db.close(), /NS_ERROR_UNEXPECTED/); + + // Clean up after ourselves. + db.asyncClose(function () { + // Reset gDBConn so that later tests will get a new connection object. + gDBConn = null; + deferred.resolve(); + }); + yield deferred.promise; }); diff --git a/storage/test/unit/test_storage_value_array.js b/storage/test/unit/test_storage_value_array.js index dbeb7bb56a..27bd23992e 100644 --- a/storage/test/unit/test_storage_value_array.js +++ b/storage/test/unit/test_storage_value_array.js @@ -4,8 +4,7 @@ // This file tests the functions of mozIStorageValueArray -function setup() -{ +add_task(function* setup() { getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT," + "number REAL, nuller NULL, blobber BLOB"); @@ -23,10 +22,11 @@ function setup() stmt.reset(); stmt.finalize(); -} -function test_getIsNull_for_null() -{ + do_register_cleanup(cleanup); +}); + +add_task(function* test_getIsNull_for_null() { var stmt = createStatement("SELECT nuller, blobber FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -35,10 +35,9 @@ function test_getIsNull_for_null() do_check_true(stmt.getIsNull(1)); // data is null if size is 0 stmt.reset(); stmt.finalize(); -} +}); -function test_getIsNull_for_non_null() -{ +add_task(function* test_getIsNull_for_non_null() { var stmt = createStatement("SELECT name, blobber FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -47,10 +46,9 @@ function test_getIsNull_for_non_null() do_check_false(stmt.getIsNull(1)); stmt.reset(); stmt.finalize(); -} +}); -function test_value_type_null() -{ +add_task(function* test_value_type_null() { var stmt = createStatement("SELECT nuller FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -59,10 +57,9 @@ function test_value_type_null() stmt.getTypeOfIndex(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_value_type_integer() -{ +add_task(function* test_value_type_integer() { var stmt = createStatement("SELECT id FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -71,10 +68,9 @@ function test_value_type_integer() stmt.getTypeOfIndex(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_value_type_float() -{ +add_task(function* test_value_type_float() { var stmt = createStatement("SELECT number FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -83,10 +79,9 @@ function test_value_type_float() stmt.getTypeOfIndex(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_value_type_text() -{ +add_task(function* test_value_type_text() { var stmt = createStatement("SELECT name FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -95,10 +90,9 @@ function test_value_type_text() stmt.getTypeOfIndex(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_value_type_blob() -{ +add_task(function* test_value_type_blob() { var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -107,10 +101,9 @@ function test_value_type_blob() stmt.getTypeOfIndex(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_numEntries_one() -{ +add_task(function* test_numEntries_one() { var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -118,10 +111,9 @@ function test_numEntries_one() do_check_eq(1, stmt.numEntries); stmt.reset(); stmt.finalize(); -} +}); -function test_numEntries_all() -{ +add_task(function* test_numEntries_all() { var stmt = createStatement("SELECT * FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -129,10 +121,9 @@ function test_numEntries_all() do_check_eq(5, stmt.numEntries); stmt.reset(); stmt.finalize(); -} +}); -function test_getInt() -{ +add_task(function* test_getInt() { var stmt = createStatement("SELECT id FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -141,10 +132,9 @@ function test_getInt() do_check_eq(2, stmt.getInt64(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_getDouble() -{ +add_task(function* test_getDouble() { var stmt = createStatement("SELECT number FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -152,10 +142,9 @@ function test_getDouble() do_check_eq(1.23, stmt.getDouble(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_getUTF8String() -{ +add_task(function* test_getUTF8String() { var stmt = createStatement("SELECT name FROM test WHERE id = ?1"); stmt.bindByIndex(0, 1); do_check_true(stmt.executeStep()); @@ -163,10 +152,9 @@ function test_getUTF8String() do_check_eq("foo", stmt.getUTF8String(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_getString() -{ +add_task(function* test_getString() { var stmt = createStatement("SELECT name FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -174,10 +162,9 @@ function test_getString() do_check_eq("", stmt.getString(0)); stmt.reset(); stmt.finalize(); -} +}); -function test_getBlob() -{ +add_task(function* test_getBlob() { var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1"); stmt.bindByIndex(0, 2); do_check_true(stmt.executeStep()); @@ -190,22 +177,6 @@ function test_getBlob() do_check_eq(2, arr.value[1]); stmt.reset(); stmt.finalize(); -} - -var tests = [test_getIsNull_for_null, test_getIsNull_for_non_null, - test_value_type_null, test_value_type_integer, - test_value_type_float, test_value_type_text, test_value_type_blob, - test_numEntries_one, test_numEntries_all, test_getInt, - test_getDouble, test_getUTF8String, test_getString, test_getBlob]; - -function run_test() -{ - setup(); - - for (var i = 0; i < tests.length; i++) { - tests[i](); - } +}); - cleanup(); -} diff --git a/storage/test/unit/test_unicode.js b/storage/test/unit/test_unicode.js index 8aa8f01296..7753bbfdbf 100644 --- a/storage/test/unit/test_unicode.js +++ b/storage/test/unit/test_unicode.js @@ -7,8 +7,7 @@ const LATIN1_AE = "\xc6"; // "Æ" const LATIN1_ae = "\xe6"; // "æ" -function setup() -{ +add_task(function* setup() { getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT"); var stmt = createStatement("INSERT INTO test (name, id) VALUES (?1, ?2)"); @@ -25,20 +24,20 @@ function setup() stmt.bindByIndex(1, 4); stmt.execute(); stmt.finalize(); -} -function test_upper_ascii() -{ + do_register_cleanup(cleanup); +}); + +add_task(function* test_upper_ascii() { var stmt = createStatement("SELECT name, id FROM test WHERE name = upper('a')"); do_check_true(stmt.executeStep()); do_check_eq("A", stmt.getString(0)); do_check_eq(2, stmt.getInt32(1)); stmt.reset(); stmt.finalize(); -} +}); -function test_upper_non_ascii() -{ +add_task(function* test_upper_non_ascii() { var stmt = createStatement("SELECT name, id FROM test WHERE name = upper(?1)"); stmt.bindByIndex(0, LATIN1_ae); do_check_true(stmt.executeStep()); @@ -46,20 +45,18 @@ function test_upper_non_ascii() do_check_eq(1, stmt.getInt32(1)); stmt.reset(); stmt.finalize(); -} +}); -function test_lower_ascii() -{ +add_task(function* test_lower_ascii() { var stmt = createStatement("SELECT name, id FROM test WHERE name = lower('B')"); do_check_true(stmt.executeStep()); do_check_eq("b", stmt.getString(0)); do_check_eq(3, stmt.getInt32(1)); stmt.reset(); stmt.finalize(); -} +}); -function test_lower_non_ascii() -{ +add_task(function* test_lower_non_ascii() { var stmt = createStatement("SELECT name, id FROM test WHERE name = lower(?1)"); stmt.bindByIndex(0, LATIN1_AE); do_check_true(stmt.executeStep()); @@ -67,38 +64,20 @@ function test_lower_non_ascii() do_check_eq(4, stmt.getInt32(1)); stmt.reset(); stmt.finalize(); -} +}); -function test_like_search_different() -{ +add_task(function* test_like_search_different() { var stmt = createStatement("SELECT COUNT(*) FROM test WHERE name LIKE ?1"); stmt.bindByIndex(0, LATIN1_AE); do_check_true(stmt.executeStep()); do_check_eq(2, stmt.getInt32(0)); stmt.finalize(); -} +}); -function test_like_search_same() -{ +add_task(function* test_like_search_same() { var stmt = createStatement("SELECT COUNT(*) FROM test WHERE name LIKE ?1"); stmt.bindByIndex(0, LATIN1_ae); do_check_true(stmt.executeStep()); do_check_eq(2, stmt.getInt32(0)); stmt.finalize(); -} - -var tests = [test_upper_ascii, test_upper_non_ascii, test_lower_ascii, - test_lower_non_ascii, test_like_search_different, - test_like_search_same]; - -function run_test() -{ - setup(); - - for (var i = 0; i < tests.length; i++) { - tests[i](); - } - - cleanup(); -} - +}); diff --git a/storage/test/unit/vacuumParticipant.js b/storage/test/unit/vacuumParticipant.js index d6af4152a7..01b980178c 100644 --- a/storage/test/unit/vacuumParticipant.js +++ b/storage/test/unit/vacuumParticipant.js @@ -121,5 +121,5 @@ vacuumParticipant.prototype = ]) }; -let gComponentsArray = [vacuumParticipant]; +var gComponentsArray = [vacuumParticipant]; this.NSGetFactory = XPCOMUtils.generateNSGetFactory(gComponentsArray); diff --git a/widget/CompositorWidgetProxy.cpp b/widget/CompositorWidgetProxy.cpp new file mode 100644 index 0000000000..a4594a2b70 --- /dev/null +++ b/widget/CompositorWidgetProxy.cpp @@ -0,0 +1,206 @@ +/* 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 "CompositorWidgetProxy.h" +#include "GLConsts.h" +#include "nsBaseWidget.h" + +namespace mozilla { +namespace widget { + +CompositorWidgetProxy::~CompositorWidgetProxy() +{ +} + +already_AddRefed<gfx::DrawTarget> +CompositorWidgetProxy::StartRemoteDrawing() +{ + return nullptr; +} + +void +CompositorWidgetProxy::CleanupRemoteDrawing() +{ + mLastBackBuffer = nullptr; +} + +already_AddRefed<gfx::DrawTarget> +CompositorWidgetProxy::CreateBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget, + const LayoutDeviceIntRect& aRect, + const LayoutDeviceIntRect& aClearRect) +{ + MOZ_ASSERT(aScreenTarget); + gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; + gfx::IntSize size = aRect.ToUnknownRect().Size(); + gfx::IntSize clientSize(GetClientSize().ToUnknownSize()); + + RefPtr<gfx::DrawTarget> target; + // Re-use back buffer if possible + if (mLastBackBuffer && + mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() && + mLastBackBuffer->GetFormat() == format && + size <= mLastBackBuffer->GetSize() && + mLastBackBuffer->GetSize() <= clientSize) { + target = mLastBackBuffer; + target->SetTransform(gfx::Matrix()); + if (!aClearRect.IsEmpty()) { + gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft(); + target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height)); + } + } else { + target = aScreenTarget->CreateSimilarDrawTarget(size, format); + mLastBackBuffer = target; + } + return target.forget(); +} + +uint32_t +CompositorWidgetProxy::GetGLFrameBufferFormat() +{ + return LOCAL_GL_RGBA; +} + +CompositorWidgetProxyWrapper::CompositorWidgetProxyWrapper(nsBaseWidget* aWidget) + : mWidget(aWidget) +{ +} + +bool +CompositorWidgetProxyWrapper::PreRender(layers::LayerManagerComposite* aManager) +{ + if (!mWidget) { + return false; + } + return mWidget->PreRender(aManager); +} + +void +CompositorWidgetProxyWrapper::PostRender(layers::LayerManagerComposite* aManager) +{ + if (!mWidget) { + return; + } + mWidget->PostRender(aManager); +} + +void +CompositorWidgetProxyWrapper::DrawWindowUnderlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) +{ + if (!mWidget) { + return; + } + mWidget->DrawWindowUnderlay(aManager, aRect); +} + +void +CompositorWidgetProxyWrapper::DrawWindowOverlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) +{ + if (!mWidget) { + return; + } + mWidget->DrawWindowOverlay(aManager, aRect); +} + +already_AddRefed<gfx::DrawTarget> +CompositorWidgetProxyWrapper::StartRemoteDrawing() +{ + if (!mWidget) { + return nullptr; + } + return mWidget->StartRemoteDrawing(); +} + +already_AddRefed<gfx::DrawTarget> +CompositorWidgetProxyWrapper::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + layers::BufferMode* aBufferMode) +{ + if (!mWidget) { + return nullptr; + } + return mWidget->StartRemoteDrawingInRegion(aInvalidRegion, aBufferMode); +} + +void +CompositorWidgetProxyWrapper::EndRemoteDrawing() +{ + if (!mWidget) { + return; + } + mWidget->EndRemoteDrawing(); +} + +void +CompositorWidgetProxyWrapper::EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget, + LayoutDeviceIntRegion& aInvalidRegion) +{ + if (!mWidget) { + return; + } + mWidget->EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion); +} + +void +CompositorWidgetProxyWrapper::CleanupRemoteDrawing() +{ + if (mWidget) { + mWidget->CleanupRemoteDrawing(); + } + CompositorWidgetProxy::CleanupRemoteDrawing(); +} + +void +CompositorWidgetProxyWrapper::CleanupWindowEffects() +{ + if (!mWidget) { + return; + } + mWidget->CleanupWindowEffects(); +} + +bool +CompositorWidgetProxyWrapper::InitCompositor(layers::Compositor* aCompositor) +{ + if (!mWidget) { + return false; + } + return mWidget->InitCompositor(aCompositor); +} + +LayoutDeviceIntSize +CompositorWidgetProxyWrapper::GetClientSize() +{ + if (!mWidget) { + return LayoutDeviceIntSize(); + } + return mWidget->GetClientSize(); +} + +uint32_t +CompositorWidgetProxyWrapper::GetGLFrameBufferFormat() +{ + if (!mWidget) { + return CompositorWidgetProxy::GetGLFrameBufferFormat(); + } + return mWidget->GetGLFrameBufferFormat(); +} + +layers::Composer2D* +CompositorWidgetProxyWrapper::GetComposer2D() +{ + if (!mWidget) { + return nullptr; + } + return mWidget->GetComposer2D(); +} + +nsIWidget* +CompositorWidgetProxyWrapper::RealWidget() +{ + return mWidget; +} + +} // namespace widget +} // namespace mozilla diff --git a/widget/CompositorWidgetProxy.h b/widget/CompositorWidgetProxy.h new file mode 100644 index 0000000000..eb5eea4073 --- /dev/null +++ b/widget/CompositorWidgetProxy.h @@ -0,0 +1,218 @@ +/* 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_widget_CompositorWidgetProxy_h__ +#define mozilla_widget_CompositorWidgetProxy_h__ + +#include "nsISupports.h" +#include "mozilla/RefPtr.h" +#include "Units.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/layers/LayersTypes.h" + +class nsIWidget; +class nsBaseWidget; + +namespace mozilla { +namespace layers { +class Compositor; +class LayerManagerComposite; +class Compositor; +class Composer2D; +} // namespace layers +namespace gfx { +class DrawTarget; +} // namespace gfx +namespace widget { + +/** + * Access to a widget from the compositor is restricted to these methods. + */ +class CompositorWidgetProxy +{ +public: + NS_INLINE_DECL_REFCOUNTING(mozilla::widget::CompositorWidgetProxy) + + /** + * Called before rendering using OMTC. Returns false when the widget is + * not ready to be rendered (for example while the window is closed). + * + * Always called from the compositing thread, which may be the main-thread if + * OMTC is not enabled. + */ + virtual bool PreRender(layers::LayerManagerComposite* aManager) { + return true; + } + + /** + * Called after rendering using OMTC. Not called when rendering was + * cancelled by a negative return value from PreRender. + * + * Always called from the compositing thread, which may be the main-thread if + * OMTC is not enabled. + */ + virtual void PostRender(layers::LayerManagerComposite* aManager) + {} + + /** + * Called before the LayerManager draws the layer tree. + * + * Always called from the compositing thread. + */ + virtual void DrawWindowUnderlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) + {} + + /** + * Called after the LayerManager draws the layer tree + * + * Always called from the compositing thread. + */ + virtual void DrawWindowOverlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) + {} + + /** + * Return a DrawTarget for the window which can be composited into. + * + * Called by BasicCompositor on the compositor thread for OMTC drawing + * before each composition. + * + * The window may specify its buffer mode. If unspecified, it is assumed + * to require double-buffering. + */ + virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing(); + virtual already_AddRefed<gfx::DrawTarget> + StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + layers::BufferMode* aBufferMode) + { + return StartRemoteDrawing(); + } + + /** + * Ensure that what was painted into the DrawTarget returned from + * StartRemoteDrawing reaches the screen. + * + * Called by BasicCompositor on the compositor thread for OMTC drawing + * after each composition. + */ + virtual void EndRemoteDrawing() + {} + virtual void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget, + LayoutDeviceIntRegion& aInvalidRegion) + { + EndRemoteDrawing(); + } + + /** + * Called when shutting down the LayerManager to clean-up any cached resources. + * + * Always called from the compositing thread. + */ + virtual void CleanupWindowEffects() + {} + + /** + * A hook for the widget to prepare a Compositor, during the latter's initialization. + * + * If this method returns true, it means that the widget will be able to + * present frames from the compoositor. + * + * Returning false will cause the compositor's initialization to fail, and + * a different compositor backend will be used (if any). + */ + virtual bool InitCompositor(layers::Compositor* aCompositor) { + return true; + } + + /** + * Return the size of the drawable area of the widget. + */ + virtual LayoutDeviceIntSize GetClientSize() = 0; + + /** + * Return the internal format of the default framebuffer for this + * widget. + */ + virtual uint32_t GetGLFrameBufferFormat(); + + /** + * If this widget has a more efficient composer available for its + * native framebuffer, return it. + * + * This can be called from a non-main thread, but that thread must + * hold a strong reference to this. + */ + virtual layers::Composer2D* GetComposer2D() { + return nullptr; + } + + /* + * Access the underlying nsIWidget. This method will be removed when the compositor no longer + * depends on nsIWidget on any platform. + */ + virtual nsIWidget* RealWidget() = 0; + + /** + * Clean up any resources used by Start/EndRemoteDrawing. + * + * Called by BasicCompositor on the compositor thread for OMTC drawing + * when the compositor is destroyed. + */ + virtual void CleanupRemoteDrawing(); + + /** + * Create a backbuffer for the software compositor. + */ + virtual already_AddRefed<gfx::DrawTarget> + CreateBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget, + const LayoutDeviceIntRect& aRect, + const LayoutDeviceIntRect& aClearRect); + +protected: + virtual ~CompositorWidgetProxy(); + +private: + // Back buffer of BasicCompositor + RefPtr<gfx::DrawTarget> mLastBackBuffer; +}; + +// This version of CompositorWidgetProxy implements a wrapper around +// nsBaseWidget. +class CompositorWidgetProxyWrapper : public CompositorWidgetProxy +{ +public: + explicit CompositorWidgetProxyWrapper(nsBaseWidget* aWidget); + + virtual bool PreRender(layers::LayerManagerComposite* aManager) override; + virtual void PostRender(layers::LayerManagerComposite* aManager) override; + virtual void DrawWindowUnderlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) override; + virtual void DrawWindowOverlay(layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) override; + virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override; + virtual already_AddRefed<gfx::DrawTarget> + StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + layers::BufferMode* aBufferMode) override; + virtual void EndRemoteDrawing() override; + virtual void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget, + LayoutDeviceIntRegion& aInvalidRegion) override; + virtual void CleanupRemoteDrawing() override; + virtual void CleanupWindowEffects() override; + virtual bool InitCompositor(layers::Compositor* aCompositor) override; + virtual LayoutDeviceIntSize GetClientSize() override; + virtual uint32_t GetGLFrameBufferFormat() override; + virtual layers::Composer2D* GetComposer2D() override; + + // If you can override this method, inherit from CompositorWidgetProxy instead. + nsIWidget* RealWidget() override; + +private: + nsBaseWidget* mWidget; +}; + +} // namespace widget +} // namespace mozilla + +#endif diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index 59aac521f2..bc9db9ba07 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -33,6 +33,7 @@ #include "mozilla/gfx/Logging.h" #include "gfxPrefs.h" #include "gfxPlatform.h" +#include "gfxConfig.h" #if defined(MOZ_CRASHREPORTER) #include "nsExceptionHandler.h" @@ -1276,6 +1277,30 @@ GetLayersBackendName(layers::LayersBackend aBackend) } } +static inline bool +SetJSPropertyString(JSContext* aCx, JS::Handle<JSObject*> aObj, + const char* aProp, const char* aString) +{ + JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, aString)); + if (!str) { + return false; + } + + JS::Rooted<JS::Value> val(aCx, JS::StringValue(str)); + return JS_SetProperty(aCx, aObj, aProp, val); +} + +template <typename T> +static inline bool +AppendJSElement(JSContext* aCx, JS::Handle<JSObject*> aObj, const T& aValue) +{ + uint32_t index; + if (!JS_GetArrayLength(aCx, aObj, &index)) { + return false; + } + return JS_SetElement(aCx, aObj, index, aValue); +} + nsresult GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) { @@ -1289,11 +1314,7 @@ GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) ? gfxPlatform::GetPlatform()->GetCompositorBackend() : layers::LayersBackend::LAYERS_NONE; const char* backendName = GetLayersBackendName(backend); - { - JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, backendName)); - JS::Rooted<JS::Value> val(aCx, StringValue(str)); - JS_SetProperty(aCx, obj, "compositor", val); - } + SetJSPropertyString(aCx, obj, "compositor", backendName); // If graphics isn't initialized yet, just stop now. if (!gfxPlatform::Initialized()) { @@ -1304,6 +1325,114 @@ GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) return NS_OK; } +nsresult GfxInfoBase::GetFeatureLog(JSContext* aCx, JS::MutableHandle<JS::Value> aOut) +{ + JS::Rooted<JSObject*> containerObj(aCx, JS_NewPlainObject(aCx)); + if (!containerObj) { + return NS_ERROR_OUT_OF_MEMORY; + } + aOut.setObject(*containerObj); + + JS::Rooted<JSObject*> featureArray(aCx, JS_NewArrayObject(aCx, 0)); + if (!featureArray) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // Collect features. + gfxConfig::ForEachFeature([&](const char* aName, + const char* aDescription, + FeatureState& aFeature) -> void { + JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); + if (!obj) { + return; + } + if (!SetJSPropertyString(aCx, obj, "name", aName) || + !SetJSPropertyString(aCx, obj, "description", aDescription) || + !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aFeature.GetValue()))) + { + return; + } + + JS::Rooted<JS::Value> log(aCx); + if (!BuildFeatureStateLog(aCx, aFeature, &log)) { + return; + } + if (!JS_SetProperty(aCx, obj, "log", log)) { + return; + } + + if (!AppendJSElement(aCx, featureArray, obj)) { + return; + } + }); + + JS::Rooted<JSObject*> fallbackArray(aCx, JS_NewArrayObject(aCx, 0)); + if (!fallbackArray) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // Collect fallbacks. + gfxConfig::ForEachFallback([&](const char* aName, const char* aMessage) -> void { + JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); + if (!obj) { + return; + } + + if (!SetJSPropertyString(aCx, obj, "name", aName) || + !SetJSPropertyString(aCx, obj, "message", aMessage)) + { + return; + } + + if (!AppendJSElement(aCx, fallbackArray, obj)) { + return; + } + }); + + JS::Rooted<JS::Value> val(aCx); + + val = JS::ObjectValue(*featureArray); + JS_SetProperty(aCx, containerObj, "features", val); + + val = JS::ObjectValue(*fallbackArray); + JS_SetProperty(aCx, containerObj, "fallbacks", val); + + return NS_OK; +} + +bool +GfxInfoBase::BuildFeatureStateLog(JSContext* aCx, const FeatureState& aFeature, + JS::MutableHandle<JS::Value> aOut) +{ + JS::Rooted<JSObject*> log(aCx, JS_NewArrayObject(aCx, 0)); + if (!log) { + return false; + } + aOut.setObject(*log); + + aFeature.ForEachStatusChange([&](const char* aType, + FeatureStatus aStatus, + const char* aMessage) -> void { + JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx)); + if (!obj) { + return; + } + + if (!SetJSPropertyString(aCx, obj, "type", aType) || + !SetJSPropertyString(aCx, obj, "status", FeatureStatusToString(aStatus)) || + (aMessage && !SetJSPropertyString(aCx, obj, "message", aMessage))) + { + return; + } + + if (!AppendJSElement(aCx, log, obj)) { + return; + } + }); + + return true; +} + void GfxInfoBase::DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut) { diff --git a/widget/GfxInfoBase.h b/widget/GfxInfoBase.h index 1629fddb4f..7ba871866a 100644 --- a/widget/GfxInfoBase.h +++ b/widget/GfxInfoBase.h @@ -17,6 +17,7 @@ #include "nsString.h" #include "GfxInfoCollector.h" #include "gfxTelemetry.h" +#include "gfxFeature.h" #include "nsIGfxInfoDebug.h" #include "mozilla/Mutex.h" #include "js/Value.h" @@ -54,6 +55,7 @@ class GfxInfoBase : public nsIGfxInfo, NS_IMETHOD_(void) LogFailure(const nsACString &failure) override; NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override; NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override; + NS_IMETHOD GetFeatureLog(JSContext*, JS::MutableHandle<JS::Value>) override; // Initialization function. If you override this, you must call this class's // version of Init first. @@ -117,6 +119,9 @@ class GfxInfoBase : public nsIGfxInfo, void EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo); + bool BuildFeatureStateLog(JSContext* aCx, const gfx::FeatureState& aFeature, + JS::MutableHandle<JS::Value> aOut); + Mutex mMutex; }; diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index fcbbfe1415..e777411661 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -274,6 +274,12 @@ class PuppetWidget : public nsBaseWidget virtual nsresult NotifyIMEInternal( const IMENotification& aIMENotification) override; + // PuppetWidgets do not create compositors. + widget::CompositorWidgetProxy* NewCompositorWidgetProxy() override { + MOZ_ASSERT_UNREACHABLE("PuppetWidgets should not have widget proxies"); + return nullptr; + } + private: nsresult Paint(); diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 68ad862f93..1419ffb405 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2672,7 +2672,6 @@ static void MakeRegionsNonOverlapping(Region& aFirst, Regions& ... aRest) void nsChildView::CleanupRemoteDrawing() { - nsBaseWidget::CleanupRemoteDrawing(); mBasicCompositorImage = nullptr; mCornerMaskImage = nullptr; mResizerImage = nullptr; diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 624394055f..0bd520e7fd 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -375,6 +375,11 @@ class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa void SetPopupWindowLevel(); NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override; + + CompositorWidgetProxy* NewCompositorWidgetProxy() override { + return nullptr; + } + protected: virtual ~nsCocoaWindow(); diff --git a/widget/moz.build b/widget/moz.build index 7c07803842..244515744a 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -87,6 +87,7 @@ XPIDL_SOURCES += [ XPIDL_MODULE = 'widget' EXPORTS += [ + 'CompositorWidgetProxy.h', 'ContentHelper.h', 'GfxDriverInfo.h', 'GfxInfoBase.h', @@ -135,6 +136,7 @@ EXPORTS.mozilla.widget += [ ] UNIFIED_SOURCES += [ + 'CompositorWidgetProxy.cpp', 'ContentCache.cpp', 'ContentHelper.cpp', 'GfxDriverInfo.cpp', diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 4670022a40..ed5865644f 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -69,6 +69,7 @@ #ifdef ACCESSIBILITY #include "nsAccessibilityService.h" #endif +#include "gfxConfig.h" #ifdef DEBUG #include "nsIObserver.h" @@ -928,13 +929,28 @@ nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup() bool nsBaseWidget::ComputeShouldAccelerate() { - return gfxPlatform::GetPlatform()->ShouldUseLayersAcceleration(); + return gfx::gfxConfig::IsEnabled(gfx::Feature::HW_COMPOSITING); } -CompositorBridgeParent* nsBaseWidget::NewCompositorBridgeParent(int aSurfaceWidth, - int aSurfaceHeight) +bool +nsBaseWidget::UseAPZ() +{ + return (gfxPlatform::AsyncPanZoomEnabled() && + (WindowType() == eWindowType_toplevel || WindowType() == eWindowType_child)); +} + +CompositorBridgeParent* +nsBaseWidget::NewCompositorBridgeParent(int aSurfaceWidth, + int aSurfaceHeight) { - return new CompositorBridgeParent(this, false, aSurfaceWidth, aSurfaceHeight); + if (!mCompositorWidgetProxy) { + mCompositorWidgetProxy = NewCompositorWidgetProxy(); + } + return new CompositorBridgeParent(mCompositorWidgetProxy, + GetDefaultScale(), + UseAPZ(), + false, + aSurfaceWidth, aSurfaceHeight); } void nsBaseWidget::CreateCompositor() @@ -1371,46 +1387,22 @@ CompositorBridgeChild* nsBaseWidget::GetRemoteRenderer() return mCompositorBridgeChild; } -already_AddRefed<mozilla::gfx::DrawTarget> +already_AddRefed<gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing() { return nullptr; } -void -nsBaseWidget::CleanupRemoteDrawing() -{ - mLastBackBuffer = nullptr; -} - -already_AddRefed<mozilla::gfx::DrawTarget> -nsBaseWidget::CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget, - const LayoutDeviceIntRect& aRect, - const LayoutDeviceIntRect& aClearRect) -{ - MOZ_ASSERT(aScreenTarget); - gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; - gfx::IntSize size = aRect.ToUnknownRect().Size(); - gfx::IntSize clientSize(GetClientSize().ToUnknownSize()); - - RefPtr<gfx::DrawTarget> target; - // Re-use back buffer if possible - if (mLastBackBuffer && - mLastBackBuffer->GetBackendType() == aScreenTarget->GetBackendType() && - mLastBackBuffer->GetFormat() == format && - size <= mLastBackBuffer->GetSize() && - mLastBackBuffer->GetSize() <= clientSize) { - target = mLastBackBuffer; - target->SetTransform(gfx::Matrix()); - if (!aClearRect.IsEmpty()) { - gfx::IntRect clearRect = aClearRect.ToUnknownRect() - aRect.ToUnknownRect().TopLeft(); - target->ClearRect(gfx::Rect(clearRect.x, clearRect.y, clearRect.width, clearRect.height)); - } - } else { - target = aScreenTarget->CreateSimilarDrawTarget(size, format); - mLastBackBuffer = target; - } - return target.forget(); +uint32_t +nsBaseWidget::GetGLFrameBufferFormat() +{ + return LOCAL_GL_RGBA; +} + +mozilla::widget::CompositorWidgetProxy* +nsBaseWidget::NewCompositorWidgetProxy() +{ + return new mozilla::widget::CompositorWidgetProxyWrapper(this); } //------------------------------------------------------------------------- @@ -1695,12 +1687,6 @@ nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent) return NS_ERROR_NOT_IMPLEMENTED; } -uint32_t -nsBaseWidget::GetGLFrameBufferFormat() -{ - return LOCAL_GL_RGBA; -} - void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints) { mSizeConstraints = aConstraints; diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 5b91435842..b8442c1a4e 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -21,6 +21,7 @@ #include "nsIWidgetListener.h" #include "nsPIDOMWindow.h" #include "nsWeakReference.h" +#include "CompositorWidgetProxy.h" #include <algorithm> class nsIContent; class nsAutoRollup; @@ -92,6 +93,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference { friend class nsAutoRollup; friend class DispatchWheelEventOnMainThread; + friend class mozilla::widget::CompositorWidgetProxyWrapper; protected: typedef base::Thread Thread; @@ -108,6 +110,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference typedef mozilla::CSSIntRect CSSIntRect; typedef mozilla::CSSRect CSSRect; typedef mozilla::ScreenRotation ScreenRotation; + typedef mozilla::widget::CompositorWidgetProxy CompositorWidgetProxy; virtual ~nsBaseWidget(); @@ -165,17 +168,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference virtual void CreateCompositor(); virtual void CreateCompositor(int aWidth, int aHeight); virtual void PrepareWindowEffects() override {} - virtual void CleanupWindowEffects() override {} - virtual bool PreRender(LayerManagerComposite* aManager) override { return true; } - virtual void PostRender(LayerManagerComposite* aManager) override {} - virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {} - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {} - virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() override; - virtual void EndRemoteDrawing() override { }; - virtual void CleanupRemoteDrawing() override; - virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget, - const LayoutDeviceIntRect& aRect, - const LayoutDeviceIntRect& aClearRect) override; virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override {} NS_IMETHOD SetModal(bool aModal) override; virtual uint32_t GetMaxTouchPoints() const override; @@ -312,8 +304,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override = 0; - virtual uint32_t GetGLFrameBufferFormat() override; - virtual const SizeConstraints GetSizeConstraints() override; virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override; @@ -347,8 +337,50 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference void Shutdown(); + // Return a new CompositorWidgetProxy for this widget. + virtual CompositorWidgetProxy* NewCompositorWidgetProxy(); + protected: + // These are methods for CompositorWidgetProxyWrapper, and should only be + // accessed from that class. Derived widgets can choose which methods to + // implement, or none if supporting out-of-process compositing. + virtual bool PreRender(mozilla::layers::LayerManagerComposite* aManager) { + return true; + } + virtual void PostRender(mozilla::layers::LayerManagerComposite* aManager) + {} + virtual void DrawWindowUnderlay(mozilla::layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) + {} + virtual void DrawWindowOverlay(mozilla::layers::LayerManagerComposite* aManager, + LayoutDeviceIntRect aRect) + {} + virtual already_AddRefed<DrawTarget> StartRemoteDrawing(); + virtual already_AddRefed<DrawTarget> + StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) + { + return StartRemoteDrawing(); + } + virtual void EndRemoteDrawing() + {} + virtual void EndRemoteDrawingInRegion(DrawTarget* aDrawTarget, + LayoutDeviceIntRegion& aInvalidRegion) + { + EndRemoteDrawing(); + } + virtual void CleanupRemoteDrawing() + {} + virtual void CleanupWindowEffects() + {} + virtual bool InitCompositor(mozilla::layers::Compositor* aCompositor) { + return true; + } + virtual uint32_t GetGLFrameBufferFormat(); + virtual mozilla::layers::Composer2D* GetComposer2D() { + return nullptr; + } +protected: void ResolveIconName(const nsAString &aIconName, const nsAString &aIconSuffix, nsIFile **aResult); @@ -489,11 +521,13 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference nsIDocument* GetDocument() const; - void EnsureTextEventDispatcher(); + void EnsureTextEventDispatcher(); // Notify the compositor that a device reset has occurred. void OnRenderingDeviceReset(); + bool UseAPZ(); + protected: /** * Starts the OMTC compositor destruction sequence. @@ -519,8 +553,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference RefPtr<APZCTreeManager> mAPZC; RefPtr<GeckoContentController> mRootContentController; RefPtr<APZEventState> mAPZEventState; - // Back buffer of BasicCompositor - RefPtr<DrawTarget> mLastBackBuffer; SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback; RefPtr<WidgetShutdownObserver> mShutdownObserver; RefPtr<TextEventDispatcher> mTextEventDispatcher; @@ -536,6 +568,8 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference nsPopupType mPopupType; SizeConstraints mSizeConstraints; + RefPtr<CompositorWidgetProxy> mCompositorWidgetProxy; + bool mUpdateCursor; bool mUseAttachedEvents; bool mIMEHasFocus; diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl index df596695f5..d3358e8109 100644 --- a/widget/nsIGfxInfo.idl +++ b/widget/nsIGfxInfo.idl @@ -159,6 +159,35 @@ interface nsIGfxInfo : nsISupports [implicit_jscontext] jsval getInfo(); + // Return an object describing all features that have been configured: + // + // "features": [ + // // For each feature: + // { + // "name": <string>, + // "description": <string>, + // "status": <string>, + // "log": [ + // // One or more log entries, the first denotes the default value. + // { + // "type": <string>, // "base", "user", "env", or "runtime" + // "status": <string>, + // "message": <string> // Set unless type is "base" and status is "available". + // } + // ] + // } + // ] + // "fallbacks": [ + // // For each workaround: + // { + // "name:" <string>, + // "description": <string>, + // "message": <string> + // ] + // } + [implicit_jscontext] + jsval getFeatureLog(); + // Returns an object containing information about graphics features. It is // intended to be directly included into the Telemetry environment. // diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index caf5e78f0a..85e4210793 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -322,7 +322,8 @@ struct AutoObserverNotifier { * The base class for all the widgets. It provides the interface for * all basic and necessary functionality. */ -class nsIWidget : public nsISupports { +class nsIWidget : public nsISupports +{ protected: typedef mozilla::dom::TabChild TabChild; @@ -1217,100 +1218,6 @@ class nsIWidget : public nsISupports { */ virtual void PrepareWindowEffects() = 0; - /** - * Called when shutting down the LayerManager to clean-up any cached resources. - * - * Always called from the compositing thread, which may be the main-thread if - * OMTC is not enabled. - */ - virtual void CleanupWindowEffects() = 0; - - /** - * Called before rendering using OMTC. Returns false when the widget is - * not ready to be rendered (for example while the window is closed). - * - * Always called from the compositing thread, which may be the main-thread if - * OMTC is not enabled. - */ - virtual bool PreRender(LayerManagerComposite* aManager) = 0; - - /** - * Called after rendering using OMTC. Not called when rendering was - * cancelled by a negative return value from PreRender. - * - * Always called from the compositing thread, which may be the main-thread if - * OMTC is not enabled. - */ - virtual void PostRender(LayerManagerComposite* aManager) = 0; - - /** - * Called before the LayerManager draws the layer tree. - * - * Always called from the compositing thread. - */ - virtual void DrawWindowUnderlay(LayerManagerComposite* aManager, - LayoutDeviceIntRect aRect) = 0; - - /** - * Called after the LayerManager draws the layer tree - * - * Always called from the compositing thread. - */ - virtual void DrawWindowOverlay(LayerManagerComposite* aManager, - LayoutDeviceIntRect aRect) = 0; - - /** - * Return a DrawTarget for the window which can be composited into. - * - * Called by BasicCompositor on the compositor thread for OMTC drawing - * before each composition. - * - * The window may specify its buffer mode. If unspecified, it is assumed - * to require double-buffering. - */ - virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0; - virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, - mozilla::layers::BufferMode* aBufferMode) { - return StartRemoteDrawing(); - } - - /** - * Ensure that what was painted into the DrawTarget returned from - * StartRemoteDrawing reaches the screen. - * - * Called by BasicCompositor on the compositor thread for OMTC drawing - * after each composition. - */ - virtual void EndRemoteDrawing() = 0; - virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aInvalidRegion) { - EndRemoteDrawing(); - } - - /** - * Clean up any resources used by Start/EndRemoteDrawing. - * - * Called by BasicCompositor on the compositor thread for OMTC drawing - * when the compositor is destroyed. - */ - virtual void CleanupRemoteDrawing() = 0; - - /** - * Create DrawTarget used as BackBuffer of the screen - */ - virtual already_AddRefed<mozilla::gfx::DrawTarget> CreateBackBufferDrawTarget(mozilla::gfx::DrawTarget* aScreenTarget, - const LayoutDeviceIntRect& aRect, - const LayoutDeviceIntRect& aClearRect) = 0; - - /** - * A hook for the widget to prepare a Compositor, during the latter's initialization. - * - * If this method returns true, it means that the widget will be able to - * present frames from the compoositor. - * Returning false will cause the compositor's initialization to fail, and - * a different compositor backend will be used (if any). - */ - virtual bool InitCompositor(mozilla::layers::Compositor*) { return true; } - /** * Called when Gecko knows which themed widgets exist in this window. * The passed array contains an entry for every themed widget of the right @@ -1909,12 +1816,6 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) = 0; - /** - * Return the internal format of the default framebuffer for this - * widget. - */ - virtual uint32_t GetGLFrameBufferFormat() { return 0; /*GL_NONE*/ } - /** * Return true if widget has it's own GL context */ @@ -1988,16 +1889,6 @@ class nsIWidget : public nsISupports { virtual CompositorBridgeChild* GetRemoteRenderer() { return nullptr; } - /** - * If this widget has a more efficient composer available for its - * native framebuffer, return it. - * - * This can be called from a non-main thread, but that thread must - * hold a strong reference to this. - */ - virtual Composer2D* GetComposer2D() - { return nullptr; } - /** * Some platforms (only cocoa right now) round widget coordinates to the * nearest even pixels (see bug 892994), this function allows us to diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index ab467d9e13..9cb3824c75 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -7,6 +7,7 @@ #include <windows.h> #include <setupapi.h> +#include "gfxConfig.h" #include "gfxWindowsPlatform.h" #include "GfxInfo.h" #include "GfxInfoWebGL.h" @@ -26,6 +27,7 @@ #endif using namespace mozilla; +using namespace mozilla::gfx; using namespace mozilla::widget; #ifdef DEBUG @@ -46,7 +48,7 @@ GfxInfo::GfxInfo() nsresult GfxInfo::GetD2DEnabled(bool *aEnabled) { - *aEnabled = gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D; + *aEnabled = gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend(); return NS_OK; } @@ -1260,7 +1262,7 @@ GfxInfo::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj) gfxWindowsPlatform* platform = gfxWindowsPlatform::GetPlatform(); - gfx::FeatureStatus d3d11 = platform->GetD3D11Status(); + gfx::FeatureStatus d3d11 = gfxConfig::GetValue(Feature::D3D11_COMPOSITING); if (!InitFeatureObject(aCx, aObj, "d3d11", d3d11, &obj)) { return; } @@ -1274,11 +1276,20 @@ GfxInfo::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj) val = JS::BooleanValue(platform->CompositorD3D11TextureSharingWorks()); JS_SetProperty(aCx, obj, "textureSharing", val); - val = JS::BooleanValue(!platform->CanUseDirect3D11()); + bool blacklisted = false; + if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) { + int32_t status; + nsCString discardFailureId; + if (SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, discardFailureId, &status))) { + blacklisted = (status != nsIGfxInfo::FEATURE_STATUS_OK); + } + } + + val = JS::BooleanValue(blacklisted); JS_SetProperty(aCx, obj, "blacklisted", val); } - gfx::FeatureStatus d2d = platform->GetD2D1Status(); + gfx::FeatureStatus d2d = gfxConfig::GetValue(Feature::DIRECT2D); if (!InitFeatureObject(aCx, aObj, "d2d", d2d, &obj)) { return; } diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index aae84e587b..c65c90cc48 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -138,6 +138,8 @@ #include "nsThemeConstants.h" #include "nsBidiKeyboard.h" #include "nsIFrame.h" +#include "nsThemeConstants.h" +#include "gfxConfig.h" #include "nsIGfxInfo.h" #include "nsUXThemeConstants.h" @@ -3021,6 +3023,27 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen) return rv; } +HDC nsWindow::GetWindowSurface() +{ +#ifdef MOZ_XUL + return eTransparencyTransparent == mTransparencyMode + ? mMemoryDC + : ::GetDC(mWnd); +#else + return ::GetDC(mWnd); +#endif +} + +void nsWindow::FreeWindowSurface(HDC dc) +{ +#ifdef MOZ_XUL + if (eTransparencyTransparent != mTransparencyMode) + ::ReleaseDC(mWnd, dc); +#else + ::ReleaseDC(mWnd, dc); +#endif +} + /************************************************************** * * SECTION: Native data storage @@ -3057,14 +3080,8 @@ void* nsWindow::GetNativeData(uint32_t aDataType) case NS_NATIVE_SHAREABLE_WINDOW: return (void*) WinUtils::GetTopLevelHWND(mWnd); case NS_NATIVE_GRAPHIC: - // XXX: This is sleezy!! Remember to Release the DC after using it! -#ifdef MOZ_XUL - return (void*)(eTransparencyTransparent == mTransparencyMode) ? - mMemoryDC : ::GetDC(mWnd); -#else - return (void*)::GetDC(mWnd); -#endif - + MOZ_ASSERT_UNREACHABLE("Not supported on Windows:"); + return nullptr; case NS_RAW_NATIVE_IME_CONTEXT: { void* pseudoIMEContext = GetPseudoIMEContext(); if (pseudoIMEContext) { @@ -3120,13 +3137,6 @@ void nsWindow::FreeNativeData(void * data, uint32_t aDataType) switch (aDataType) { case NS_NATIVE_GRAPHIC: -#ifdef MOZ_XUL - if (eTransparencyTransparent != mTransparencyMode) - ::ReleaseDC(mWnd, (HDC)data); -#else - ::ReleaseDC(mWnd, (HDC)data); -#endif - break; case NS_NATIVE_WIDGET: case NS_NATIVE_WINDOW: case NS_NATIVE_PLUGIN_PORT: @@ -3519,11 +3529,7 @@ already_AddRefed<mozilla::gfx::DrawTarget> nsWindow::StartRemoteDrawing() { MOZ_ASSERT(!mCompositeDC); - NS_ASSERTION(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) || - IsRenderMode(gfxWindowsPlatform::RENDER_GDI), - "Unexpected render mode for remote drawing"); - - HDC dc = (HDC)GetNativeData(NS_NATIVE_GRAPHIC); + HDC dc = GetWindowSurface(); RefPtr<gfxASurface> surf; if (mTransparencyMode == eTransparencyTransparent) { @@ -3547,7 +3553,7 @@ nsWindow::StartRemoteDrawing() mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height); if (size.width <= 0 || size.height <= 0) { if (dc) { - FreeNativeData(dc, NS_NATIVE_GRAPHIC); + FreeWindowSurface(dc); } return nullptr; } @@ -3562,12 +3568,12 @@ void nsWindow::EndRemoteDrawing() { if (mTransparencyMode == eTransparencyTransparent) { - MOZ_ASSERT(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) + MOZ_ASSERT(gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend() || mTransparentSurface); UpdateTranslucentWindow(); } if (mCompositeDC) { - FreeNativeData(mCompositeDC, NS_NATIVE_GRAPHIC); + FreeWindowSurface(mCompositeDC); } mCompositeDC = nullptr; } @@ -6399,8 +6405,7 @@ nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations) w->Move(configuration.mBounds.x, configuration.mBounds.y); - if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == - gfxWindowsPlatform::RENDER_DIRECT2D || + if (gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend() || GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_BASIC) { // XXX - Workaround for Bug 587508. This will invalidate the part of the // plugin window that might be touched by moving content somehow. The @@ -6630,11 +6635,10 @@ nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() { // done just once. // Check for Direct2D first. sHasBogusPopupsDropShadowOnMultiMonitor = - gfxWindowsPlatform::GetPlatform()->GetRenderMode() == - gfxWindowsPlatform::RENDER_DIRECT2D ? TRI_TRUE : TRI_FALSE; + gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend() ? TRI_TRUE : TRI_FALSE; if (!sHasBogusPopupsDropShadowOnMultiMonitor) { // Otherwise check if Direct3D 9 may be used. - if (gfxPlatform::GetPlatform()->ShouldUseLayersAcceleration() && + if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING) && !gfxPrefs::LayersPreferOpenGL()) { nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); @@ -6644,7 +6648,7 @@ nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() { if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, discardFailureId, &status))) { if (status == nsIGfxInfo::FEATURE_STATUS_OK || - gfxPrefs::LayersAccelerationForceEnabled()) + gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { sHasBogusPopupsDropShadowOnMultiMonitor = TRI_TRUE; } diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index 5d431ea9d6..5791450db6 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -462,6 +462,9 @@ class nsWindow : public nsWindowBase protected: #endif // MOZ_XUL + HDC GetWindowSurface(); + void FreeWindowSurface(HDC dc); + static bool IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult); void IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam); @@ -477,7 +480,7 @@ class nsWindow : public nsWindowBase static void ActivateOtherWindowHelper(HWND aWnd); void ClearCachedResources(); nsIWidgetListener* GetPaintListener(); - static bool IsRenderMode(gfxWindowsPlatform::RenderMode aMode); + virtual bool PreRender(LayerManagerComposite*) override; virtual void PostRender(LayerManagerComposite*) override; diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 3693f866df..96dc80b869 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -87,22 +87,6 @@ static IconMetrics sIconMetrics[] = { {SM_CXICON, SM_CYICON, 32} // regular icon }; -/************************************************************** - ************************************************************** - ** - ** BLOCK: nsWindowGfx impl. - ** - ** Misc. graphics related utilities. - ** - ************************************************************** - **************************************************************/ - -/* static */ bool -nsWindow::IsRenderMode(gfxWindowsPlatform::RenderMode rmode) -{ - return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == rmode; -} - /************************************************************** ************************************************************** ** @@ -325,19 +309,16 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) #if defined(MOZ_XUL) // don't support transparency for non-GDI rendering, for now - if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || - IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) && - eTransparencyTransparent == mTransparencyMode) { - if (mTransparentSurface == nullptr) + if (eTransparencyTransparent == mTransparencyMode) { + if (mTransparentSurface == nullptr) { SetupTranslucentWindowMemoryBitmap(mTransparencyMode); + } targetSurface = mTransparentSurface; } #endif RefPtr<gfxWindowsSurface> targetSurfaceWin; - if (!targetSurface && - (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || - IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))) + if (!targetSurface) { uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : gfxWindowsSurface::FLAG_IS_TRANSPARENT; @@ -345,32 +326,6 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) targetSurface = targetSurfaceWin; } - RefPtr<gfxImageSurface> targetSurfaceImage; - if (!targetSurface && - (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32) || - IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24))) - { - IntSize surfaceSize(ps.rcPaint.right - ps.rcPaint.left, - ps.rcPaint.bottom - ps.rcPaint.top); - - if (!EnsureSharedSurfaceSize(surfaceSize)) { - NS_ERROR("Couldn't allocate a shared image surface!"); - return false; - } - - // don't use the shared surface directly; instead, create a new one - // that just reuses its buffer. - targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(), - surfaceSize, - surfaceSize.width * 4, - SurfaceFormat::X8R8G8B8_UINT32); - - if (targetSurfaceImage && !targetSurfaceImage->CairoStatus()) { - targetSurfaceImage->SetDeviceOffset(gfxPoint(-ps.rcPaint.left, -ps.rcPaint.top)); - targetSurface = targetSurfaceImage; - } - } - if (!targetSurface) { NS_ERROR("Invalid RenderMode!"); return false; @@ -389,27 +344,24 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) // don't need to double buffer with anything but GDI BufferMode doubleBuffering = mozilla::layers::BufferMode::BUFFER_NONE; - if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || - IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) { #ifdef MOZ_XUL - switch (mTransparencyMode) { - case eTransparencyGlass: - case eTransparencyBorderlessGlass: - default: - // If we're not doing translucency, then double buffer - doubleBuffering = mozilla::layers::BufferMode::BUFFERED; - break; - case eTransparencyTransparent: - // If we're rendering with translucency, we're going to be - // rendering the whole window; make sure we clear it first - dt->ClearRect(Rect(0.f, 0.f, - dt->GetSize().width, dt->GetSize().height)); - break; - } + switch (mTransparencyMode) { + case eTransparencyGlass: + case eTransparencyBorderlessGlass: + default: + // If we're not doing translucency, then double buffer + doubleBuffering = mozilla::layers::BufferMode::BUFFERED; + break; + case eTransparencyTransparent: + // If we're rendering with translucency, we're going to be + // rendering the whole window; make sure we clear it first + dt->ClearRect(Rect(0.f, 0.f, + dt->GetSize().width, dt->GetSize().height)); + break; + } #else - doubleBuffering = mozilla::layers::BufferMode::BUFFERED; + doubleBuffering = mozilla::layers::BufferMode::BUFFERED; #endif - } RefPtr<gfxContext> thebesContext = gfxContext::ForDrawTarget(dt); MOZ_ASSERT(thebesContext); // already checked draw target above @@ -422,106 +374,13 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) } #ifdef MOZ_XUL - if ((IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || - IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D))&& - eTransparencyTransparent == mTransparencyMode) { + if (eTransparencyTransparent == mTransparencyMode) { // Data from offscreen drawing surface was copied to memory bitmap of transparent // bitmap. Now it can be read from memory bitmap to apply alpha channel and after // that displayed on the screen. UpdateTranslucentWindow(); - } else -#endif - - if (result) { - if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24) || - IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32)) - { - IntSize surfaceSize = targetSurfaceImage->GetSize(); - - // Just blit this directly - BITMAPINFOHEADER bi; - memset(&bi, 0, sizeof(BITMAPINFOHEADER)); - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = surfaceSize.width; - bi.biHeight = - surfaceSize.height; - bi.biPlanes = 1; - bi.biBitCount = 32; - bi.biCompression = BI_RGB; - - if (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24)) { - // On Windows CE/Windows Mobile, 24bpp packed-pixel sources - // seem to be far faster to blit than 32bpp (see bug 484864). - // So, convert the bits to 24bpp by stripping out the unused - // alpha byte. 24bpp DIBs also have scanlines that are 4-byte - // aligned though, so that must be taken into account. - int srcstride = surfaceSize.width*4; - int dststride = surfaceSize.width*3; - dststride = (dststride + 3) & ~3; - - // Convert in place - for (int j = 0; j < surfaceSize.height; ++j) { - unsigned int *src = (unsigned int*) (targetSurfaceImage->Data() + j*srcstride); - unsigned int *dst = (unsigned int*) (targetSurfaceImage->Data() + j*dststride); - - // go 4 pixels at a time, since each 4 pixels - // turns into 3 DWORDs when converted into BGR: - // BGRx BGRx BGRx BGRx -> BGRB GRBG RBGR - // - // However, since we're dealing with little-endian ints, this is actually: - // xRGB xrgb xRGB xrgb -> bRGB GBrg rgbR - int width_left = surfaceSize.width; - while (width_left >= 4) { - unsigned int a = *src++; - unsigned int b = *src++; - unsigned int c = *src++; - unsigned int d = *src++; - - *dst++ = (a & 0x00ffffff) | (b << 24); - *dst++ = ((b & 0x00ffff00) >> 8) | (c << 16); - *dst++ = ((c & 0x00ff0000) >> 16) | (d << 8); - - width_left -= 4; - } - - // then finish up whatever number of pixels are left, - // using bytes. - unsigned char *bsrc = (unsigned char*) src; - unsigned char *bdst = (unsigned char*) dst; - switch (width_left) { - case 3: - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - bsrc++; - case 2: - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - bsrc++; - case 1: - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - *bdst++ = *bsrc++; - bsrc++; - case 0: - break; - } - } - - bi.biBitCount = 24; - } - - StretchDIBits(hDC, - ps.rcPaint.left, ps.rcPaint.top, - surfaceSize.width, surfaceSize.height, - 0, 0, - surfaceSize.width, surfaceSize.height, - targetSurfaceImage->Data(), - (BITMAPINFO*) &bi, - DIB_RGB_COLORS, - SRCCOPY); - } } +#endif } break; case LayersBackend::LAYERS_CLIENT: