electron_api_web_contents.cc 166 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/api/electron_api_web_contents.h"
  5. #include <limits>
  6. #include <list>
  7. #include <memory>
  8. #include <optional>
  9. #include <set>
  10. #include <string>
  11. #include <string_view>
  12. #include <utility>
  13. #include <vector>
  14. #include "base/base64.h"
  15. #include "base/containers/contains.h"
  16. #include "base/containers/fixed_flat_map.h"
  17. #include "base/containers/id_map.h"
  18. #include "base/files/file_util.h"
  19. #include "base/json/json_reader.h"
  20. #include "base/no_destructor.h"
  21. #include "base/strings/strcat.h"
  22. #include "base/strings/utf_string_conversions.h"
  23. #include "base/task/current_thread.h"
  24. #include "base/threading/scoped_blocking_call.h"
  25. #include "base/values.h"
  26. #include "chrome/browser/browser_process.h"
  27. #include "chrome/browser/devtools/devtools_eye_dropper.h"
  28. #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
  29. #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
  30. #include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
  31. #include "chrome/common/pref_names.h"
  32. #include "components/embedder_support/user_agent_utils.h"
  33. #include "components/input/native_web_keyboard_event.h"
  34. #include "components/prefs/pref_service.h"
  35. #include "components/prefs/scoped_user_pref_update.h"
  36. #include "components/security_state/content/content_utils.h"
  37. #include "components/security_state/core/security_state.h"
  38. #include "content/browser/renderer_host/frame_tree_node.h" // nogncheck
  39. #include "content/browser/renderer_host/navigation_controller_impl.h" // nogncheck
  40. #include "content/browser/renderer_host/render_frame_host_manager.h" // nogncheck
  41. #include "content/browser/renderer_host/render_widget_host_impl.h" // nogncheck
  42. #include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck
  43. #include "content/browser/web_contents/web_contents_impl.h" // nogncheck
  44. #include "content/public/browser/child_process_security_policy.h"
  45. #include "content/public/browser/context_menu_params.h"
  46. #include "content/public/browser/desktop_media_id.h"
  47. #include "content/public/browser/desktop_streams_registry.h"
  48. #include "content/public/browser/download_request_utils.h"
  49. #include "content/public/browser/favicon_status.h"
  50. #include "content/public/browser/file_select_listener.h"
  51. #include "content/public/browser/keyboard_event_processing_result.h"
  52. #include "content/public/browser/navigation_details.h"
  53. #include "content/public/browser/navigation_entry.h"
  54. #include "content/public/browser/navigation_entry_restore_context.h"
  55. #include "content/public/browser/navigation_handle.h"
  56. #include "content/public/browser/render_frame_host.h"
  57. #include "content/public/browser/render_process_host.h"
  58. #include "content/public/browser/render_view_host.h"
  59. #include "content/public/browser/render_widget_host.h"
  60. #include "content/public/browser/render_widget_host_view.h"
  61. #include "content/public/browser/service_worker_context.h"
  62. #include "content/public/browser/site_instance.h"
  63. #include "content/public/browser/storage_partition.h"
  64. #include "content/public/browser/visibility.h"
  65. #include "content/public/browser/web_contents.h"
  66. #include "content/public/common/referrer_type_converters.h"
  67. #include "content/public/common/result_codes.h"
  68. #include "content/public/common/webplugininfo.h"
  69. #include "electron/buildflags/buildflags.h"
  70. #include "electron/mas.h"
  71. #include "gin/arguments.h"
  72. #include "gin/data_object_builder.h"
  73. #include "gin/handle.h"
  74. #include "gin/object_template_builder.h"
  75. #include "gin/wrappable.h"
  76. #include "media/base/mime_util.h"
  77. #include "mojo/public/cpp/bindings/associated_remote.h"
  78. #include "mojo/public/cpp/bindings/pending_receiver.h"
  79. #include "mojo/public/cpp/bindings/remote.h"
  80. #include "mojo/public/cpp/system/platform_handle.h"
  81. #include "printing/buildflags/buildflags.h"
  82. #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
  83. #include "services/service_manager/public/cpp/interface_provider.h"
  84. #include "shell/browser/api/electron_api_browser_window.h"
  85. #include "shell/browser/api/electron_api_debugger.h"
  86. #include "shell/browser/api/electron_api_session.h"
  87. #include "shell/browser/api/electron_api_web_frame_main.h"
  88. #include "shell/browser/api/frame_subscriber.h"
  89. #include "shell/browser/api/message_port.h"
  90. #include "shell/browser/browser.h"
  91. #include "shell/browser/child_web_contents_tracker.h"
  92. #include "shell/browser/electron_autofill_driver_factory.h"
  93. #include "shell/browser/electron_browser_context.h"
  94. #include "shell/browser/electron_browser_main_parts.h"
  95. #include "shell/browser/electron_navigation_throttle.h"
  96. #include "shell/browser/file_select_helper.h"
  97. #include "shell/browser/native_window.h"
  98. #include "shell/browser/osr/osr_render_widget_host_view.h"
  99. #include "shell/browser/osr/osr_web_contents_view.h"
  100. #include "shell/browser/session_preferences.h"
  101. #include "shell/browser/ui/drag_util.h"
  102. #include "shell/browser/ui/file_dialog.h"
  103. #include "shell/browser/ui/inspectable_web_contents.h"
  104. #include "shell/browser/ui/inspectable_web_contents_view.h"
  105. #include "shell/browser/web_contents_permission_helper.h"
  106. #include "shell/browser/web_contents_preferences.h"
  107. #include "shell/browser/web_contents_zoom_controller.h"
  108. #include "shell/browser/web_view_guest_delegate.h"
  109. #include "shell/browser/web_view_manager.h"
  110. #include "shell/common/api/api.mojom.h"
  111. #include "shell/common/api/electron_api_native_image.h"
  112. #include "shell/common/api/electron_bindings.h"
  113. #include "shell/common/color_util.h"
  114. #include "shell/common/electron_constants.h"
  115. #include "shell/common/gin_converters/base_converter.h"
  116. #include "shell/common/gin_converters/blink_converter.h"
  117. #include "shell/common/gin_converters/callback_converter.h"
  118. #include "shell/common/gin_converters/content_converter.h"
  119. #include "shell/common/gin_converters/file_path_converter.h"
  120. #include "shell/common/gin_converters/frame_converter.h"
  121. #include "shell/common/gin_converters/gfx_converter.h"
  122. #include "shell/common/gin_converters/gurl_converter.h"
  123. #include "shell/common/gin_converters/image_converter.h"
  124. #include "shell/common/gin_converters/net_converter.h"
  125. #include "shell/common/gin_converters/optional_converter.h"
  126. #include "shell/common/gin_converters/osr_converter.h"
  127. #include "shell/common/gin_converters/value_converter.h"
  128. #include "shell/common/gin_helper/dictionary.h"
  129. #include "shell/common/gin_helper/error_thrower.h"
  130. #include "shell/common/gin_helper/locker.h"
  131. #include "shell/common/gin_helper/object_template_builder.h"
  132. #include "shell/common/gin_helper/promise.h"
  133. #include "shell/common/gin_helper/reply_channel.h"
  134. #include "shell/common/language_util.h"
  135. #include "shell/common/node_includes.h"
  136. #include "shell/common/node_util.h"
  137. #include "shell/common/options_switches.h"
  138. #include "shell/common/thread_restrictions.h"
  139. #include "shell/common/v8_util.h"
  140. #include "storage/browser/file_system/isolated_context.h"
  141. #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
  142. #include "third_party/blink/public/common/input/web_input_event.h"
  143. #include "third_party/blink/public/common/messaging/transferable_message_mojom_traits.h"
  144. #include "third_party/blink/public/common/page/page_zoom.h"
  145. #include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
  146. #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
  147. #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
  148. #include "third_party/blink/public/mojom/messaging/transferable_message.mojom.h"
  149. #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
  150. #include "ui/base/cursor/cursor.h"
  151. #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
  152. #include "ui/display/screen.h"
  153. #include "ui/events/base_event_utils.h"
  154. #if BUILDFLAG(IS_MAC)
  155. #include "ui/base/cocoa/defaults_utils.h"
  156. #endif
  157. #if BUILDFLAG(IS_LINUX)
  158. #include "ui/linux/linux_ui.h"
  159. #endif
  160. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
  161. #include "ui/aura/window.h"
  162. #include "ui/gfx/font_render_params.h"
  163. #endif
  164. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  165. #include "extensions/browser/script_executor.h"
  166. #include "extensions/browser/view_type_utils.h"
  167. #include "extensions/common/mojom/view_type.mojom.h"
  168. #include "shell/browser/extensions/electron_extension_web_contents_observer.h"
  169. #endif
  170. #if BUILDFLAG(ENABLE_PRINTING)
  171. #include "chrome/browser/printing/print_view_manager_base.h"
  172. #include "components/printing/browser/print_manager_utils.h"
  173. #include "components/printing/browser/print_to_pdf/pdf_print_result.h"
  174. #include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
  175. #include "printing/mojom/print.mojom.h" // nogncheck
  176. #include "printing/page_range.h"
  177. #include "shell/browser/printing/print_view_manager_electron.h"
  178. #include "shell/browser/printing/printing_utils.h"
  179. #if BUILDFLAG(IS_WIN)
  180. #include "printing/backend/win_helper.h"
  181. #endif
  182. #endif // BUILDFLAG(ENABLE_PRINTING)
  183. #if BUILDFLAG(ENABLE_PLUGINS)
  184. #include "content/public/browser/plugin_service.h"
  185. #endif
  186. #if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  187. #include "chrome/browser/spellchecker/spellcheck_factory.h"
  188. #include "chrome/browser/spellchecker/spellcheck_service.h"
  189. #include "components/spellcheck/browser/spellcheck_platform.h"
  190. #include "components/spellcheck/common/spellcheck_common.h"
  191. #include "components/spellcheck/common/spellcheck_features.h"
  192. #endif
  193. #if !IS_MAS_BUILD()
  194. #include "chrome/browser/hang_monitor/hang_crash_dump.h" // nogncheck
  195. #endif
  196. namespace gin {
  197. #if BUILDFLAG(ENABLE_PRINTING)
  198. template <>
  199. struct Converter<printing::mojom::MarginType> {
  200. static bool FromV8(v8::Isolate* isolate,
  201. v8::Local<v8::Value> val,
  202. printing::mojom::MarginType* out) {
  203. using Val = printing::mojom::MarginType;
  204. static constexpr auto Lookup =
  205. base::MakeFixedFlatMap<std::string_view, Val>({
  206. {"custom", Val::kCustomMargins},
  207. {"default", Val::kDefaultMargins},
  208. {"none", Val::kNoMargins},
  209. {"printableArea", Val::kPrintableAreaMargins},
  210. });
  211. return FromV8WithLookup(isolate, val, Lookup, out);
  212. }
  213. };
  214. template <>
  215. struct Converter<printing::mojom::DuplexMode> {
  216. static bool FromV8(v8::Isolate* isolate,
  217. v8::Local<v8::Value> val,
  218. printing::mojom::DuplexMode* out) {
  219. using Val = printing::mojom::DuplexMode;
  220. static constexpr auto Lookup =
  221. base::MakeFixedFlatMap<std::string_view, Val>({
  222. {"longEdge", Val::kLongEdge},
  223. {"shortEdge", Val::kShortEdge},
  224. {"simplex", Val::kSimplex},
  225. });
  226. return FromV8WithLookup(isolate, val, Lookup, out);
  227. }
  228. };
  229. #endif
  230. template <>
  231. struct Converter<WindowOpenDisposition> {
  232. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  233. WindowOpenDisposition val) {
  234. std::string disposition = "other";
  235. switch (val) {
  236. case WindowOpenDisposition::CURRENT_TAB:
  237. disposition = "default";
  238. break;
  239. case WindowOpenDisposition::NEW_FOREGROUND_TAB:
  240. disposition = "foreground-tab";
  241. break;
  242. case WindowOpenDisposition::NEW_BACKGROUND_TAB:
  243. disposition = "background-tab";
  244. break;
  245. case WindowOpenDisposition::NEW_POPUP:
  246. case WindowOpenDisposition::NEW_WINDOW:
  247. disposition = "new-window";
  248. break;
  249. case WindowOpenDisposition::SAVE_TO_DISK:
  250. disposition = "save-to-disk";
  251. break;
  252. default:
  253. break;
  254. }
  255. return gin::ConvertToV8(isolate, disposition);
  256. }
  257. };
  258. template <>
  259. struct Converter<content::JavaScriptDialogType> {
  260. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  261. content::JavaScriptDialogType val) {
  262. switch (val) {
  263. case content::JAVASCRIPT_DIALOG_TYPE_ALERT:
  264. return gin::ConvertToV8(isolate, "alert");
  265. case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM:
  266. return gin::ConvertToV8(isolate, "confirm");
  267. case content::JAVASCRIPT_DIALOG_TYPE_PROMPT:
  268. return gin::ConvertToV8(isolate, "prompt");
  269. }
  270. }
  271. };
  272. template <>
  273. struct Converter<content::SavePageType> {
  274. static bool FromV8(v8::Isolate* isolate,
  275. v8::Local<v8::Value> val,
  276. content::SavePageType* out) {
  277. using Val = content::SavePageType;
  278. static constexpr auto Lookup =
  279. base::MakeFixedFlatMap<std::string_view, Val>({
  280. {"htmlcomplete", Val::SAVE_PAGE_TYPE_AS_COMPLETE_HTML},
  281. {"htmlonly", Val::SAVE_PAGE_TYPE_AS_ONLY_HTML},
  282. {"mhtml", Val::SAVE_PAGE_TYPE_AS_MHTML},
  283. });
  284. return FromV8WithLowerLookup(isolate, val, Lookup, out);
  285. }
  286. };
  287. template <>
  288. struct Converter<electron::api::WebContents::Type> {
  289. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  290. electron::api::WebContents::Type val) {
  291. using Type = electron::api::WebContents::Type;
  292. std::string type;
  293. switch (val) {
  294. case Type::kBackgroundPage:
  295. type = "backgroundPage";
  296. break;
  297. case Type::kBrowserWindow:
  298. type = "window";
  299. break;
  300. case Type::kBrowserView:
  301. type = "browserView";
  302. break;
  303. case Type::kRemote:
  304. type = "remote";
  305. break;
  306. case Type::kWebView:
  307. type = "webview";
  308. break;
  309. case Type::kOffScreen:
  310. type = "offscreen";
  311. break;
  312. default:
  313. break;
  314. }
  315. return gin::ConvertToV8(isolate, type);
  316. }
  317. static bool FromV8(v8::Isolate* isolate,
  318. v8::Local<v8::Value> val,
  319. electron::api::WebContents::Type* out) {
  320. using Val = electron::api::WebContents::Type;
  321. static constexpr auto Lookup =
  322. base::MakeFixedFlatMap<std::string_view, Val>({
  323. {"backgroundPage", Val::kBackgroundPage},
  324. {"browserView", Val::kBrowserView},
  325. {"offscreen", Val::kOffScreen},
  326. {"webview", Val::kWebView},
  327. });
  328. return FromV8WithLookup(isolate, val, Lookup, out);
  329. }
  330. };
  331. template <>
  332. struct Converter<scoped_refptr<content::DevToolsAgentHost>> {
  333. static v8::Local<v8::Value> ToV8(
  334. v8::Isolate* isolate,
  335. const scoped_refptr<content::DevToolsAgentHost>& val) {
  336. gin_helper::Dictionary dict(isolate, v8::Object::New(isolate));
  337. dict.Set("id", val->GetId());
  338. dict.Set("url", val->GetURL().spec());
  339. return dict.GetHandle();
  340. }
  341. };
  342. template <>
  343. struct Converter<content::NavigationEntry*> {
  344. static bool FromV8(v8::Isolate* isolate,
  345. v8::Local<v8::Value> val,
  346. content::NavigationEntry** out) {
  347. gin_helper::Dictionary dict;
  348. if (!gin::ConvertFromV8(isolate, val, &dict))
  349. return false;
  350. std::string url_str;
  351. std::string title;
  352. std::string encoded_page_state;
  353. GURL url;
  354. if (!dict.Get("url", &url) || !dict.Get("title", &title))
  355. return false;
  356. auto entry = content::NavigationEntry::Create();
  357. entry->SetURL(url);
  358. entry->SetTitle(base::UTF8ToUTF16(title));
  359. // Handle optional page state
  360. if (dict.Get("pageState", &encoded_page_state)) {
  361. std::string decoded_page_state;
  362. if (base::Base64Decode(encoded_page_state, &decoded_page_state)) {
  363. auto restore_context = content::NavigationEntryRestoreContext::Create();
  364. auto page_state =
  365. blink::PageState::CreateFromEncodedData(decoded_page_state);
  366. if (!page_state.IsValid())
  367. return false;
  368. entry->SetPageState(std::move(page_state), restore_context.get());
  369. }
  370. }
  371. *out = entry.release();
  372. return true;
  373. }
  374. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  375. content::NavigationEntry* entry) {
  376. if (!entry) {
  377. return v8::Null(isolate);
  378. }
  379. gin_helper::Dictionary dict = gin_helper::Dictionary::CreateEmpty(isolate);
  380. dict.Set("url", entry->GetURL().spec());
  381. dict.Set("title", entry->GetTitleForDisplay());
  382. // Page state saves scroll position and values of any form fields
  383. const blink::PageState& page_state = entry->GetPageState();
  384. if (page_state.IsValid()) {
  385. std::string encoded_data = base::Base64Encode(page_state.ToEncodedData());
  386. dict.Set("pageState", encoded_data);
  387. }
  388. return dict.GetHandle();
  389. }
  390. };
  391. } // namespace gin
  392. namespace electron::api {
  393. namespace {
  394. // Global toggle for disabling draggable regions checks.
  395. bool g_disable_draggable_regions = false;
  396. constexpr std::string_view CursorTypeToString(
  397. ui::mojom::CursorType cursor_type) {
  398. switch (cursor_type) {
  399. case ui::mojom::CursorType::kPointer:
  400. return "pointer";
  401. case ui::mojom::CursorType::kCross:
  402. return "crosshair";
  403. case ui::mojom::CursorType::kHand:
  404. return "hand";
  405. case ui::mojom::CursorType::kIBeam:
  406. return "text";
  407. case ui::mojom::CursorType::kWait:
  408. return "wait";
  409. case ui::mojom::CursorType::kHelp:
  410. return "help";
  411. case ui::mojom::CursorType::kEastResize:
  412. return "e-resize";
  413. case ui::mojom::CursorType::kNorthResize:
  414. return "n-resize";
  415. case ui::mojom::CursorType::kNorthEastResize:
  416. return "ne-resize";
  417. case ui::mojom::CursorType::kNorthWestResize:
  418. return "nw-resize";
  419. case ui::mojom::CursorType::kSouthResize:
  420. return "s-resize";
  421. case ui::mojom::CursorType::kSouthEastResize:
  422. return "se-resize";
  423. case ui::mojom::CursorType::kSouthWestResize:
  424. return "sw-resize";
  425. case ui::mojom::CursorType::kWestResize:
  426. return "w-resize";
  427. case ui::mojom::CursorType::kNorthSouthResize:
  428. return "ns-resize";
  429. case ui::mojom::CursorType::kEastWestResize:
  430. return "ew-resize";
  431. case ui::mojom::CursorType::kNorthEastSouthWestResize:
  432. return "nesw-resize";
  433. case ui::mojom::CursorType::kNorthWestSouthEastResize:
  434. return "nwse-resize";
  435. case ui::mojom::CursorType::kColumnResize:
  436. return "col-resize";
  437. case ui::mojom::CursorType::kRowResize:
  438. return "row-resize";
  439. case ui::mojom::CursorType::kMiddlePanning:
  440. return "m-panning";
  441. case ui::mojom::CursorType::kMiddlePanningVertical:
  442. return "m-panning-vertical";
  443. case ui::mojom::CursorType::kMiddlePanningHorizontal:
  444. return "m-panning-horizontal";
  445. case ui::mojom::CursorType::kEastPanning:
  446. return "e-panning";
  447. case ui::mojom::CursorType::kNorthPanning:
  448. return "n-panning";
  449. case ui::mojom::CursorType::kNorthEastPanning:
  450. return "ne-panning";
  451. case ui::mojom::CursorType::kNorthWestPanning:
  452. return "nw-panning";
  453. case ui::mojom::CursorType::kSouthPanning:
  454. return "s-panning";
  455. case ui::mojom::CursorType::kSouthEastPanning:
  456. return "se-panning";
  457. case ui::mojom::CursorType::kSouthWestPanning:
  458. return "sw-panning";
  459. case ui::mojom::CursorType::kWestPanning:
  460. return "w-panning";
  461. case ui::mojom::CursorType::kMove:
  462. return "move";
  463. case ui::mojom::CursorType::kVerticalText:
  464. return "vertical-text";
  465. case ui::mojom::CursorType::kCell:
  466. return "cell";
  467. case ui::mojom::CursorType::kContextMenu:
  468. return "context-menu";
  469. case ui::mojom::CursorType::kAlias:
  470. return "alias";
  471. case ui::mojom::CursorType::kProgress:
  472. return "progress";
  473. case ui::mojom::CursorType::kNoDrop:
  474. return "nodrop";
  475. case ui::mojom::CursorType::kCopy:
  476. return "copy";
  477. case ui::mojom::CursorType::kNone:
  478. return "none";
  479. case ui::mojom::CursorType::kNotAllowed:
  480. return "not-allowed";
  481. case ui::mojom::CursorType::kZoomIn:
  482. return "zoom-in";
  483. case ui::mojom::CursorType::kZoomOut:
  484. return "zoom-out";
  485. case ui::mojom::CursorType::kGrab:
  486. return "grab";
  487. case ui::mojom::CursorType::kGrabbing:
  488. return "grabbing";
  489. case ui::mojom::CursorType::kCustom:
  490. return "custom";
  491. case ui::mojom::CursorType::kNull:
  492. return "null";
  493. case ui::mojom::CursorType::kDndNone:
  494. return "drag-drop-none";
  495. case ui::mojom::CursorType::kDndMove:
  496. return "drag-drop-move";
  497. case ui::mojom::CursorType::kDndCopy:
  498. return "drag-drop-copy";
  499. case ui::mojom::CursorType::kDndLink:
  500. return "drag-drop-link";
  501. case ui::mojom::CursorType::kNorthSouthNoResize:
  502. return "ns-no-resize";
  503. case ui::mojom::CursorType::kEastWestNoResize:
  504. return "ew-no-resize";
  505. case ui::mojom::CursorType::kNorthEastSouthWestNoResize:
  506. return "nesw-no-resize";
  507. case ui::mojom::CursorType::kNorthWestSouthEastNoResize:
  508. return "nwse-no-resize";
  509. default:
  510. return "default";
  511. }
  512. }
  513. base::IDMap<WebContents*>& GetAllWebContents() {
  514. static base::NoDestructor<base::IDMap<WebContents*>> s_all_web_contents;
  515. return *s_all_web_contents;
  516. }
  517. void OnCapturePageDone(gin_helper::Promise<gfx::Image> promise,
  518. base::ScopedClosureRunner capture_handle,
  519. const SkBitmap& bitmap) {
  520. auto ui_task_runner = content::GetUIThreadTaskRunner({});
  521. if (!ui_task_runner->RunsTasksInCurrentSequence()) {
  522. ui_task_runner->PostTask(
  523. FROM_HERE, base::BindOnce(&OnCapturePageDone, std::move(promise),
  524. std::move(capture_handle), bitmap));
  525. return;
  526. }
  527. // Hack to enable transparency in captured image
  528. promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
  529. capture_handle.RunAndReset();
  530. }
  531. std::optional<base::TimeDelta> GetCursorBlinkInterval() {
  532. #if BUILDFLAG(IS_MAC)
  533. std::optional<base::TimeDelta> system_value(
  534. ui::TextInsertionCaretBlinkPeriodFromDefaults());
  535. if (system_value)
  536. return *system_value;
  537. #elif BUILDFLAG(IS_LINUX)
  538. if (auto* linux_ui = ui::LinuxUi::instance())
  539. return linux_ui->GetCursorBlinkInterval();
  540. #elif BUILDFLAG(IS_WIN)
  541. const auto system_msec = ::GetCaretBlinkTime();
  542. if (system_msec != 0) {
  543. return (system_msec == INFINITE) ? base::TimeDelta()
  544. : base::Milliseconds(system_msec);
  545. }
  546. #endif
  547. return std::nullopt;
  548. }
  549. struct UserDataLink : public base::SupportsUserData::Data {
  550. explicit UserDataLink(base::WeakPtr<WebContents> contents)
  551. : web_contents(contents) {}
  552. base::WeakPtr<WebContents> web_contents;
  553. };
  554. const void* kElectronApiWebContentsKey = &kElectronApiWebContentsKey;
  555. const char kRootName[] = "<root>";
  556. struct FileSystem {
  557. std::string type;
  558. std::string file_system_name;
  559. std::string root_url;
  560. std::string file_system_path;
  561. };
  562. std::string RegisterFileSystem(content::WebContents* web_contents,
  563. const base::FilePath& path) {
  564. auto* isolated_context = storage::IsolatedContext::GetInstance();
  565. std::string root_name(kRootName);
  566. storage::IsolatedContext::ScopedFSHandle file_system =
  567. isolated_context->RegisterFileSystemForPath(
  568. storage::kFileSystemTypeLocal, std::string(), path, &root_name);
  569. content::ChildProcessSecurityPolicy* policy =
  570. content::ChildProcessSecurityPolicy::GetInstance();
  571. content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
  572. int renderer_id = render_view_host->GetProcess()->GetDeprecatedID();
  573. policy->GrantReadFileSystem(renderer_id, file_system.id());
  574. policy->GrantWriteFileSystem(renderer_id, file_system.id());
  575. policy->GrantCreateFileForFileSystem(renderer_id, file_system.id());
  576. policy->GrantDeleteFromFileSystem(renderer_id, file_system.id());
  577. if (!policy->CanReadFile(renderer_id, path))
  578. policy->GrantReadFile(renderer_id, path);
  579. return file_system.id();
  580. }
  581. FileSystem CreateFileSystemStruct(content::WebContents* web_contents,
  582. const std::string& file_system_id,
  583. const std::string& file_system_path,
  584. const std::string& type) {
  585. const GURL origin = web_contents->GetURL().DeprecatedGetOriginAsURL();
  586. std::string file_system_name =
  587. storage::GetIsolatedFileSystemName(origin, file_system_id);
  588. std::string root_url = storage::GetIsolatedFileSystemRootURIString(
  589. origin, file_system_id, kRootName);
  590. return FileSystem(type, file_system_name, root_url, file_system_path);
  591. }
  592. base::Value::Dict CreateFileSystemValue(const FileSystem& file_system) {
  593. base::Value::Dict value;
  594. value.Set("type", file_system.type);
  595. value.Set("fileSystemName", file_system.file_system_name);
  596. value.Set("rootURL", file_system.root_url);
  597. value.Set("fileSystemPath", file_system.file_system_path);
  598. return value;
  599. }
  600. void WriteToFile(const base::FilePath& path,
  601. const std::string& content,
  602. bool is_base64) {
  603. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  604. base::BlockingType::WILL_BLOCK);
  605. DCHECK(!path.empty());
  606. if (!is_base64) {
  607. base::WriteFile(path, content);
  608. return;
  609. }
  610. const std::optional<std::vector<uint8_t>> decoded_content =
  611. base::Base64Decode(content);
  612. if (decoded_content) {
  613. base::WriteFile(path, decoded_content.value());
  614. } else {
  615. LOG(ERROR) << "Invalid base64. Not writing " << path;
  616. }
  617. }
  618. void AppendToFile(const base::FilePath& path, const std::string& content) {
  619. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  620. base::BlockingType::WILL_BLOCK);
  621. DCHECK(!path.empty());
  622. base::AppendToFile(path, content);
  623. }
  624. PrefService* GetPrefService(content::WebContents* web_contents) {
  625. auto* context = web_contents->GetBrowserContext();
  626. return static_cast<electron::ElectronBrowserContext*>(context)->prefs();
  627. }
  628. std::map<std::string, std::string> GetAddedFileSystemPaths(
  629. content::WebContents* web_contents) {
  630. auto* pref_service = GetPrefService(web_contents);
  631. const base::Value::Dict& file_system_paths =
  632. pref_service->GetDict(prefs::kDevToolsFileSystemPaths);
  633. std::map<std::string, std::string> result;
  634. for (auto it : file_system_paths) {
  635. std::string type =
  636. it.second.is_string() ? it.second.GetString() : std::string();
  637. result[it.first] = type;
  638. }
  639. return result;
  640. }
  641. bool IsDevToolsFileSystemAdded(content::WebContents* web_contents,
  642. const std::string& file_system_path) {
  643. return base::Contains(GetAddedFileSystemPaths(web_contents),
  644. file_system_path);
  645. }
  646. content::RenderFrameHost* GetRenderFrameHost(
  647. content::NavigationHandle* navigation_handle) {
  648. content::FrameTreeNodeId frame_tree_node_id =
  649. navigation_handle->GetFrameTreeNodeId();
  650. content::FrameTreeNode* frame_tree_node =
  651. content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
  652. content::RenderFrameHostManager* render_manager =
  653. frame_tree_node->render_manager();
  654. content::RenderFrameHost* frame_host = nullptr;
  655. if (render_manager) {
  656. frame_host = render_manager->speculative_frame_host();
  657. if (!frame_host)
  658. frame_host = render_manager->current_frame_host();
  659. }
  660. return frame_host;
  661. }
  662. } // namespace
  663. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  664. WebContents::Type GetTypeFromViewType(extensions::mojom::ViewType view_type) {
  665. switch (view_type) {
  666. case extensions::mojom::ViewType::kExtensionBackgroundPage:
  667. return WebContents::Type::kBackgroundPage;
  668. case extensions::mojom::ViewType::kAppWindow:
  669. case extensions::mojom::ViewType::kComponent:
  670. case extensions::mojom::ViewType::kExtensionPopup:
  671. case extensions::mojom::ViewType::kBackgroundContents:
  672. case extensions::mojom::ViewType::kExtensionGuest:
  673. case extensions::mojom::ViewType::kTabContents:
  674. case extensions::mojom::ViewType::kOffscreenDocument:
  675. case extensions::mojom::ViewType::kExtensionSidePanel:
  676. case extensions::mojom::ViewType::kInvalid:
  677. case extensions::mojom::ViewType::kDeveloperTools:
  678. return WebContents::Type::kRemote;
  679. }
  680. }
  681. #endif
  682. WebContents::WebContents(v8::Isolate* isolate,
  683. content::WebContents* web_contents)
  684. : content::WebContentsObserver(web_contents),
  685. type_(Type::kRemote),
  686. id_(GetAllWebContents().Add(this))
  687. #if BUILDFLAG(ENABLE_PRINTING)
  688. ,
  689. print_task_runner_(CreatePrinterHandlerTaskRunner())
  690. #endif
  691. {
  692. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  693. // WebContents created by extension host will have valid ViewType set.
  694. extensions::mojom::ViewType view_type = extensions::GetViewType(web_contents);
  695. if (view_type != extensions::mojom::ViewType::kInvalid) {
  696. InitWithExtensionView(isolate, web_contents, view_type);
  697. }
  698. extensions::ElectronExtensionWebContentsObserver::CreateForWebContents(
  699. web_contents);
  700. script_executor_ = std::make_unique<extensions::ScriptExecutor>(web_contents);
  701. #endif
  702. auto session = Session::CreateFrom(isolate, GetBrowserContext());
  703. session_.Reset(isolate, session.ToV8());
  704. SetUserAgent(GetBrowserContext()->GetUserAgent());
  705. web_contents->SetUserData(kElectronApiWebContentsKey,
  706. std::make_unique<UserDataLink>(GetWeakPtr()));
  707. InitZoomController(web_contents, gin::Dictionary::CreateEmpty(isolate));
  708. }
  709. WebContents::WebContents(v8::Isolate* isolate,
  710. std::unique_ptr<content::WebContents> web_contents,
  711. Type type)
  712. : content::WebContentsObserver(web_contents.get()),
  713. type_(type),
  714. id_(GetAllWebContents().Add(this))
  715. #if BUILDFLAG(ENABLE_PRINTING)
  716. ,
  717. print_task_runner_(CreatePrinterHandlerTaskRunner())
  718. #endif
  719. {
  720. DCHECK(type != Type::kRemote)
  721. << "Can't take ownership of a remote WebContents";
  722. auto session = Session::CreateFrom(isolate, GetBrowserContext());
  723. session_.Reset(isolate, session.ToV8());
  724. InitWithSessionAndOptions(isolate, std::move(web_contents), session,
  725. gin::Dictionary::CreateEmpty(isolate));
  726. }
  727. WebContents::WebContents(v8::Isolate* isolate,
  728. const gin_helper::Dictionary& options)
  729. : id_(GetAllWebContents().Add(this))
  730. #if BUILDFLAG(ENABLE_PRINTING)
  731. ,
  732. print_task_runner_(CreatePrinterHandlerTaskRunner())
  733. #endif
  734. {
  735. // Read options.
  736. options.Get("backgroundThrottling", &background_throttling_);
  737. // Get type
  738. options.Get("type", &type_);
  739. // Get transparent for guest view
  740. options.Get("transparent", &guest_transparent_);
  741. // Offscreen rendering
  742. v8::Local<v8::Value> use_offscreen;
  743. if (options.Get(options::kOffscreen, &use_offscreen)) {
  744. if (use_offscreen->IsBoolean()) {
  745. bool b = false;
  746. if (options.Get(options::kOffscreen, &b) && b) {
  747. type_ = Type::kOffScreen;
  748. }
  749. } else if (use_offscreen->IsObject()) {
  750. type_ = Type::kOffScreen;
  751. auto use_offscreen_dict =
  752. gin_helper::Dictionary::CreateEmpty(options.isolate());
  753. options.Get(options::kOffscreen, &use_offscreen_dict);
  754. use_offscreen_dict.Get(options::kUseSharedTexture,
  755. &offscreen_use_shared_texture_);
  756. }
  757. }
  758. // Init embedder earlier
  759. options.Get("embedder", &embedder_);
  760. // Whether to enable DevTools.
  761. options.Get("devTools", &enable_devtools_);
  762. bool initially_shown = true;
  763. options.Get(options::kShow, &initially_shown);
  764. // Obtain the session.
  765. std::string partition;
  766. gin::Handle<api::Session> session;
  767. if (options.Get("session", &session) && !session.IsEmpty()) {
  768. } else if (options.Get("partition", &partition)) {
  769. session = Session::FromPartition(isolate, partition);
  770. } else {
  771. // Use the default session if not specified.
  772. session = Session::FromPartition(isolate, "");
  773. }
  774. session_.Reset(isolate, session.ToV8());
  775. std::unique_ptr<content::WebContents> web_contents;
  776. if (is_guest()) {
  777. scoped_refptr<content::SiteInstance> site_instance =
  778. content::SiteInstance::CreateForURL(session->browser_context(),
  779. GURL("chrome-guest://fake-host"));
  780. content::WebContents::CreateParams params(session->browser_context(),
  781. site_instance);
  782. guest_delegate_ =
  783. std::make_unique<WebViewGuestDelegate>(embedder_->web_contents(), this);
  784. params.guest_delegate = guest_delegate_.get();
  785. if (embedder_ && embedder_->IsOffScreen()) {
  786. auto* view = new OffScreenWebContentsView(
  787. false, offscreen_use_shared_texture_,
  788. base::BindRepeating(&WebContents::OnPaint, base::Unretained(this)));
  789. params.view = view;
  790. params.delegate_view = view;
  791. web_contents = content::WebContents::Create(params);
  792. view->SetWebContents(web_contents.get());
  793. } else {
  794. web_contents = content::WebContents::Create(params);
  795. }
  796. } else if (IsOffScreen()) {
  797. // webPreferences does not have a transparent option, so if the window needs
  798. // to be transparent, that will be set at electron_api_browser_window.cc#L57
  799. // and we then need to pull it back out and check it here.
  800. std::string background_color;
  801. options.GetHidden(options::kBackgroundColor, &background_color);
  802. bool transparent = ParseCSSColor(background_color) == SK_ColorTRANSPARENT;
  803. content::WebContents::CreateParams params(session->browser_context());
  804. auto* view = new OffScreenWebContentsView(
  805. transparent, offscreen_use_shared_texture_,
  806. base::BindRepeating(&WebContents::OnPaint, base::Unretained(this)));
  807. params.view = view;
  808. params.delegate_view = view;
  809. web_contents = content::WebContents::Create(params);
  810. view->SetWebContents(web_contents.get());
  811. } else {
  812. content::WebContents::CreateParams params(session->browser_context());
  813. params.initially_hidden = !initially_shown;
  814. web_contents = content::WebContents::Create(params);
  815. }
  816. InitWithSessionAndOptions(isolate, std::move(web_contents), session, options);
  817. }
  818. void WebContents::InitZoomController(content::WebContents* web_contents,
  819. const gin_helper::Dictionary& options) {
  820. WebContentsZoomController::CreateForWebContents(web_contents);
  821. zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
  822. double zoom_factor;
  823. if (options.Get(options::kZoomFactor, &zoom_factor))
  824. zoom_controller_->SetDefaultZoomFactor(zoom_factor);
  825. // Nothing to do with ZoomController, but this function gets called in all
  826. // init cases!
  827. content::RenderViewHost* host = web_contents->GetRenderViewHost();
  828. if (host)
  829. host->GetWidget()->AddInputEventObserver(this);
  830. }
  831. void WebContents::InitWithSessionAndOptions(
  832. v8::Isolate* isolate,
  833. std::unique_ptr<content::WebContents> owned_web_contents,
  834. gin::Handle<api::Session> session,
  835. const gin_helper::Dictionary& options) {
  836. Observe(owned_web_contents.get());
  837. InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
  838. is_guest());
  839. inspectable_web_contents_->GetView()->SetDelegate(this);
  840. auto* prefs = web_contents()->GetMutableRendererPrefs();
  841. // Collect preferred languages from OS and browser process. accept_languages
  842. // effects HTTP header, navigator.languages, and CJK fallback font selection.
  843. //
  844. // Note that an application locale set to the browser process might be
  845. // different with the one set to the preference list.
  846. // (e.g. overridden with --lang)
  847. std::string accept_languages =
  848. g_browser_process->GetApplicationLocale() + ",";
  849. for (auto const& language : electron::GetPreferredLanguages()) {
  850. if (language == g_browser_process->GetApplicationLocale())
  851. continue;
  852. accept_languages += language + ",";
  853. }
  854. accept_languages.pop_back();
  855. prefs->accept_languages = accept_languages;
  856. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
  857. // Update font settings.
  858. static const gfx::FontRenderParams params(
  859. gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr));
  860. prefs->should_antialias_text = params.antialiasing;
  861. prefs->use_subpixel_positioning = params.subpixel_positioning;
  862. prefs->hinting = params.hinting;
  863. prefs->use_autohinter = params.autohinter;
  864. prefs->use_bitmaps = params.use_bitmaps;
  865. prefs->subpixel_rendering = params.subpixel_rendering;
  866. #endif
  867. // Honor the system's cursor blink rate settings
  868. if (auto interval = GetCursorBlinkInterval())
  869. prefs->caret_blink_interval = *interval;
  870. // Save the preferences in C++.
  871. // If there's already a WebContentsPreferences object, we created it as part
  872. // of the webContents.setWindowOpenHandler path, so don't overwrite it.
  873. if (!WebContentsPreferences::From(web_contents())) {
  874. new WebContentsPreferences(web_contents(), options);
  875. }
  876. // Trigger re-calculation of webkit prefs.
  877. web_contents()->NotifyPreferencesChanged();
  878. WebContentsPermissionHelper::CreateForWebContents(web_contents());
  879. InitZoomController(web_contents(), options);
  880. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  881. extensions::ElectronExtensionWebContentsObserver::CreateForWebContents(
  882. web_contents());
  883. script_executor_ =
  884. std::make_unique<extensions::ScriptExecutor>(web_contents());
  885. #endif
  886. AutofillDriverFactory::CreateForWebContents(web_contents());
  887. SetUserAgent(GetBrowserContext()->GetUserAgent());
  888. if (is_guest()) {
  889. NativeWindow* owner_window = nullptr;
  890. if (embedder_) {
  891. // New WebContents's owner_window is the embedder's owner_window.
  892. auto* relay =
  893. NativeWindowRelay::FromWebContents(embedder_->web_contents());
  894. if (relay)
  895. owner_window = relay->GetNativeWindow();
  896. }
  897. if (owner_window)
  898. SetOwnerWindow(owner_window);
  899. }
  900. web_contents()->SetUserData(kElectronApiWebContentsKey,
  901. std::make_unique<UserDataLink>(GetWeakPtr()));
  902. }
  903. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  904. void WebContents::InitWithExtensionView(v8::Isolate* isolate,
  905. content::WebContents* web_contents,
  906. extensions::mojom::ViewType view_type) {
  907. // Must reassign type prior to calling `Init`.
  908. type_ = GetTypeFromViewType(view_type);
  909. if (type_ == Type::kRemote)
  910. return;
  911. if (type_ == Type::kBackgroundPage)
  912. // non-background-page WebContents are retained by other classes. We need
  913. // to pin here to prevent background-page WebContents from being GC'd.
  914. // The background page api::WebContents will live until the underlying
  915. // content::WebContents is destroyed.
  916. Pin(isolate);
  917. // Allow toggling DevTools for background pages
  918. Observe(web_contents);
  919. InitWithWebContents(std::unique_ptr<content::WebContents>(web_contents),
  920. GetBrowserContext(), is_guest());
  921. inspectable_web_contents_->GetView()->SetDelegate(this);
  922. }
  923. #endif
  924. void WebContents::InitWithWebContents(
  925. std::unique_ptr<content::WebContents> web_contents,
  926. ElectronBrowserContext* browser_context,
  927. bool is_guest) {
  928. browser_context_ = browser_context;
  929. web_contents->SetDelegate(this);
  930. #if BUILDFLAG(ENABLE_PRINTING)
  931. PrintViewManagerElectron::CreateForWebContents(web_contents.get());
  932. #endif
  933. // Determine whether the WebContents is offscreen.
  934. auto* web_preferences = WebContentsPreferences::From(web_contents.get());
  935. offscreen_ = web_preferences && web_preferences->IsOffscreen();
  936. // Create InspectableWebContents.
  937. inspectable_web_contents_ = std::make_unique<InspectableWebContents>(
  938. std::move(web_contents), browser_context->prefs(), is_guest);
  939. inspectable_web_contents_->SetDelegate(this);
  940. }
  941. WebContents::~WebContents() {
  942. if (owner_window_) {
  943. owner_window_->RemoveBackgroundThrottlingSource(this);
  944. }
  945. if (web_contents()) {
  946. content::RenderViewHost* host = web_contents()->GetRenderViewHost();
  947. if (host)
  948. host->GetWidget()->RemoveInputEventObserver(this);
  949. }
  950. if (!inspectable_web_contents_) {
  951. WebContentsDestroyed();
  952. return;
  953. }
  954. inspectable_web_contents_->GetView()->SetDelegate(nullptr);
  955. // This event is only for internal use, which is emitted when WebContents is
  956. // being destroyed.
  957. Emit("will-destroy");
  958. // For guest view based on OOPIF, the WebContents is released by the embedder
  959. // frame, and we need to clear the reference to the memory.
  960. bool not_owned_by_this = is_guest() && attached_;
  961. #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
  962. // And background pages are owned by extensions::ExtensionHost.
  963. if (type_ == Type::kBackgroundPage)
  964. not_owned_by_this = true;
  965. #endif
  966. if (not_owned_by_this) {
  967. inspectable_web_contents_->ReleaseWebContents();
  968. WebContentsDestroyed();
  969. }
  970. // InspectableWebContents will be automatically destroyed.
  971. }
  972. void WebContents::DeleteThisIfAlive() {
  973. // It is possible that the FirstWeakCallback has been called but the
  974. // SecondWeakCallback has not, in this case the garbage collection of
  975. // WebContents has already started and we should not |delete this|.
  976. // Calling |GetWrapper| can detect this corner case.
  977. auto* isolate = JavascriptEnvironment::GetIsolate();
  978. v8::HandleScope scope(isolate);
  979. v8::Local<v8::Object> wrapper;
  980. if (!GetWrapper(isolate).ToLocal(&wrapper))
  981. return;
  982. delete this;
  983. }
  984. void WebContents::Destroy() {
  985. // The content::WebContents should be destroyed asynchronously when possible
  986. // as user may choose to destroy WebContents during an event of it.
  987. if (Browser::Get()->is_shutting_down() || is_guest()) {
  988. DeleteThisIfAlive();
  989. } else {
  990. content::GetUIThreadTaskRunner({})->PostTask(
  991. FROM_HERE,
  992. base::BindOnce(&WebContents::DeleteThisIfAlive, GetWeakPtr()));
  993. }
  994. }
  995. void WebContents::Close(std::optional<gin_helper::Dictionary> options) {
  996. bool dispatch_beforeunload = false;
  997. if (options)
  998. options->Get("waitForBeforeUnload", &dispatch_beforeunload);
  999. if (dispatch_beforeunload &&
  1000. web_contents()->NeedToFireBeforeUnloadOrUnloadEvents()) {
  1001. NotifyUserActivation();
  1002. web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
  1003. } else {
  1004. web_contents()->Close();
  1005. }
  1006. }
  1007. void WebContents::OnDidAddMessageToConsole(
  1008. content::RenderFrameHost* source_frame,
  1009. blink::mojom::ConsoleMessageLevel level,
  1010. const std::u16string& message,
  1011. int32_t line_no,
  1012. const std::u16string& source_id,
  1013. const std::optional<std::u16string>& untrusted_stack_trace) {
  1014. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1015. v8::HandleScope handle_scope(isolate);
  1016. gin::Handle<gin_helper::internal::Event> event =
  1017. gin_helper::internal::Event::New(isolate);
  1018. v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
  1019. gin_helper::Dictionary dict(isolate, event_object);
  1020. dict.SetGetter("frame", source_frame);
  1021. dict.Set("level", level);
  1022. dict.Set("message", message);
  1023. dict.Set("lineNumber", line_no);
  1024. dict.Set("sourceId", source_id);
  1025. // TODO(samuelmaddock): Delete when deprecated arguments are fully removed.
  1026. dict.Set("_level", static_cast<int32_t>(level));
  1027. EmitWithoutEvent("-console-message", event);
  1028. }
  1029. void WebContents::OnCreateWindow(
  1030. const GURL& target_url,
  1031. const content::Referrer& referrer,
  1032. const std::string& frame_name,
  1033. WindowOpenDisposition disposition,
  1034. const std::string& features,
  1035. const scoped_refptr<network::ResourceRequestBody>& body) {
  1036. Emit("-new-window", target_url, frame_name, disposition, features, referrer,
  1037. body);
  1038. }
  1039. void WebContents::WebContentsCreatedWithFullParams(
  1040. content::WebContents* source_contents,
  1041. int opener_render_process_id,
  1042. int opener_render_frame_id,
  1043. const content::mojom::CreateNewWindowParams& params,
  1044. content::WebContents* new_contents) {
  1045. ChildWebContentsTracker::CreateForWebContents(new_contents);
  1046. auto* tracker = ChildWebContentsTracker::FromWebContents(new_contents);
  1047. tracker->url = params.target_url;
  1048. tracker->frame_name = params.frame_name;
  1049. tracker->referrer = params.referrer.To<content::Referrer>();
  1050. tracker->raw_features = params.raw_features;
  1051. tracker->body = params.body;
  1052. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1053. v8::HandleScope handle_scope(isolate);
  1054. gin_helper::Dictionary dict;
  1055. gin::ConvertFromV8(isolate, pending_child_web_preferences_.Get(isolate),
  1056. &dict);
  1057. pending_child_web_preferences_.Reset();
  1058. // Associate the preferences passed in via `setWindowOpenHandler` with the
  1059. // content::WebContents that was just created for the child window. These
  1060. // preferences will be picked up by the RenderWidgetHost via its call to the
  1061. // delegate's OverrideWebkitPrefs.
  1062. new WebContentsPreferences(new_contents, dict);
  1063. }
  1064. bool WebContents::IsWebContentsCreationOverridden(
  1065. content::SiteInstance* source_site_instance,
  1066. content::mojom::WindowContainerType window_container_type,
  1067. const GURL& opener_url,
  1068. const content::mojom::CreateNewWindowParams& params) {
  1069. bool default_prevented = Emit(
  1070. "-will-add-new-contents", params.target_url, params.frame_name,
  1071. params.raw_features, params.disposition, *params.referrer, params.body);
  1072. // If the app prevented the default, redirect to CreateCustomWebContents,
  1073. // which always returns nullptr, which will result in the window open being
  1074. // prevented (window.open() will return null in the renderer).
  1075. return default_prevented;
  1076. }
  1077. void WebContents::SetNextChildWebPreferences(
  1078. const gin_helper::Dictionary preferences) {
  1079. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1080. v8::HandleScope handle_scope(isolate);
  1081. // Store these prefs for when Chrome calls WebContentsCreatedWithFullParams
  1082. // with the new child contents.
  1083. pending_child_web_preferences_.Reset(isolate, preferences.GetHandle());
  1084. }
  1085. content::WebContents* WebContents::CreateCustomWebContents(
  1086. content::RenderFrameHost* opener,
  1087. content::SiteInstance* source_site_instance,
  1088. bool is_new_browsing_instance,
  1089. const GURL& opener_url,
  1090. const std::string& frame_name,
  1091. const GURL& target_url,
  1092. const content::StoragePartitionConfig& partition_config,
  1093. content::SessionStorageNamespace* session_storage_namespace) {
  1094. return nullptr;
  1095. }
  1096. content::WebContents* WebContents::AddNewContents(
  1097. content::WebContents* source,
  1098. std::unique_ptr<content::WebContents> new_contents,
  1099. const GURL& target_url,
  1100. WindowOpenDisposition disposition,
  1101. const blink::mojom::WindowFeatures& window_features,
  1102. bool user_gesture,
  1103. bool* was_blocked) {
  1104. auto* tracker = ChildWebContentsTracker::FromWebContents(new_contents.get());
  1105. DCHECK(tracker);
  1106. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1107. v8::HandleScope handle_scope(isolate);
  1108. auto api_web_contents =
  1109. CreateAndTake(isolate, std::move(new_contents), Type::kBrowserWindow);
  1110. // We call RenderFrameCreated here as at this point the empty "about:blank"
  1111. // render frame has already been created. If the window never navigates again
  1112. // RenderFrameCreated won't be called and certain prefs like
  1113. // "kBackgroundColor" will not be applied.
  1114. auto* frame = api_web_contents->MainFrame();
  1115. if (frame) {
  1116. api_web_contents->HandleNewRenderFrame(frame);
  1117. }
  1118. if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
  1119. window_features.bounds.x(), window_features.bounds.y(),
  1120. window_features.bounds.width(), window_features.bounds.height(),
  1121. tracker->url, tracker->frame_name, tracker->referrer,
  1122. tracker->raw_features, tracker->body)) {
  1123. api_web_contents->Destroy();
  1124. }
  1125. return nullptr;
  1126. }
  1127. content::WebContents* WebContents::OpenURLFromTab(
  1128. content::WebContents* source,
  1129. const content::OpenURLParams& params,
  1130. base::OnceCallback<void(content::NavigationHandle&)>
  1131. navigation_handle_callback) {
  1132. auto weak_this = GetWeakPtr();
  1133. if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
  1134. Emit("-new-window", params.url, "", params.disposition, "", params.referrer,
  1135. params.post_data);
  1136. return nullptr;
  1137. }
  1138. if (!weak_this || !web_contents())
  1139. return nullptr;
  1140. content::NavigationController::LoadURLParams load_url_params(params.url);
  1141. load_url_params.referrer = params.referrer;
  1142. load_url_params.transition_type = params.transition;
  1143. load_url_params.extra_headers = params.extra_headers;
  1144. load_url_params.should_replace_current_entry =
  1145. params.should_replace_current_entry;
  1146. load_url_params.is_renderer_initiated = params.is_renderer_initiated;
  1147. load_url_params.started_from_context_menu = params.started_from_context_menu;
  1148. load_url_params.initiator_origin = params.initiator_origin;
  1149. load_url_params.source_site_instance = params.source_site_instance;
  1150. load_url_params.frame_tree_node_id = params.frame_tree_node_id;
  1151. load_url_params.redirect_chain = params.redirect_chain;
  1152. load_url_params.has_user_gesture = params.user_gesture;
  1153. load_url_params.blob_url_loader_factory = params.blob_url_loader_factory;
  1154. load_url_params.href_translate = params.href_translate;
  1155. load_url_params.reload_type = params.reload_type;
  1156. if (params.post_data) {
  1157. load_url_params.load_type =
  1158. content::NavigationController::LOAD_TYPE_HTTP_POST;
  1159. load_url_params.post_data = params.post_data;
  1160. }
  1161. source->GetController().LoadURLWithParams(load_url_params);
  1162. return source;
  1163. }
  1164. void WebContents::BeforeUnloadFired(content::WebContents* tab,
  1165. bool proceed,
  1166. bool* proceed_to_fire_unload) {
  1167. // Note that Chromium does not emit this for navigations.
  1168. // Emit returns true if preventDefault() was called, so !Emit will be true if
  1169. // the event should proceed.
  1170. *proceed_to_fire_unload = !Emit("-before-unload-fired", proceed);
  1171. }
  1172. void WebContents::SetContentsBounds(content::WebContents* source,
  1173. const gfx::Rect& rect) {
  1174. if (!Emit("content-bounds-updated", rect))
  1175. for (ExtendedWebContentsObserver& observer : observers_)
  1176. observer.OnSetContentBounds(rect);
  1177. }
  1178. void WebContents::CloseContents(content::WebContents* source) {
  1179. Emit("close");
  1180. auto* autofill_driver_factory =
  1181. AutofillDriverFactory::FromWebContents(web_contents());
  1182. if (autofill_driver_factory) {
  1183. autofill_driver_factory->CloseAllPopups();
  1184. }
  1185. Destroy();
  1186. }
  1187. void WebContents::ActivateContents(content::WebContents* source) {
  1188. for (ExtendedWebContentsObserver& observer : observers_)
  1189. observer.OnActivateContents();
  1190. }
  1191. void WebContents::UpdateTargetURL(content::WebContents* source,
  1192. const GURL& url) {
  1193. Emit("update-target-url", url);
  1194. }
  1195. bool WebContents::HandleKeyboardEvent(
  1196. content::WebContents* source,
  1197. const input::NativeWebKeyboardEvent& event) {
  1198. if (type_ == Type::kWebView && embedder_) {
  1199. // Send the unhandled keyboard events back to the embedder.
  1200. return embedder_->HandleKeyboardEvent(source, event);
  1201. } else {
  1202. return PlatformHandleKeyboardEvent(source, event);
  1203. }
  1204. }
  1205. #if !BUILDFLAG(IS_MAC)
  1206. // NOTE: The macOS version of this function is found in
  1207. // electron_api_web_contents_mac.mm, as it requires calling into objective-C
  1208. // code.
  1209. bool WebContents::PlatformHandleKeyboardEvent(
  1210. content::WebContents* source,
  1211. const input::NativeWebKeyboardEvent& event) {
  1212. // Check if the webContents has preferences and to ignore shortcuts
  1213. auto* web_preferences = WebContentsPreferences::From(source);
  1214. if (web_preferences && web_preferences->ShouldIgnoreMenuShortcuts())
  1215. return false;
  1216. // Let the NativeWindow handle other parts.
  1217. if (owner_window()) {
  1218. owner_window()->HandleKeyboardEvent(source, event);
  1219. return true;
  1220. }
  1221. return false;
  1222. }
  1223. #endif
  1224. content::KeyboardEventProcessingResult WebContents::PreHandleKeyboardEvent(
  1225. content::WebContents* source,
  1226. const input::NativeWebKeyboardEvent& event) {
  1227. if (exclusive_access_manager_.HandleUserKeyEvent(event))
  1228. return content::KeyboardEventProcessingResult::HANDLED;
  1229. if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown ||
  1230. event.GetType() == blink::WebInputEvent::Type::kKeyUp) {
  1231. // For backwards compatibility, pretend that `kRawKeyDown` events are
  1232. // actually `kKeyDown`.
  1233. input::NativeWebKeyboardEvent tweaked_event(event);
  1234. if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown)
  1235. tweaked_event.SetType(blink::WebInputEvent::Type::kKeyDown);
  1236. bool prevent_default = Emit("before-input-event", tweaked_event);
  1237. if (prevent_default) {
  1238. return content::KeyboardEventProcessingResult::HANDLED;
  1239. }
  1240. }
  1241. return content::KeyboardEventProcessingResult::NOT_HANDLED;
  1242. }
  1243. void WebContents::ContentsZoomChange(bool zoom_in) {
  1244. Emit("zoom-changed", std::string_view{zoom_in ? "in" : "out"});
  1245. }
  1246. Profile* WebContents::GetProfile() {
  1247. return nullptr;
  1248. }
  1249. bool WebContents::IsFullscreen() const {
  1250. if (!owner_window())
  1251. return false;
  1252. return owner_window()->IsFullscreen() || is_html_fullscreen();
  1253. }
  1254. void WebContents::EnterFullscreen(const GURL& url,
  1255. ExclusiveAccessBubbleType bubble_type,
  1256. const int64_t display_id) {}
  1257. content::WebContents* WebContents::GetWebContentsForExclusiveAccess() {
  1258. return web_contents();
  1259. }
  1260. bool WebContents::CanUserEnterFullscreen() const {
  1261. return true;
  1262. }
  1263. bool WebContents::CanUserExitFullscreen() const {
  1264. return true;
  1265. }
  1266. bool WebContents::IsExclusiveAccessBubbleDisplayed() const {
  1267. return false;
  1268. }
  1269. void WebContents::EnterFullscreenModeForTab(
  1270. content::RenderFrameHost* requesting_frame,
  1271. const blink::mojom::FullscreenOptions& options) {
  1272. auto* source = content::WebContents::FromRenderFrameHost(requesting_frame);
  1273. auto* permission_helper =
  1274. WebContentsPermissionHelper::FromWebContents(source);
  1275. auto callback =
  1276. base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab,
  1277. base::Unretained(this), requesting_frame, options);
  1278. permission_helper->RequestFullscreenPermission(requesting_frame, callback);
  1279. }
  1280. void WebContents::OnEnterFullscreenModeForTab(
  1281. content::RenderFrameHost* requesting_frame,
  1282. const blink::mojom::FullscreenOptions& options,
  1283. bool allowed) {
  1284. if (!allowed || !owner_window())
  1285. return;
  1286. auto* source = content::WebContents::FromRenderFrameHost(requesting_frame);
  1287. if (IsFullscreenForTabOrPending(source)) {
  1288. DCHECK_EQ(fullscreen_frame_, source->GetFocusedFrame());
  1289. return;
  1290. }
  1291. owner_window()->set_fullscreen_transition_type(
  1292. NativeWindow::FullScreenTransitionType::kHTML);
  1293. exclusive_access_manager_.fullscreen_controller()->EnterFullscreenModeForTab(
  1294. requesting_frame, options.display_id);
  1295. SetHtmlApiFullscreen(true);
  1296. if (native_fullscreen_) {
  1297. // Explicitly trigger a view resize, as the size is not actually changing if
  1298. // the browser is fullscreened, too.
  1299. source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
  1300. }
  1301. }
  1302. void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
  1303. if (!owner_window())
  1304. return;
  1305. // This needs to be called before we exit fullscreen on the native window,
  1306. // or the controller will incorrectly think we weren't fullscreen and bail.
  1307. exclusive_access_manager_.fullscreen_controller()->ExitFullscreenModeForTab(
  1308. source);
  1309. SetHtmlApiFullscreen(false);
  1310. if (native_fullscreen_) {
  1311. // Explicitly trigger a view resize, as the size is not actually changing if
  1312. // the browser is fullscreened, too. Chrome does this indirectly from
  1313. // `chrome/browser/ui/exclusive_access/fullscreen_controller.cc`.
  1314. source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
  1315. }
  1316. }
  1317. void WebContents::RendererUnresponsive(
  1318. content::WebContents* source,
  1319. content::RenderWidgetHost* render_widget_host,
  1320. base::RepeatingClosure hang_monitor_restarter) {
  1321. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1322. v8::HandleScope handle_scope(isolate);
  1323. gin::Handle<gin_helper::internal::Event> event =
  1324. gin_helper::internal::Event::New(isolate);
  1325. v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
  1326. gin::Dictionary dict(isolate, event_object);
  1327. auto* web_contents_impl = static_cast<content::WebContentsImpl*>(source);
  1328. bool should_ignore = web_contents_impl->ShouldIgnoreUnresponsiveRenderer();
  1329. dict.Set("shouldIgnore", should_ignore);
  1330. bool visible = source->GetVisibility() == content::Visibility::VISIBLE;
  1331. dict.Set("visible", visible);
  1332. auto* rwh_impl =
  1333. static_cast<content::RenderWidgetHostImpl*>(render_widget_host);
  1334. dict.Set("rendererInitialized", rwh_impl->renderer_initialized());
  1335. EmitWithoutEvent("-unresponsive", event);
  1336. }
  1337. void WebContents::RendererResponsive(
  1338. content::WebContents* source,
  1339. content::RenderWidgetHost* render_widget_host) {
  1340. Emit("responsive");
  1341. }
  1342. bool WebContents::HandleContextMenu(content::RenderFrameHost& render_frame_host,
  1343. const content::ContextMenuParams& params) {
  1344. #if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  1345. if (!params.misspelled_word.empty() && spellcheck::UseBrowserSpellChecker()) {
  1346. SpellcheckService* spellcheck_service =
  1347. SpellcheckServiceFactory::GetForContext(
  1348. render_frame_host.GetBrowserContext());
  1349. if (spellcheck_service) {
  1350. spellcheck_platform::GetPerLanguageSuggestions(
  1351. spellcheck_service->platform_spell_checker(), params.misspelled_word,
  1352. base::BindOnce(&WebContents::OnGetPlatformSuggestionsComplete,
  1353. GetWeakPtr(), std::ref(render_frame_host), params));
  1354. }
  1355. } else {
  1356. #endif
  1357. Emit("context-menu",
  1358. std::make_tuple(params, &render_frame_host,
  1359. std::optional<std::vector<std::u16string>>{}));
  1360. #if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  1361. }
  1362. #endif
  1363. return true;
  1364. }
  1365. #if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
  1366. void WebContents::OnGetPlatformSuggestionsComplete(
  1367. content::RenderFrameHost& render_frame_host,
  1368. const content::ContextMenuParams& params,
  1369. const spellcheck::PerLanguageSuggestions&
  1370. platform_per_language_suggestions) {
  1371. std::vector<std::u16string> combined_suggestions;
  1372. spellcheck::FillSuggestions(platform_per_language_suggestions,
  1373. &combined_suggestions);
  1374. Emit("context-menu",
  1375. std::make_tuple(params, &render_frame_host,
  1376. std::make_optional(combined_suggestions)));
  1377. }
  1378. #endif
  1379. void WebContents::FindReply(content::WebContents* web_contents,
  1380. int request_id,
  1381. int number_of_matches,
  1382. const gfx::Rect& selection_rect,
  1383. int active_match_ordinal,
  1384. bool final_update) {
  1385. if (!final_update)
  1386. return;
  1387. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1388. v8::HandleScope handle_scope(isolate);
  1389. auto result = gin_helper::Dictionary::CreateEmpty(isolate);
  1390. result.Set("requestId", request_id);
  1391. result.Set("matches", number_of_matches);
  1392. result.Set("selectionArea", selection_rect);
  1393. result.Set("activeMatchOrdinal", active_match_ordinal);
  1394. result.Set("finalUpdate", final_update); // Deprecate after 2.0
  1395. Emit("found-in-page", result.GetHandle());
  1396. }
  1397. void WebContents::OnRequestPointerLock(content::WebContents* web_contents,
  1398. bool user_gesture,
  1399. bool last_unlocked_by_target,
  1400. bool allowed) {
  1401. if (allowed) {
  1402. exclusive_access_manager_.pointer_lock_controller()->RequestToLockPointer(
  1403. web_contents, user_gesture, last_unlocked_by_target);
  1404. } else {
  1405. web_contents->GotResponseToPointerLockRequest(
  1406. blink::mojom::PointerLockResult::kPermissionDenied);
  1407. }
  1408. }
  1409. void WebContents::RequestPointerLock(content::WebContents* web_contents,
  1410. bool user_gesture,
  1411. bool last_unlocked_by_target) {
  1412. auto* permission_helper =
  1413. WebContentsPermissionHelper::FromWebContents(web_contents);
  1414. permission_helper->RequestPointerLockPermission(
  1415. user_gesture, last_unlocked_by_target,
  1416. base::BindOnce(&WebContents::OnRequestPointerLock,
  1417. base::Unretained(this)));
  1418. }
  1419. void WebContents::LostPointerLock() {
  1420. exclusive_access_manager_.pointer_lock_controller()
  1421. ->ExitExclusiveAccessToPreviousState();
  1422. }
  1423. bool WebContents::IsWaitingForPointerLockPrompt(
  1424. content::WebContents* web_contents) {
  1425. return exclusive_access_manager_.pointer_lock_controller()
  1426. ->IsWaitingForPointerLockPrompt(web_contents);
  1427. }
  1428. void WebContents::OnRequestKeyboardLock(content::WebContents* web_contents,
  1429. bool esc_key_locked,
  1430. bool allowed) {
  1431. if (allowed) {
  1432. exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
  1433. web_contents, esc_key_locked);
  1434. } else {
  1435. web_contents->GotResponseToKeyboardLockRequest(false);
  1436. }
  1437. }
  1438. void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
  1439. bool esc_key_locked) {
  1440. auto* permission_helper =
  1441. WebContentsPermissionHelper::FromWebContents(web_contents);
  1442. permission_helper->RequestKeyboardLockPermission(
  1443. esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
  1444. base::Unretained(this)));
  1445. }
  1446. void WebContents::CancelKeyboardLockRequest(
  1447. content::WebContents* web_contents) {
  1448. exclusive_access_manager_.keyboard_lock_controller()
  1449. ->CancelKeyboardLockRequest(web_contents);
  1450. }
  1451. bool WebContents::CheckMediaAccessPermission(
  1452. content::RenderFrameHost* render_frame_host,
  1453. const url::Origin& security_origin,
  1454. blink::mojom::MediaStreamType type) {
  1455. auto* web_contents =
  1456. content::WebContents::FromRenderFrameHost(render_frame_host);
  1457. auto* permission_helper =
  1458. WebContentsPermissionHelper::FromWebContents(web_contents);
  1459. return permission_helper->CheckMediaAccessPermission(security_origin, type);
  1460. }
  1461. void WebContents::RequestMediaAccessPermission(
  1462. content::WebContents* web_contents,
  1463. const content::MediaStreamRequest& request,
  1464. content::MediaResponseCallback callback) {
  1465. auto* permission_helper =
  1466. WebContentsPermissionHelper::FromWebContents(web_contents);
  1467. permission_helper->RequestMediaAccessPermission(request, std::move(callback));
  1468. }
  1469. const void* const kJavaScriptDialogManagerKey = &kJavaScriptDialogManagerKey;
  1470. content::JavaScriptDialogManager* WebContents::GetJavaScriptDialogManager(
  1471. content::WebContents* source) {
  1472. // Indirect these delegate methods through a helper object whose lifetime is
  1473. // bound to that of the content::WebContents. This prevents the
  1474. // content::WebContents from calling methods on the Electron WebContents in
  1475. // the event that the Electron one is destroyed before the content one, as
  1476. // happens sometimes during shutdown or when webviews are involved.
  1477. class JSDialogManagerHelper : public content::JavaScriptDialogManager,
  1478. public base::SupportsUserData::Data {
  1479. public:
  1480. void RunJavaScriptDialog(content::WebContents* web_contents,
  1481. content::RenderFrameHost* rfh,
  1482. content::JavaScriptDialogType dialog_type,
  1483. const std::u16string& message_text,
  1484. const std::u16string& default_prompt_text,
  1485. DialogClosedCallback callback,
  1486. bool* did_suppress_message) override {
  1487. auto* wc = WebContents::From(web_contents);
  1488. if (wc)
  1489. wc->RunJavaScriptDialog(web_contents, rfh, dialog_type, message_text,
  1490. default_prompt_text, std::move(callback),
  1491. did_suppress_message);
  1492. }
  1493. void RunBeforeUnloadDialog(content::WebContents* web_contents,
  1494. content::RenderFrameHost* rfh,
  1495. bool is_reload,
  1496. DialogClosedCallback callback) override {
  1497. auto* wc = WebContents::From(web_contents);
  1498. if (wc)
  1499. wc->RunBeforeUnloadDialog(web_contents, rfh, is_reload,
  1500. std::move(callback));
  1501. }
  1502. void CancelDialogs(content::WebContents* web_contents,
  1503. bool reset_state) override {
  1504. auto* wc = WebContents::From(web_contents);
  1505. if (wc)
  1506. wc->CancelDialogs(web_contents, reset_state);
  1507. }
  1508. };
  1509. if (!source->GetUserData(kJavaScriptDialogManagerKey))
  1510. source->SetUserData(kJavaScriptDialogManagerKey,
  1511. std::make_unique<JSDialogManagerHelper>());
  1512. return static_cast<JSDialogManagerHelper*>(
  1513. source->GetUserData(kJavaScriptDialogManagerKey));
  1514. }
  1515. void WebContents::OnAudioStateChanged(bool audible) {
  1516. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1517. v8::HandleScope handle_scope(isolate);
  1518. gin::Handle<gin_helper::internal::Event> event =
  1519. gin_helper::internal::Event::New(isolate);
  1520. v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
  1521. gin::Dictionary dict(isolate, event_object);
  1522. dict.Set("audible", audible);
  1523. EmitWithoutEvent("audio-state-changed", event);
  1524. }
  1525. void WebContents::BeforeUnloadFired(bool proceed) {
  1526. // Do nothing, we override this method just to avoid compilation error since
  1527. // there are two virtual functions named BeforeUnloadFired.
  1528. }
  1529. void WebContents::HandleNewRenderFrame(
  1530. content::RenderFrameHost* render_frame_host) {
  1531. auto* rwhv = render_frame_host->GetView();
  1532. if (!rwhv)
  1533. return;
  1534. // Set the background color of RenderWidgetHostView.
  1535. auto* web_preferences = WebContentsPreferences::From(web_contents());
  1536. if (web_preferences)
  1537. SetBackgroundColor(web_preferences->GetBackgroundColor());
  1538. if (!background_throttling_)
  1539. render_frame_host->GetRenderViewHost()->SetSchedulerThrottling(false);
  1540. auto* rwh_impl =
  1541. static_cast<content::RenderWidgetHostImpl*>(rwhv->GetRenderWidgetHost());
  1542. if (rwh_impl)
  1543. rwh_impl->disable_hidden_ = !background_throttling_;
  1544. auto* web_frame = WebFrameMain::FromRenderFrameHost(render_frame_host);
  1545. if (web_frame)
  1546. web_frame->MaybeSetupMojoConnection();
  1547. }
  1548. void WebContents::OnBackgroundColorChanged() {
  1549. std::optional<SkColor> color = web_contents()->GetBackgroundColor();
  1550. if (color.has_value()) {
  1551. auto* const view = web_contents()->GetRenderWidgetHostView();
  1552. static_cast<content::RenderWidgetHostViewBase*>(view)
  1553. ->SetContentBackgroundColor(color.value());
  1554. }
  1555. }
  1556. void WebContents::RenderFrameCreated(
  1557. content::RenderFrameHost* render_frame_host) {
  1558. HandleNewRenderFrame(render_frame_host);
  1559. // RenderFrameCreated is called for speculative frames which may not be
  1560. // used in certain cross-origin navigations. Invoking
  1561. // RenderFrameHost::GetLifecycleState currently crashes when called for
  1562. // speculative frames so we need to filter it out for now. Check
  1563. // https://crbug.com/1183639 for details on when this can be removed.
  1564. auto* rfh_impl =
  1565. static_cast<content::RenderFrameHostImpl*>(render_frame_host);
  1566. if (rfh_impl->lifecycle_state() ==
  1567. content::RenderFrameHostImpl::LifecycleStateImpl::kSpeculative) {
  1568. return;
  1569. }
  1570. content::RenderFrameHost::LifecycleState lifecycle_state =
  1571. render_frame_host->GetLifecycleState();
  1572. if (lifecycle_state == content::RenderFrameHost::LifecycleState::kActive) {
  1573. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1574. v8::HandleScope handle_scope(isolate);
  1575. auto details = gin_helper::Dictionary::CreateEmpty(isolate);
  1576. details.SetGetter("frame", render_frame_host);
  1577. Emit("frame-created", details);
  1578. }
  1579. }
  1580. void WebContents::RenderFrameDeleted(
  1581. content::RenderFrameHost* render_frame_host) {
  1582. // A RenderFrameHost can be deleted when:
  1583. // - A WebContents is removed and its containing frames are disposed.
  1584. // - An <iframe> is removed from the DOM.
  1585. // - Cross-origin navigation creates a new RFH in a separate process which
  1586. // is swapped by content::RenderFrameHostManager.
  1587. // WebFrameMain::FromRenderFrameHost(rfh) will use the RFH's FrameTreeNode ID
  1588. // to find an existing instance of WebFrameMain. During a cross-origin
  1589. // navigation, the deleted RFH will be the old host which was swapped out. In
  1590. // this special case, we need to also ensure that WebFrameMain's internal RFH
  1591. // matches before marking it as disposed.
  1592. auto* web_frame = WebFrameMain::FromRenderFrameHost(render_frame_host);
  1593. if (web_frame) {
  1594. // Need to directly compare frame tokens as frames pending deletion can no
  1595. // longer be looked up using content::RenderFrameHost::FromFrameToken().
  1596. if (web_frame->frame_token_ == render_frame_host->GetGlobalFrameToken()) {
  1597. web_frame->MarkRenderFrameDisposed();
  1598. }
  1599. }
  1600. }
  1601. void WebContents::RenderFrameHostChanged(content::RenderFrameHost* old_host,
  1602. content::RenderFrameHost* new_host) {
  1603. if (new_host->IsInPrimaryMainFrame()) {
  1604. if (old_host)
  1605. old_host->GetRenderWidgetHost()->RemoveInputEventObserver(this);
  1606. if (new_host)
  1607. new_host->GetRenderWidgetHost()->AddInputEventObserver(this);
  1608. }
  1609. // During cross-origin navigation, a FrameTreeNode will swap out its RFH.
  1610. // If an instance of WebFrameMain exists, it will need to have its RFH
  1611. // swapped as well.
  1612. //
  1613. // |old_host| can be a nullptr so we use |new_host| for looking up the
  1614. // WebFrameMain instance.
  1615. auto* web_frame =
  1616. WebFrameMain::FromFrameTreeNodeId(new_host->GetFrameTreeNodeId());
  1617. if (web_frame) {
  1618. web_frame->UpdateRenderFrameHost(new_host);
  1619. }
  1620. }
  1621. void WebContents::FrameDeleted(content::FrameTreeNodeId frame_tree_node_id) {
  1622. auto* web_frame = WebFrameMain::FromFrameTreeNodeId(frame_tree_node_id);
  1623. if (web_frame)
  1624. web_frame->Destroyed();
  1625. }
  1626. void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
  1627. // This event is necessary for tracking any states with respect to
  1628. // intermediate render view hosts aka speculative render view hosts. Currently
  1629. // used by object-registry.js to ref count remote objects.
  1630. Emit("render-view-deleted",
  1631. render_view_host->GetProcess()->GetID().GetUnsafeValue());
  1632. if (web_contents()->GetRenderViewHost() == render_view_host) {
  1633. // When the RVH that has been deleted is the current RVH it means that the
  1634. // the web contents are being closed. This is communicated by this event.
  1635. // Currently tracked by guest-window-manager.ts to destroy the
  1636. // BrowserWindow.
  1637. Emit("current-render-view-deleted",
  1638. render_view_host->GetProcess()->GetID().GetUnsafeValue());
  1639. }
  1640. }
  1641. void WebContents::PrimaryMainFrameRenderProcessGone(
  1642. base::TerminationStatus status) {
  1643. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1644. v8::HandleScope handle_scope(isolate);
  1645. auto details = gin_helper::Dictionary::CreateEmpty(isolate);
  1646. details.Set("reason", status);
  1647. details.Set("exitCode", web_contents()->GetCrashedErrorCode());
  1648. Emit("render-process-gone", details);
  1649. }
  1650. void WebContents::PluginCrashed(const base::FilePath& plugin_path,
  1651. base::ProcessId plugin_pid) {
  1652. #if BUILDFLAG(ENABLE_PLUGINS)
  1653. content::WebPluginInfo info;
  1654. auto* plugin_service = content::PluginService::GetInstance();
  1655. plugin_service->GetPluginInfoByPath(plugin_path, &info);
  1656. Emit("plugin-crashed", info.name, info.version);
  1657. #endif // BUILDFLAG(ENABLE_PLUGINS)
  1658. }
  1659. void WebContents::MediaStartedPlaying(const MediaPlayerInfo& video_type,
  1660. const content::MediaPlayerId& id) {
  1661. Emit("media-started-playing");
  1662. }
  1663. void WebContents::MediaStoppedPlaying(
  1664. const MediaPlayerInfo& video_type,
  1665. const content::MediaPlayerId& id,
  1666. content::WebContentsObserver::MediaStoppedReason reason) {
  1667. Emit("media-paused");
  1668. }
  1669. void WebContents::DidChangeThemeColor() {
  1670. auto theme_color = web_contents()->GetThemeColor();
  1671. if (theme_color) {
  1672. Emit("did-change-theme-color", electron::ToRGBHex(theme_color.value()));
  1673. } else {
  1674. Emit("did-change-theme-color", nullptr);
  1675. }
  1676. }
  1677. void WebContents::DidAcquireFullscreen(content::RenderFrameHost* rfh) {
  1678. set_fullscreen_frame(rfh);
  1679. }
  1680. void WebContents::OnWebContentsFocused(
  1681. content::RenderWidgetHost* render_widget_host) {
  1682. Emit("focus");
  1683. }
  1684. void WebContents::OnWebContentsLostFocus(
  1685. content::RenderWidgetHost* render_widget_host) {
  1686. Emit("blur");
  1687. }
  1688. void WebContents::DOMContentLoaded(
  1689. content::RenderFrameHost* render_frame_host) {
  1690. auto* web_frame = WebFrameMain::FromRenderFrameHost(render_frame_host);
  1691. if (web_frame)
  1692. web_frame->DOMContentLoaded();
  1693. if (!render_frame_host->GetParent())
  1694. Emit("dom-ready");
  1695. }
  1696. void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
  1697. const GURL& validated_url) {
  1698. bool is_main_frame = !render_frame_host->GetParent();
  1699. int32_t frame_process_id =
  1700. render_frame_host->GetProcess()->GetID().GetUnsafeValue();
  1701. int frame_routing_id = render_frame_host->GetRoutingID();
  1702. auto weak_this = GetWeakPtr();
  1703. Emit("did-frame-finish-load", is_main_frame, frame_process_id,
  1704. frame_routing_id);
  1705. // ⚠️WARNING!⚠️
  1706. // Emit() triggers JS which can call destroy() on |this|. It's not safe to
  1707. // assume that |this| points to valid memory at this point.
  1708. if (is_main_frame && weak_this && web_contents())
  1709. Emit("did-finish-load");
  1710. }
  1711. void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
  1712. const GURL& url,
  1713. int error_code) {
  1714. // See DocumentLoader::StartLoadingResponse() - when we navigate to a media
  1715. // resource the original request for the media resource, which resulted in a
  1716. // committed navigation, is simply discarded. The media element created
  1717. // inside the MediaDocument then makes *another new* request for the same
  1718. // media resource.
  1719. bool is_media_document =
  1720. media::IsSupportedMediaMimeType(web_contents()->GetContentsMimeType());
  1721. if (error_code == net::ERR_ABORTED && is_media_document)
  1722. return;
  1723. bool is_main_frame = !render_frame_host->GetParent();
  1724. int32_t frame_process_id =
  1725. render_frame_host->GetProcess()->GetID().GetUnsafeValue();
  1726. int frame_routing_id = render_frame_host->GetRoutingID();
  1727. Emit("did-fail-load", error_code, "", url, is_main_frame, frame_process_id,
  1728. frame_routing_id);
  1729. }
  1730. void WebContents::DidStartLoading() {
  1731. Emit("did-start-loading");
  1732. }
  1733. void WebContents::DidStopLoading() {
  1734. auto* web_preferences = WebContentsPreferences::From(web_contents());
  1735. if (web_preferences && web_preferences->ShouldUsePreferredSizeMode())
  1736. web_contents()->GetRenderViewHost()->EnablePreferredSizeMode();
  1737. Emit("did-stop-loading");
  1738. }
  1739. bool WebContents::EmitNavigationEvent(
  1740. const std::string& event_name,
  1741. content::NavigationHandle* navigation_handle) {
  1742. bool is_main_frame = navigation_handle->IsInMainFrame();
  1743. int frame_process_id = -1, frame_routing_id = -1;
  1744. content::RenderFrameHost* frame_host = GetRenderFrameHost(navigation_handle);
  1745. if (frame_host) {
  1746. frame_process_id = frame_host->GetProcess()->GetID().GetUnsafeValue();
  1747. frame_routing_id = frame_host->GetRoutingID();
  1748. }
  1749. bool is_same_document = navigation_handle->IsSameDocument();
  1750. auto url = navigation_handle->GetURL();
  1751. content::RenderFrameHost* initiator_frame_host =
  1752. navigation_handle->GetInitiatorFrameToken().has_value()
  1753. ? content::RenderFrameHost::FromFrameToken(
  1754. content::GlobalRenderFrameHostToken(
  1755. navigation_handle->GetInitiatorProcessId(),
  1756. navigation_handle->GetInitiatorFrameToken().value()))
  1757. : nullptr;
  1758. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1759. v8::HandleScope handle_scope(isolate);
  1760. gin::Handle<gin_helper::internal::Event> event =
  1761. gin_helper::internal::Event::New(isolate);
  1762. v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
  1763. gin_helper::Dictionary dict(isolate, event_object);
  1764. dict.Set("url", url);
  1765. dict.Set("isSameDocument", is_same_document);
  1766. dict.Set("isMainFrame", is_main_frame);
  1767. dict.Set("processId", frame_process_id);
  1768. dict.Set("routingId", frame_routing_id);
  1769. dict.SetGetter("frame", frame_host);
  1770. dict.SetGetter("initiator", initiator_frame_host);
  1771. EmitWithoutEvent(event_name, event, url, is_same_document, is_main_frame,
  1772. frame_process_id, frame_routing_id);
  1773. return event->GetDefaultPrevented();
  1774. }
  1775. void WebContents::OnFirstNonEmptyLayout(
  1776. content::RenderFrameHost* render_frame_host) {
  1777. if (render_frame_host == web_contents()->GetPrimaryMainFrame()) {
  1778. Emit("ready-to-show");
  1779. }
  1780. }
  1781. void WebContents::DraggableRegionsChanged(
  1782. const std::vector<blink::mojom::DraggableRegionPtr>& regions,
  1783. content::WebContents* contents) {
  1784. if (owner_window() && owner_window()->has_frame()) {
  1785. return;
  1786. }
  1787. draggable_region_ = DraggableRegionsToSkRegion(regions);
  1788. }
  1789. SkRegion* WebContents::draggable_region() {
  1790. return g_disable_draggable_regions ? nullptr : draggable_region_.get();
  1791. }
  1792. void WebContents::DidStartNavigation(
  1793. content::NavigationHandle* navigation_handle) {
  1794. EmitNavigationEvent("did-start-navigation", navigation_handle);
  1795. }
  1796. void WebContents::DidRedirectNavigation(
  1797. content::NavigationHandle* navigation_handle) {
  1798. EmitNavigationEvent("did-redirect-navigation", navigation_handle);
  1799. }
  1800. void WebContents::ReadyToCommitNavigation(
  1801. content::NavigationHandle* navigation_handle) {
  1802. // Don't focus content in an inactive window.
  1803. if (!owner_window())
  1804. return;
  1805. #if BUILDFLAG(IS_MAC)
  1806. if (!owner_window()->IsActive())
  1807. return;
  1808. #else
  1809. if (!owner_window()->widget()->IsActive())
  1810. return;
  1811. #endif
  1812. // Don't focus content after subframe navigations.
  1813. if (!navigation_handle->IsInMainFrame())
  1814. return;
  1815. // Only focus for top-level contents.
  1816. if (type_ != Type::kBrowserWindow)
  1817. return;
  1818. web_contents()->SetInitialFocus();
  1819. }
  1820. void WebContents::DidFinishNavigation(
  1821. content::NavigationHandle* navigation_handle) {
  1822. if (owner_window_) {
  1823. owner_window_->NotifyLayoutWindowControlsOverlay();
  1824. }
  1825. if (!navigation_handle->HasCommitted())
  1826. return;
  1827. bool is_main_frame = navigation_handle->IsInMainFrame();
  1828. content::RenderFrameHost* frame_host =
  1829. navigation_handle->GetRenderFrameHost();
  1830. int frame_process_id = -1, frame_routing_id = -1;
  1831. if (frame_host) {
  1832. frame_process_id = frame_host->GetProcess()->GetID().GetUnsafeValue();
  1833. frame_routing_id = frame_host->GetRoutingID();
  1834. }
  1835. if (!navigation_handle->IsErrorPage()) {
  1836. // FIXME: All the Emit() calls below could potentially result in |this|
  1837. // being destroyed (by JS listening for the event and calling
  1838. // webContents.destroy()).
  1839. auto url = navigation_handle->GetURL();
  1840. bool is_same_document = navigation_handle->IsSameDocument();
  1841. if (is_same_document) {
  1842. Emit("did-navigate-in-page", url, is_main_frame, frame_process_id,
  1843. frame_routing_id);
  1844. } else {
  1845. const net::HttpResponseHeaders* http_response =
  1846. navigation_handle->GetResponseHeaders();
  1847. std::string http_status_text;
  1848. int http_response_code = -1;
  1849. if (http_response) {
  1850. http_status_text = http_response->GetStatusText();
  1851. http_response_code = http_response->response_code();
  1852. }
  1853. Emit("did-frame-navigate", url, http_response_code, http_status_text,
  1854. is_main_frame, frame_process_id, frame_routing_id);
  1855. if (is_main_frame) {
  1856. Emit("did-navigate", url, http_response_code, http_status_text);
  1857. }
  1858. }
  1859. if (is_guest())
  1860. Emit("load-commit", url, is_main_frame);
  1861. } else {
  1862. auto url = navigation_handle->GetURL();
  1863. int code = navigation_handle->GetNetErrorCode();
  1864. auto description = net::ErrorToShortString(code);
  1865. Emit("did-fail-provisional-load", code, description, url, is_main_frame,
  1866. frame_process_id, frame_routing_id);
  1867. // Do not emit "did-fail-load" for canceled requests.
  1868. if (code != net::ERR_ABORTED) {
  1869. util::EmitWarning(
  1870. base::StrCat({"Failed to load URL: ", url.possibly_invalid_spec(),
  1871. " with error: ", description}),
  1872. "electron");
  1873. Emit("did-fail-load", code, description, url, is_main_frame,
  1874. frame_process_id, frame_routing_id);
  1875. }
  1876. }
  1877. content::NavigationEntry* entry = navigation_handle->GetNavigationEntry();
  1878. // This check is needed due to an issue in Chromium
  1879. // Check the Chromium issue to keep updated:
  1880. // https://bugs.chromium.org/p/chromium/issues/detail?id=1178663
  1881. // If a history entry has been made and the forward/back call has been made,
  1882. // proceed with setting the new title
  1883. if (entry && (entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK))
  1884. WebContents::TitleWasSet(entry);
  1885. }
  1886. void WebContents::TitleWasSet(content::NavigationEntry* entry) {
  1887. std::u16string final_title;
  1888. bool explicit_set = true;
  1889. if (entry) {
  1890. auto title = entry->GetTitle();
  1891. auto url = entry->GetURL();
  1892. if (url.SchemeIsFile() && title.empty()) {
  1893. final_title = base::UTF8ToUTF16(url.ExtractFileName());
  1894. explicit_set = false;
  1895. } else {
  1896. final_title = title;
  1897. }
  1898. } else {
  1899. final_title = web_contents()->GetTitle();
  1900. }
  1901. for (ExtendedWebContentsObserver& observer : observers_)
  1902. observer.OnPageTitleUpdated(final_title, explicit_set);
  1903. Emit("page-title-updated", final_title, explicit_set);
  1904. }
  1905. void WebContents::DidUpdateFaviconURL(
  1906. content::RenderFrameHost* render_frame_host,
  1907. const std::vector<blink::mojom::FaviconURLPtr>& urls) {
  1908. std::set<GURL> unique_urls;
  1909. for (const auto& iter : urls) {
  1910. if (iter->icon_type != blink::mojom::FaviconIconType::kFavicon)
  1911. continue;
  1912. const GURL& url = iter->icon_url;
  1913. if (url.is_valid())
  1914. unique_urls.insert(url);
  1915. }
  1916. Emit("page-favicon-updated", unique_urls);
  1917. }
  1918. void WebContents::DevToolsReloadPage() {
  1919. Emit("devtools-reload-page");
  1920. }
  1921. void WebContents::DevToolsFocused() {
  1922. Emit("devtools-focused");
  1923. }
  1924. void WebContents::DevToolsOpened() {
  1925. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1926. v8::HandleScope handle_scope(isolate);
  1927. DCHECK(inspectable_web_contents_);
  1928. DCHECK(inspectable_web_contents_->GetDevToolsWebContents());
  1929. auto handle = FromOrCreate(
  1930. isolate, inspectable_web_contents_->GetDevToolsWebContents());
  1931. devtools_web_contents_.Reset(isolate, handle.ToV8());
  1932. // Set inspected tabID.
  1933. inspectable_web_contents_->CallClientFunction(
  1934. "DevToolsAPI", "setInspectedTabId", base::Value(ID()));
  1935. // Inherit owner window in devtools when it doesn't have one.
  1936. auto* devtools = inspectable_web_contents_->GetDevToolsWebContents();
  1937. bool has_window = devtools->GetUserData(NativeWindowRelay::UserDataKey());
  1938. if (owner_window() && !has_window)
  1939. handle->SetOwnerWindow(devtools, owner_window());
  1940. Emit("devtools-opened");
  1941. }
  1942. void WebContents::DevToolsClosed() {
  1943. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1944. v8::HandleScope handle_scope(isolate);
  1945. devtools_web_contents_.Reset();
  1946. Emit("devtools-closed");
  1947. }
  1948. void WebContents::DevToolsResized() {
  1949. for (ExtendedWebContentsObserver& observer : observers_)
  1950. observer.OnDevToolsResized();
  1951. }
  1952. void WebContents::SetOwnerWindow(NativeWindow* owner_window) {
  1953. SetOwnerWindow(GetWebContents(), owner_window);
  1954. }
  1955. void WebContents::SetOwnerBaseWindow(std::optional<BaseWindow*> owner_window) {
  1956. SetOwnerWindow(GetWebContents(),
  1957. owner_window ? (*owner_window)->window() : nullptr);
  1958. }
  1959. void WebContents::SetOwnerWindow(content::WebContents* web_contents,
  1960. NativeWindow* owner_window) {
  1961. if (owner_window_) {
  1962. owner_window_->RemoveBackgroundThrottlingSource(this);
  1963. }
  1964. if (owner_window) {
  1965. owner_window_ = owner_window->GetWeakPtr();
  1966. NativeWindowRelay::CreateForWebContents(web_contents,
  1967. owner_window->GetWeakPtr());
  1968. owner_window_->AddBackgroundThrottlingSource(this);
  1969. } else {
  1970. owner_window_ = nullptr;
  1971. web_contents->RemoveUserData(NativeWindowRelay::UserDataKey());
  1972. }
  1973. auto* osr_wcv = GetOffScreenWebContentsView();
  1974. if (osr_wcv)
  1975. osr_wcv->SetNativeWindow(owner_window);
  1976. }
  1977. content::WebContents* WebContents::GetWebContents() const {
  1978. if (!inspectable_web_contents_)
  1979. return nullptr;
  1980. return inspectable_web_contents_->GetWebContents();
  1981. }
  1982. content::WebContents* WebContents::GetDevToolsWebContents() const {
  1983. if (!inspectable_web_contents_)
  1984. return nullptr;
  1985. return inspectable_web_contents_->GetDevToolsWebContents();
  1986. }
  1987. void WebContents::WebContentsDestroyed() {
  1988. // Clear the pointer stored in wrapper.
  1989. if (GetAllWebContents().Lookup(id_))
  1990. GetAllWebContents().Remove(id_);
  1991. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  1992. v8::HandleScope scope(isolate);
  1993. v8::Local<v8::Object> wrapper;
  1994. if (!GetWrapper(isolate).ToLocal(&wrapper))
  1995. return;
  1996. wrapper->SetAlignedPointerInInternalField(0, nullptr);
  1997. // Tell WebViewGuestDelegate that the WebContents has been destroyed.
  1998. if (guest_delegate_)
  1999. guest_delegate_->WillDestroy();
  2000. Observe(nullptr);
  2001. Emit("destroyed");
  2002. }
  2003. void WebContents::NavigationEntryCommitted(
  2004. const content::LoadCommittedDetails& details) {
  2005. Emit("navigation-entry-committed", details.entry->GetURL(),
  2006. details.is_same_document, details.did_replace_entry);
  2007. }
  2008. bool WebContents::GetBackgroundThrottling() const {
  2009. return background_throttling_;
  2010. }
  2011. void WebContents::SetBackgroundThrottling(bool allowed) {
  2012. background_throttling_ = allowed;
  2013. if (owner_window_) {
  2014. owner_window_->UpdateBackgroundThrottlingState();
  2015. }
  2016. auto* rfh = web_contents()->GetPrimaryMainFrame();
  2017. if (!rfh)
  2018. return;
  2019. auto* rwhv = rfh->GetView();
  2020. if (!rwhv)
  2021. return;
  2022. auto* rwh_impl =
  2023. static_cast<content::RenderWidgetHostImpl*>(rwhv->GetRenderWidgetHost());
  2024. if (!rwh_impl)
  2025. return;
  2026. rwh_impl->disable_hidden_ = !background_throttling_;
  2027. web_contents()->GetRenderViewHost()->SetSchedulerThrottling(allowed);
  2028. if (rwh_impl->is_hidden()) {
  2029. rwh_impl->WasShown({});
  2030. }
  2031. }
  2032. int32_t WebContents::GetProcessID() const {
  2033. return web_contents()
  2034. ->GetPrimaryMainFrame()
  2035. ->GetProcess()
  2036. ->GetID()
  2037. .GetUnsafeValue();
  2038. }
  2039. base::ProcessId WebContents::GetOSProcessID() const {
  2040. base::ProcessHandle process_handle = web_contents()
  2041. ->GetPrimaryMainFrame()
  2042. ->GetProcess()
  2043. ->GetProcess()
  2044. .Handle();
  2045. return base::GetProcId(process_handle);
  2046. }
  2047. bool WebContents::Equal(const WebContents* web_contents) const {
  2048. return ID() == web_contents->ID();
  2049. }
  2050. GURL WebContents::GetURL() const {
  2051. return web_contents()->GetLastCommittedURL();
  2052. }
  2053. void WebContents::LoadURL(const GURL& url,
  2054. const gin_helper::Dictionary& options) {
  2055. if (!url.is_valid() || url.spec().size() > url::kMaxURLChars) {
  2056. Emit("did-fail-load", static_cast<int>(net::ERR_INVALID_URL),
  2057. net::ErrorToShortString(net::ERR_INVALID_URL),
  2058. url.possibly_invalid_spec(), true);
  2059. return;
  2060. }
  2061. content::NavigationController::LoadURLParams params(url);
  2062. if (!options.Get("httpReferrer", &params.referrer)) {
  2063. GURL http_referrer;
  2064. if (options.Get("httpReferrer", &http_referrer))
  2065. params.referrer =
  2066. content::Referrer(http_referrer.GetAsReferrer(),
  2067. network::mojom::ReferrerPolicy::kDefault);
  2068. }
  2069. std::string user_agent;
  2070. if (options.Get("userAgent", &user_agent))
  2071. SetUserAgent(user_agent);
  2072. std::string extra_headers;
  2073. if (options.Get("extraHeaders", &extra_headers))
  2074. params.extra_headers = extra_headers;
  2075. scoped_refptr<network::ResourceRequestBody> body;
  2076. if (options.Get("postData", &body)) {
  2077. params.post_data = body;
  2078. params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
  2079. }
  2080. GURL base_url_for_data_url;
  2081. if (options.Get("baseURLForDataURL", &base_url_for_data_url)) {
  2082. params.base_url_for_data_url = base_url_for_data_url;
  2083. params.load_type = content::NavigationController::LOAD_TYPE_DATA;
  2084. }
  2085. bool reload_ignoring_cache = false;
  2086. if (options.Get("reloadIgnoringCache", &reload_ignoring_cache) &&
  2087. reload_ignoring_cache) {
  2088. params.reload_type = content::ReloadType::BYPASSING_CACHE;
  2089. }
  2090. // Calling LoadURLWithParams() can trigger JS which destroys |this|.
  2091. auto weak_this = GetWeakPtr();
  2092. params.transition_type = ui::PageTransitionFromInt(
  2093. ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
  2094. params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
  2095. // It's not safe to start a new navigation or otherwise discard the current
  2096. // one while the call that started it is still on the stack. See
  2097. // http://crbug.com/347742.
  2098. auto& ctrl_impl = static_cast<content::NavigationControllerImpl&>(
  2099. web_contents()->GetController());
  2100. if (ctrl_impl.in_navigate_to_pending_entry()) {
  2101. Emit("did-fail-load", static_cast<int>(net::ERR_FAILED),
  2102. net::ErrorToShortString(net::ERR_FAILED), url.possibly_invalid_spec(),
  2103. true);
  2104. return;
  2105. }
  2106. // Discard non-committed entries to ensure we don't re-use a pending entry.
  2107. web_contents()->GetController().DiscardNonCommittedEntries();
  2108. web_contents()->GetController().LoadURLWithParams(params);
  2109. // ⚠️WARNING!⚠️
  2110. // LoadURLWithParams() triggers JS events which can call destroy() on |this|.
  2111. // It's not safe to assume that |this| points to valid memory at this point.
  2112. if (!weak_this || !web_contents())
  2113. return;
  2114. // Required to make beforeunload handler work.
  2115. NotifyUserActivation();
  2116. }
  2117. // TODO(MarshallOfSound): Figure out what we need to do with post data here, I
  2118. // believe the default behavior when we pass "true" is to phone out to the
  2119. // delegate and then the controller expects this method to be called again with
  2120. // "false" if the user approves the reload. For now this would result in
  2121. // ".reload()" calls on POST data domains failing silently. Passing false would
  2122. // result in them succeeding, but reposting which although more correct could be
  2123. // considering a breaking change.
  2124. void WebContents::Reload() {
  2125. web_contents()->GetController().Reload(content::ReloadType::NORMAL,
  2126. /* check_for_repost */ true);
  2127. }
  2128. void WebContents::ReloadIgnoringCache() {
  2129. web_contents()->GetController().Reload(content::ReloadType::BYPASSING_CACHE,
  2130. /* check_for_repost */ true);
  2131. }
  2132. void WebContents::DownloadURL(const GURL& url, gin::Arguments* args) {
  2133. std::map<std::string, std::string> headers;
  2134. gin_helper::Dictionary options;
  2135. if (args->GetNext(&options)) {
  2136. if (options.Has("headers") && !options.Get("headers", &headers)) {
  2137. args->ThrowTypeError("Invalid value for headers - must be an object");
  2138. return;
  2139. }
  2140. }
  2141. std::unique_ptr<download::DownloadUrlParameters> download_params(
  2142. content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
  2143. web_contents(), url, MISSING_TRAFFIC_ANNOTATION));
  2144. for (const auto& [name, value] : headers) {
  2145. download_params->add_request_header(name, value);
  2146. }
  2147. auto* download_manager =
  2148. web_contents()->GetBrowserContext()->GetDownloadManager();
  2149. download_manager->DownloadUrl(std::move(download_params));
  2150. }
  2151. std::u16string WebContents::GetTitle() const {
  2152. return web_contents()->GetTitle();
  2153. }
  2154. bool WebContents::IsLoading() const {
  2155. return web_contents()->IsLoading();
  2156. }
  2157. bool WebContents::IsLoadingMainFrame() const {
  2158. return web_contents()->ShouldShowLoadingUI();
  2159. }
  2160. bool WebContents::IsWaitingForResponse() const {
  2161. return web_contents()->IsWaitingForResponse();
  2162. }
  2163. void WebContents::Stop() {
  2164. web_contents()->Stop();
  2165. }
  2166. bool WebContents::CanGoBack() const {
  2167. return web_contents()->GetController().CanGoBack();
  2168. }
  2169. void WebContents::GoBack() {
  2170. if (CanGoBack())
  2171. web_contents()->GetController().GoBack();
  2172. }
  2173. bool WebContents::CanGoForward() const {
  2174. return web_contents()->GetController().CanGoForward();
  2175. }
  2176. void WebContents::GoForward() {
  2177. if (CanGoForward())
  2178. web_contents()->GetController().GoForward();
  2179. }
  2180. bool WebContents::CanGoToOffset(int offset) const {
  2181. return web_contents()->GetController().CanGoToOffset(offset);
  2182. }
  2183. void WebContents::GoToOffset(int offset) {
  2184. if (CanGoToOffset(offset))
  2185. web_contents()->GetController().GoToOffset(offset);
  2186. }
  2187. bool WebContents::CanGoToIndex(int index) const {
  2188. return index >= 0 && index < GetHistoryLength();
  2189. }
  2190. void WebContents::GoToIndex(int index) {
  2191. if (CanGoToIndex(index))
  2192. web_contents()->GetController().GoToIndex(index);
  2193. }
  2194. int WebContents::GetActiveIndex() const {
  2195. return web_contents()->GetController().GetCurrentEntryIndex();
  2196. }
  2197. content::NavigationEntry* WebContents::GetNavigationEntryAtIndex(
  2198. int index) const {
  2199. return web_contents()->GetController().GetEntryAtIndex(index);
  2200. }
  2201. bool WebContents::RemoveNavigationEntryAtIndex(int index) {
  2202. if (!CanGoToIndex(index))
  2203. return false;
  2204. return web_contents()->GetController().RemoveEntryAtIndex(index);
  2205. }
  2206. std::vector<content::NavigationEntry*> WebContents::GetHistory() const {
  2207. const int history_length = GetHistoryLength();
  2208. auto& controller = web_contents()->GetController();
  2209. // If the history is empty, it contains only one entry and that is
  2210. // "InitialEntry"
  2211. if (history_length == 1 && controller.GetEntryAtIndex(0)->IsInitialEntry())
  2212. return {};
  2213. std::vector<content::NavigationEntry*> history;
  2214. history.reserve(history_length);
  2215. for (int i = 0; i < history_length; i++)
  2216. history.push_back(controller.GetEntryAtIndex(i));
  2217. return history;
  2218. }
  2219. void WebContents::RestoreHistory(
  2220. v8::Isolate* isolate,
  2221. gin_helper::ErrorThrower thrower,
  2222. int index,
  2223. const std::vector<v8::Local<v8::Value>>& entries) {
  2224. if (!web_contents()
  2225. ->GetController()
  2226. .GetLastCommittedEntry()
  2227. ->IsInitialEntry()) {
  2228. thrower.ThrowError(
  2229. "Cannot restore history on webContents that have previously loaded "
  2230. "a page.");
  2231. return;
  2232. }
  2233. auto navigation_entries = std::make_unique<
  2234. std::vector<std::unique_ptr<content::NavigationEntry>>>();
  2235. for (const auto& entry : entries) {
  2236. content::NavigationEntry* nav_entry = nullptr;
  2237. if (!gin::Converter<content::NavigationEntry*>::FromV8(isolate, entry,
  2238. &nav_entry) ||
  2239. !nav_entry) {
  2240. // Invalid entry, bail out early
  2241. thrower.ThrowError(
  2242. "Failed to restore navigation history: Invalid navigation entry at "
  2243. "index " +
  2244. std::to_string(index) + ".");
  2245. return;
  2246. }
  2247. navigation_entries->push_back(
  2248. std::unique_ptr<content::NavigationEntry>(nav_entry));
  2249. }
  2250. if (!navigation_entries->empty()) {
  2251. web_contents()->GetController().Restore(
  2252. index, content::RestoreType::kRestored, navigation_entries.get());
  2253. web_contents()->GetController().LoadIfNecessary();
  2254. }
  2255. }
  2256. void WebContents::ClearHistory() {
  2257. // In some rare cases (normally while there is no real history) we are in a
  2258. // state where we can't prune navigation entries
  2259. if (web_contents()->GetController().CanPruneAllButLastCommitted()) {
  2260. web_contents()->GetController().PruneAllButLastCommitted();
  2261. }
  2262. }
  2263. int WebContents::GetHistoryLength() const {
  2264. return web_contents()->GetController().GetEntryCount();
  2265. }
  2266. const std::string WebContents::GetWebRTCIPHandlingPolicy() const {
  2267. return blink::ToString(
  2268. web_contents()->GetMutableRendererPrefs()->webrtc_ip_handling_policy);
  2269. }
  2270. void WebContents::SetWebRTCIPHandlingPolicy(
  2271. const std::string& webrtc_ip_handling_policy) {
  2272. if (GetWebRTCIPHandlingPolicy() == webrtc_ip_handling_policy)
  2273. return;
  2274. web_contents()->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
  2275. blink::ToWebRTCIPHandlingPolicy(webrtc_ip_handling_policy);
  2276. web_contents()->SyncRendererPrefs();
  2277. }
  2278. v8::Local<v8::Value> WebContents::GetWebRTCUDPPortRange(
  2279. v8::Isolate* isolate) const {
  2280. auto* prefs = web_contents()->GetMutableRendererPrefs();
  2281. auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
  2282. dict.Set("min", static_cast<uint32_t>(prefs->webrtc_udp_min_port));
  2283. dict.Set("max", static_cast<uint32_t>(prefs->webrtc_udp_max_port));
  2284. return dict.GetHandle();
  2285. }
  2286. void WebContents::SetWebRTCUDPPortRange(gin::Arguments* args) {
  2287. uint32_t min = 0, max = 0;
  2288. gin_helper::Dictionary range;
  2289. if (!args->GetNext(&range) || !range.Get("min", &min) ||
  2290. !range.Get("max", &max)) {
  2291. gin_helper::ErrorThrower(args->isolate())
  2292. .ThrowError("'min' and 'max' are both required");
  2293. return;
  2294. }
  2295. if ((0 == min && 0 != max) || max > UINT16_MAX) {
  2296. gin_helper::ErrorThrower(args->isolate())
  2297. .ThrowError(
  2298. "'min' and 'max' must be in the (0, 65535] range or [0, 0]");
  2299. return;
  2300. }
  2301. if (min > max) {
  2302. gin_helper::ErrorThrower(args->isolate())
  2303. .ThrowError("'max' must be greater than or equal to 'min'");
  2304. return;
  2305. }
  2306. auto* prefs = web_contents()->GetMutableRendererPrefs();
  2307. if (prefs->webrtc_udp_min_port == static_cast<uint16_t>(min) &&
  2308. prefs->webrtc_udp_max_port == static_cast<uint16_t>(max)) {
  2309. return;
  2310. }
  2311. prefs->webrtc_udp_min_port = min;
  2312. prefs->webrtc_udp_max_port = max;
  2313. web_contents()->SyncRendererPrefs();
  2314. }
  2315. std::string WebContents::GetMediaSourceID(
  2316. content::WebContents* request_web_contents) {
  2317. auto* frame_host = web_contents()->GetPrimaryMainFrame();
  2318. if (!frame_host)
  2319. return {};
  2320. content::DesktopMediaID media_id(
  2321. content::DesktopMediaID::TYPE_WEB_CONTENTS,
  2322. content::DesktopMediaID::kNullId,
  2323. content::WebContentsMediaCaptureId(
  2324. frame_host->GetProcess()->GetDeprecatedID(),
  2325. frame_host->GetRoutingID()));
  2326. auto* request_frame_host = request_web_contents->GetPrimaryMainFrame();
  2327. if (!request_frame_host)
  2328. return {};
  2329. std::string id =
  2330. content::DesktopStreamsRegistry::GetInstance()->RegisterStream(
  2331. request_frame_host->GetProcess()->GetDeprecatedID(),
  2332. request_frame_host->GetRoutingID(),
  2333. url::Origin::Create(request_frame_host->GetLastCommittedURL()
  2334. .DeprecatedGetOriginAsURL()),
  2335. media_id, content::kRegistryStreamTypeTab);
  2336. return id;
  2337. }
  2338. bool WebContents::IsCrashed() const {
  2339. return web_contents()->IsCrashed();
  2340. }
  2341. void WebContents::ForcefullyCrashRenderer() {
  2342. content::RenderWidgetHostView* view =
  2343. web_contents()->GetRenderWidgetHostView();
  2344. if (!view)
  2345. return;
  2346. content::RenderWidgetHost* rwh = view->GetRenderWidgetHost();
  2347. if (!rwh)
  2348. return;
  2349. content::RenderProcessHost* rph = rwh->GetProcess();
  2350. if (rph) {
  2351. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  2352. // A generic |CrashDumpHungChildProcess()| is not implemented for Linux.
  2353. // Instead we send an explicit IPC to crash on the renderer's IO thread.
  2354. rph->ForceCrash();
  2355. #else
  2356. // Try to generate a crash report for the hung process.
  2357. #if !IS_MAS_BUILD()
  2358. CrashDumpHungChildProcess(rph->GetProcess().Handle());
  2359. #endif
  2360. rph->Shutdown(content::RESULT_CODE_HUNG);
  2361. #endif
  2362. }
  2363. }
  2364. void WebContents::SetUserAgent(const std::string& user_agent) {
  2365. blink::UserAgentOverride ua_override;
  2366. ua_override.ua_string_override = user_agent;
  2367. if (!user_agent.empty())
  2368. ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata();
  2369. web_contents()->SetUserAgentOverride(ua_override, false);
  2370. }
  2371. std::string WebContents::GetUserAgent() {
  2372. return web_contents()->GetUserAgentOverride().ua_string_override;
  2373. }
  2374. v8::Local<v8::Promise> WebContents::SavePage(
  2375. const base::FilePath& full_file_path,
  2376. const content::SavePageType& save_type) {
  2377. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  2378. gin_helper::Promise<void> promise(isolate);
  2379. v8::Local<v8::Promise> handle = promise.GetHandle();
  2380. if (!full_file_path.IsAbsolute()) {
  2381. promise.RejectWithErrorMessage("Path must be absolute");
  2382. return handle;
  2383. }
  2384. auto* handler = new SavePageHandler(web_contents(), std::move(promise));
  2385. handler->Handle(full_file_path, save_type);
  2386. return handle;
  2387. }
  2388. void WebContents::OpenDevTools(gin::Arguments* args) {
  2389. if (type_ == Type::kRemote)
  2390. return;
  2391. if (!enable_devtools_)
  2392. return;
  2393. std::string state;
  2394. if (type_ == Type::kWebView || type_ == Type::kBackgroundPage ||
  2395. !owner_window()) {
  2396. state = "detach";
  2397. }
  2398. bool activate = true;
  2399. std::string title;
  2400. if (args && args->Length() == 1) {
  2401. gin_helper::Dictionary options;
  2402. if (args->GetNext(&options)) {
  2403. options.Get("mode", &state);
  2404. options.Get("activate", &activate);
  2405. options.Get("title", &title);
  2406. }
  2407. }
  2408. DCHECK(inspectable_web_contents_);
  2409. inspectable_web_contents_->SetDockState(state);
  2410. inspectable_web_contents_->SetDevToolsTitle(base::UTF8ToUTF16(title));
  2411. inspectable_web_contents_->ShowDevTools(activate);
  2412. }
  2413. void WebContents::CloseDevTools() {
  2414. if (type_ == Type::kRemote)
  2415. return;
  2416. DCHECK(inspectable_web_contents_);
  2417. inspectable_web_contents_->CloseDevTools();
  2418. }
  2419. bool WebContents::IsDevToolsOpened() {
  2420. if (type_ == Type::kRemote)
  2421. return false;
  2422. DCHECK(inspectable_web_contents_);
  2423. return inspectable_web_contents_->IsDevToolsViewShowing();
  2424. }
  2425. std::u16string WebContents::GetDevToolsTitle() {
  2426. if (type_ == Type::kRemote)
  2427. return {};
  2428. DCHECK(inspectable_web_contents_);
  2429. return inspectable_web_contents_->GetDevToolsTitle();
  2430. }
  2431. void WebContents::SetDevToolsTitle(const std::u16string& title) {
  2432. inspectable_web_contents_->SetDevToolsTitle(title);
  2433. }
  2434. bool WebContents::IsDevToolsFocused() {
  2435. if (type_ == Type::kRemote)
  2436. return false;
  2437. DCHECK(inspectable_web_contents_);
  2438. return inspectable_web_contents_->GetView()->IsDevToolsViewFocused();
  2439. }
  2440. void WebContents::EnableDeviceEmulation(
  2441. const blink::DeviceEmulationParams& params) {
  2442. if (type_ == Type::kRemote)
  2443. return;
  2444. DCHECK(web_contents());
  2445. auto* frame_host = web_contents()->GetPrimaryMainFrame();
  2446. if (frame_host) {
  2447. auto* widget_host_impl = static_cast<content::RenderWidgetHostImpl*>(
  2448. frame_host->GetView()->GetRenderWidgetHost());
  2449. if (widget_host_impl) {
  2450. auto& frame_widget = widget_host_impl->GetAssociatedFrameWidget();
  2451. frame_widget->EnableDeviceEmulation(params);
  2452. }
  2453. }
  2454. }
  2455. void WebContents::DisableDeviceEmulation() {
  2456. if (type_ == Type::kRemote)
  2457. return;
  2458. DCHECK(web_contents());
  2459. auto* frame_host = web_contents()->GetPrimaryMainFrame();
  2460. if (frame_host) {
  2461. auto* widget_host_impl = static_cast<content::RenderWidgetHostImpl*>(
  2462. frame_host->GetView()->GetRenderWidgetHost());
  2463. if (widget_host_impl) {
  2464. auto& frame_widget = widget_host_impl->GetAssociatedFrameWidget();
  2465. frame_widget->DisableDeviceEmulation();
  2466. }
  2467. }
  2468. }
  2469. void WebContents::ToggleDevTools() {
  2470. if (IsDevToolsOpened())
  2471. CloseDevTools();
  2472. else
  2473. OpenDevTools(nullptr);
  2474. }
  2475. void WebContents::InspectElement(int x, int y) {
  2476. if (type_ == Type::kRemote)
  2477. return;
  2478. if (!enable_devtools_)
  2479. return;
  2480. DCHECK(inspectable_web_contents_);
  2481. if (!inspectable_web_contents_->GetDevToolsWebContents())
  2482. OpenDevTools(nullptr);
  2483. inspectable_web_contents_->InspectElement(x, y);
  2484. }
  2485. void WebContents::InspectSharedWorkerById(const std::string& workerId) {
  2486. if (type_ == Type::kRemote)
  2487. return;
  2488. if (!enable_devtools_)
  2489. return;
  2490. for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
  2491. if (agent_host->GetType() ==
  2492. content::DevToolsAgentHost::kTypeSharedWorker) {
  2493. if (agent_host->GetId() == workerId) {
  2494. OpenDevTools(nullptr);
  2495. inspectable_web_contents_->AttachTo(agent_host);
  2496. break;
  2497. }
  2498. }
  2499. }
  2500. }
  2501. std::vector<scoped_refptr<content::DevToolsAgentHost>>
  2502. WebContents::GetAllSharedWorkers() {
  2503. std::vector<scoped_refptr<content::DevToolsAgentHost>> shared_workers;
  2504. if (type_ == Type::kRemote)
  2505. return shared_workers;
  2506. if (!enable_devtools_)
  2507. return shared_workers;
  2508. for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
  2509. if (agent_host->GetType() ==
  2510. content::DevToolsAgentHost::kTypeSharedWorker) {
  2511. shared_workers.push_back(agent_host);
  2512. }
  2513. }
  2514. return shared_workers;
  2515. }
  2516. void WebContents::InspectSharedWorker() {
  2517. if (type_ == Type::kRemote)
  2518. return;
  2519. if (!enable_devtools_)
  2520. return;
  2521. for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
  2522. if (agent_host->GetType() ==
  2523. content::DevToolsAgentHost::kTypeSharedWorker) {
  2524. OpenDevTools(nullptr);
  2525. inspectable_web_contents_->AttachTo(agent_host);
  2526. break;
  2527. }
  2528. }
  2529. }
  2530. void WebContents::InspectServiceWorker() {
  2531. if (type_ == Type::kRemote)
  2532. return;
  2533. if (!enable_devtools_)
  2534. return;
  2535. for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
  2536. if (agent_host->GetType() ==
  2537. content::DevToolsAgentHost::kTypeServiceWorker) {
  2538. OpenDevTools(nullptr);
  2539. inspectable_web_contents_->AttachTo(agent_host);
  2540. break;
  2541. }
  2542. }
  2543. }
  2544. void WebContents::SetIgnoreMenuShortcuts(bool ignore) {
  2545. auto* web_preferences = WebContentsPreferences::From(web_contents());
  2546. DCHECK(web_preferences);
  2547. web_preferences->SetIgnoreMenuShortcuts(ignore);
  2548. }
  2549. void WebContents::SetAudioMuted(bool muted) {
  2550. web_contents()->SetAudioMuted(muted);
  2551. }
  2552. bool WebContents::IsAudioMuted() {
  2553. return web_contents()->IsAudioMuted();
  2554. }
  2555. bool WebContents::IsCurrentlyAudible() {
  2556. return web_contents()->IsCurrentlyAudible();
  2557. }
  2558. #if BUILDFLAG(ENABLE_PRINTING)
  2559. namespace {
  2560. void OnGetDeviceNameToUse(base::WeakPtr<content::WebContents> web_contents,
  2561. base::Value::Dict print_settings,
  2562. printing::CompletionCallback print_callback,
  2563. // <error, device_name>
  2564. std::pair<std::string, std::u16string> info) {
  2565. // The content::WebContents might be already deleted at this point, and the
  2566. // PrintViewManagerElectron class does not do null check.
  2567. if (!web_contents) {
  2568. if (print_callback)
  2569. std::move(print_callback).Run(false, "failed");
  2570. return;
  2571. }
  2572. if (!info.first.empty()) {
  2573. if (print_callback)
  2574. std::move(print_callback).Run(false, info.first);
  2575. return;
  2576. }
  2577. // If the user has passed a deviceName use it, otherwise use default printer.
  2578. print_settings.Set(printing::kSettingDeviceName, info.second);
  2579. if (!print_settings.FindInt(printing::kSettingDpiHorizontal)) {
  2580. gfx::Size dpi = GetDefaultPrinterDPI(info.second);
  2581. print_settings.Set(printing::kSettingDpiHorizontal, dpi.width());
  2582. print_settings.Set(printing::kSettingDpiVertical, dpi.height());
  2583. }
  2584. auto* print_view_manager =
  2585. PrintViewManagerElectron::FromWebContents(web_contents.get());
  2586. if (!print_view_manager)
  2587. return;
  2588. content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents.get());
  2589. print_view_manager->PrintNow(rfh, std::move(print_settings),
  2590. std::move(print_callback));
  2591. }
  2592. void OnPDFCreated(gin_helper::Promise<v8::Local<v8::Value>> promise,
  2593. print_to_pdf::PdfPrintResult print_result,
  2594. scoped_refptr<base::RefCountedMemory> data) {
  2595. if (print_result != print_to_pdf::PdfPrintResult::kPrintSuccess) {
  2596. promise.RejectWithErrorMessage(
  2597. "Failed to generate PDF: " +
  2598. print_to_pdf::PdfPrintResultToString(print_result));
  2599. return;
  2600. }
  2601. v8::Isolate* isolate = promise.isolate();
  2602. gin_helper::Locker locker(isolate);
  2603. v8::HandleScope handle_scope(isolate);
  2604. v8::Context::Scope context_scope(
  2605. v8::Local<v8::Context>::New(isolate, promise.GetContext()));
  2606. v8::Local<v8::Value> buffer =
  2607. node::Buffer::Copy(isolate, reinterpret_cast<const char*>(data->front()),
  2608. data->size())
  2609. .ToLocalChecked();
  2610. promise.Resolve(buffer);
  2611. }
  2612. } // namespace
  2613. void WebContents::Print(gin::Arguments* args) {
  2614. auto options = gin_helper::Dictionary::CreateEmpty(args->isolate());
  2615. base::Value::Dict settings;
  2616. if (args->Length() >= 1 && !args->GetNext(&options)) {
  2617. gin_helper::ErrorThrower(args->isolate())
  2618. .ThrowError("webContents.print(): Invalid print settings specified.");
  2619. return;
  2620. }
  2621. printing::CompletionCallback callback;
  2622. if (args->Length() == 2 && !args->GetNext(&callback)) {
  2623. gin_helper::ErrorThrower(args->isolate())
  2624. .ThrowError("webContents.print(): Invalid optional callback provided.");
  2625. return;
  2626. }
  2627. // Set optional silent printing.
  2628. bool silent = false;
  2629. options.Get("silent", &silent);
  2630. settings.Set("silent", silent);
  2631. bool print_background = false;
  2632. options.Get("printBackground", &print_background);
  2633. settings.Set(printing::kSettingShouldPrintBackgrounds, print_background);
  2634. // Set custom margin settings
  2635. auto margins = gin_helper::Dictionary::CreateEmpty(args->isolate());
  2636. if (options.Get("margins", &margins)) {
  2637. printing::mojom::MarginType margin_type =
  2638. printing::mojom::MarginType::kDefaultMargins;
  2639. margins.Get("marginType", &margin_type);
  2640. settings.Set(printing::kSettingMarginsType, static_cast<int>(margin_type));
  2641. if (margin_type == printing::mojom::MarginType::kCustomMargins) {
  2642. base::Value::Dict custom_margins;
  2643. int top = 0;
  2644. margins.Get("top", &top);
  2645. custom_margins.Set(printing::kSettingMarginTop, top);
  2646. int bottom = 0;
  2647. margins.Get("bottom", &bottom);
  2648. custom_margins.Set(printing::kSettingMarginBottom, bottom);
  2649. int left = 0;
  2650. margins.Get("left", &left);
  2651. custom_margins.Set(printing::kSettingMarginLeft, left);
  2652. int right = 0;
  2653. margins.Get("right", &right);
  2654. custom_margins.Set(printing::kSettingMarginRight, right);
  2655. settings.Set(printing::kSettingMarginsCustom, std::move(custom_margins));
  2656. }
  2657. } else {
  2658. settings.Set(
  2659. printing::kSettingMarginsType,
  2660. static_cast<int>(printing::mojom::MarginType::kDefaultMargins));
  2661. }
  2662. // Set whether to print color or greyscale
  2663. bool print_color = true;
  2664. options.Get("color", &print_color);
  2665. auto const color_model = print_color ? printing::mojom::ColorModel::kColor
  2666. : printing::mojom::ColorModel::kGray;
  2667. settings.Set(printing::kSettingColor, static_cast<int>(color_model));
  2668. // Is the orientation landscape or portrait.
  2669. bool landscape = false;
  2670. options.Get("landscape", &landscape);
  2671. settings.Set(printing::kSettingLandscape, landscape);
  2672. // We set the default to the system's default printer and only update
  2673. // if at the Chromium level if the user overrides.
  2674. // Printer device name as opened by the OS.
  2675. std::u16string device_name;
  2676. options.Get("deviceName", &device_name);
  2677. int scale_factor = 100;
  2678. options.Get("scaleFactor", &scale_factor);
  2679. settings.Set(printing::kSettingScaleFactor, scale_factor);
  2680. int pages_per_sheet = 1;
  2681. options.Get("pagesPerSheet", &pages_per_sheet);
  2682. settings.Set(printing::kSettingPagesPerSheet, pages_per_sheet);
  2683. // True if the user wants to print with collate.
  2684. bool collate = true;
  2685. options.Get("collate", &collate);
  2686. settings.Set(printing::kSettingCollate, collate);
  2687. // The number of individual copies to print
  2688. int copies = 1;
  2689. options.Get("copies", &copies);
  2690. settings.Set(printing::kSettingCopies, copies);
  2691. // Strings to be printed as headers and footers if requested by the user.
  2692. std::string header;
  2693. options.Get("header", &header);
  2694. std::string footer;
  2695. options.Get("footer", &footer);
  2696. if (!(header.empty() && footer.empty())) {
  2697. settings.Set(printing::kSettingHeaderFooterEnabled, true);
  2698. settings.Set(printing::kSettingHeaderFooterTitle, header);
  2699. settings.Set(printing::kSettingHeaderFooterURL, footer);
  2700. } else {
  2701. settings.Set(printing::kSettingHeaderFooterEnabled, false);
  2702. }
  2703. // We don't want to allow the user to enable these settings
  2704. // but we need to set them or a CHECK is hit.
  2705. settings.Set(printing::kSettingPrinterType,
  2706. static_cast<int>(printing::mojom::PrinterType::kLocal));
  2707. settings.Set(printing::kSettingShouldPrintSelectionOnly, false);
  2708. settings.Set(printing::kSettingRasterizePdf, false);
  2709. // Set custom page ranges to print
  2710. std::vector<gin_helper::Dictionary> page_ranges;
  2711. if (options.Get("pageRanges", &page_ranges)) {
  2712. base::Value::List page_range_list;
  2713. for (auto& range : page_ranges) {
  2714. int from, to;
  2715. if (range.Get("from", &from) && range.Get("to", &to)) {
  2716. base::Value::Dict range_dict;
  2717. // Chromium uses 1-based page ranges, so increment each by 1.
  2718. range_dict.Set(printing::kSettingPageRangeFrom, from + 1);
  2719. range_dict.Set(printing::kSettingPageRangeTo, to + 1);
  2720. page_range_list.Append(std::move(range_dict));
  2721. } else {
  2722. continue;
  2723. }
  2724. }
  2725. if (!page_range_list.empty())
  2726. settings.Set(printing::kSettingPageRange, std::move(page_range_list));
  2727. }
  2728. // Duplex type user wants to use.
  2729. printing::mojom::DuplexMode duplex_mode =
  2730. printing::mojom::DuplexMode::kSimplex;
  2731. options.Get("duplexMode", &duplex_mode);
  2732. settings.Set(printing::kSettingDuplexMode, static_cast<int>(duplex_mode));
  2733. // We've already done necessary parameter sanitization at the
  2734. // JS level, so we can simply pass this through.
  2735. base::Value media_size(base::Value::Type::DICT);
  2736. if (options.Get("mediaSize", &media_size))
  2737. settings.Set(printing::kSettingMediaSize, std::move(media_size));
  2738. // Set custom dots per inch (dpi)
  2739. gin_helper::Dictionary dpi_settings;
  2740. if (options.Get("dpi", &dpi_settings)) {
  2741. int horizontal = 72;
  2742. dpi_settings.Get("horizontal", &horizontal);
  2743. settings.Set(printing::kSettingDpiHorizontal, horizontal);
  2744. int vertical = 72;
  2745. dpi_settings.Get("vertical", &vertical);
  2746. settings.Set(printing::kSettingDpiVertical, vertical);
  2747. }
  2748. print_task_runner_->PostTaskAndReplyWithResult(
  2749. FROM_HERE, base::BindOnce(&GetDeviceNameToUse, device_name),
  2750. base::BindOnce(&OnGetDeviceNameToUse, web_contents()->GetWeakPtr(),
  2751. std::move(settings), std::move(callback)));
  2752. }
  2753. // Partially duplicated and modified from
  2754. // headless/lib/browser/protocol/page_handler.cc;l=41
  2755. v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) {
  2756. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  2757. gin_helper::Promise<v8::Local<v8::Value>> promise(isolate);
  2758. v8::Local<v8::Promise> handle = promise.GetHandle();
  2759. // This allows us to track headless printing calls.
  2760. auto unique_id = settings.GetDict().FindInt(printing::kPreviewRequestID);
  2761. auto landscape = settings.GetDict().FindBool("landscape");
  2762. auto display_header_footer =
  2763. settings.GetDict().FindBool("displayHeaderFooter");
  2764. auto print_background = settings.GetDict().FindBool("printBackground");
  2765. auto scale = settings.GetDict().FindDouble("scale");
  2766. auto paper_width = settings.GetDict().FindDouble("paperWidth");
  2767. auto paper_height = settings.GetDict().FindDouble("paperHeight");
  2768. auto margin_top = settings.GetDict().FindDouble("marginTop");
  2769. auto margin_bottom = settings.GetDict().FindDouble("marginBottom");
  2770. auto margin_left = settings.GetDict().FindDouble("marginLeft");
  2771. auto margin_right = settings.GetDict().FindDouble("marginRight");
  2772. auto page_ranges = *settings.GetDict().FindString("pageRanges");
  2773. auto header_template = *settings.GetDict().FindString("headerTemplate");
  2774. auto footer_template = *settings.GetDict().FindString("footerTemplate");
  2775. auto prefer_css_page_size = settings.GetDict().FindBool("preferCSSPageSize");
  2776. auto generate_tagged_pdf = settings.GetDict().FindBool("generateTaggedPDF");
  2777. auto generate_document_outline =
  2778. settings.GetDict().FindBool("generateDocumentOutline");
  2779. content::RenderFrameHost* rfh = GetRenderFrameHostToUse(web_contents());
  2780. absl::variant<printing::mojom::PrintPagesParamsPtr, std::string>
  2781. print_pages_params = print_to_pdf::GetPrintPagesParams(
  2782. rfh->GetLastCommittedURL(), landscape, display_header_footer,
  2783. print_background, scale, paper_width, paper_height, margin_top,
  2784. margin_bottom, margin_left, margin_right,
  2785. std::make_optional(header_template),
  2786. std::make_optional(footer_template), prefer_css_page_size,
  2787. generate_tagged_pdf, generate_document_outline);
  2788. if (absl::holds_alternative<std::string>(print_pages_params)) {
  2789. auto error = absl::get<std::string>(print_pages_params);
  2790. promise.RejectWithErrorMessage("Invalid print parameters: " + error);
  2791. return handle;
  2792. }
  2793. auto* manager = PrintViewManagerElectron::FromWebContents(web_contents());
  2794. if (!manager) {
  2795. promise.RejectWithErrorMessage("Failed to find print manager");
  2796. return handle;
  2797. }
  2798. auto params = std::move(
  2799. absl::get<printing::mojom::PrintPagesParamsPtr>(print_pages_params));
  2800. params->params->document_cookie = unique_id.value_or(0);
  2801. manager->PrintToPdf(rfh, page_ranges, std::move(params),
  2802. base::BindOnce(&OnPDFCreated, std::move(promise)));
  2803. return handle;
  2804. }
  2805. #endif
  2806. void WebContents::AddWorkSpace(gin::Arguments* args,
  2807. const base::FilePath& path) {
  2808. if (path.empty()) {
  2809. gin_helper::ErrorThrower(args->isolate())
  2810. .ThrowError("path cannot be empty");
  2811. return;
  2812. }
  2813. DevToolsAddFileSystem(std::string(), path);
  2814. }
  2815. void WebContents::RemoveWorkSpace(gin::Arguments* args,
  2816. const base::FilePath& path) {
  2817. if (path.empty()) {
  2818. gin_helper::ErrorThrower(args->isolate())
  2819. .ThrowError("path cannot be empty");
  2820. return;
  2821. }
  2822. DevToolsRemoveFileSystem(path);
  2823. }
  2824. void WebContents::Undo() {
  2825. web_contents()->Undo();
  2826. }
  2827. void WebContents::Redo() {
  2828. web_contents()->Redo();
  2829. }
  2830. void WebContents::Cut() {
  2831. web_contents()->Cut();
  2832. }
  2833. void WebContents::Copy() {
  2834. web_contents()->Copy();
  2835. }
  2836. void WebContents::CenterSelection() {
  2837. web_contents()->CenterSelection();
  2838. }
  2839. void WebContents::Paste() {
  2840. web_contents()->Paste();
  2841. }
  2842. void WebContents::PasteAndMatchStyle() {
  2843. web_contents()->PasteAndMatchStyle();
  2844. }
  2845. void WebContents::Delete() {
  2846. web_contents()->Delete();
  2847. }
  2848. void WebContents::SelectAll() {
  2849. web_contents()->SelectAll();
  2850. }
  2851. void WebContents::Unselect() {
  2852. web_contents()->CollapseSelection();
  2853. }
  2854. void WebContents::ScrollToTopOfDocument() {
  2855. web_contents()->ScrollToTopOfDocument();
  2856. }
  2857. void WebContents::ScrollToBottomOfDocument() {
  2858. web_contents()->ScrollToBottomOfDocument();
  2859. }
  2860. void WebContents::AdjustSelectionByCharacterOffset(gin::Arguments* args) {
  2861. int start_adjust = 0;
  2862. int end_adjust = 0;
  2863. gin_helper::Dictionary dict;
  2864. if (args->GetNext(&dict)) {
  2865. dict.Get("start", &start_adjust);
  2866. dict.Get("matchCase", &end_adjust);
  2867. }
  2868. // The selection menu is a Chrome-specific piece of UI.
  2869. // TODO(codebytere): maybe surface as an event in the future?
  2870. web_contents()->AdjustSelectionByCharacterOffset(
  2871. start_adjust, end_adjust, false /* show_selection_menu */);
  2872. }
  2873. void WebContents::Replace(const std::u16string& word) {
  2874. web_contents()->Replace(word);
  2875. }
  2876. void WebContents::ReplaceMisspelling(const std::u16string& word) {
  2877. web_contents()->ReplaceMisspelling(word);
  2878. }
  2879. uint32_t WebContents::FindInPage(gin::Arguments* args) {
  2880. std::u16string search_text;
  2881. if (!args->GetNext(&search_text) || search_text.empty()) {
  2882. gin_helper::ErrorThrower(args->isolate())
  2883. .ThrowError("Must provide a non-empty search content");
  2884. return 0;
  2885. }
  2886. uint32_t request_id = ++find_in_page_request_id_;
  2887. gin_helper::Dictionary dict;
  2888. auto options = blink::mojom::FindOptions::New();
  2889. if (args->GetNext(&dict)) {
  2890. dict.Get("forward", &options->forward);
  2891. dict.Get("matchCase", &options->match_case);
  2892. dict.Get("findNext", &options->new_session);
  2893. }
  2894. web_contents()->Find(request_id, search_text, std::move(options),
  2895. /*skip_delay=*/false);
  2896. return request_id;
  2897. }
  2898. void WebContents::StopFindInPage(content::StopFindAction action) {
  2899. web_contents()->StopFinding(action);
  2900. }
  2901. void WebContents::ShowDefinitionForSelection() {
  2902. #if BUILDFLAG(IS_MAC)
  2903. auto* const view = web_contents()->GetRenderWidgetHostView();
  2904. if (view)
  2905. view->ShowDefinitionForSelection();
  2906. #endif
  2907. }
  2908. void WebContents::CopyImageAt(int x, int y) {
  2909. auto* const host = web_contents()->GetPrimaryMainFrame();
  2910. if (host)
  2911. host->CopyImageAt(x, y);
  2912. }
  2913. void WebContents::Focus() {
  2914. // Focusing on WebContents does not automatically focus the window on macOS
  2915. // and Linux, do it manually to match the behavior on Windows.
  2916. #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
  2917. if (owner_window())
  2918. owner_window()->Focus(true);
  2919. #endif
  2920. // WebView uses WebContentsViewChildFrame, which doesn't have a Focus impl
  2921. // and triggers a fatal NOTREACHED.
  2922. if (is_guest())
  2923. return;
  2924. web_contents()->Focus();
  2925. }
  2926. #if !BUILDFLAG(IS_MAC)
  2927. bool WebContents::IsFocused() const {
  2928. auto* view = web_contents()->GetRenderWidgetHostView();
  2929. if (!view)
  2930. return false;
  2931. if (type() != Type::kBackgroundPage) {
  2932. auto* window = web_contents()->GetNativeView()->GetToplevelWindow();
  2933. if (window && !window->IsVisible())
  2934. return false;
  2935. }
  2936. return view->HasFocus();
  2937. }
  2938. #endif
  2939. void WebContents::SendInputEvent(v8::Isolate* isolate,
  2940. v8::Local<v8::Value> input_event) {
  2941. content::RenderWidgetHostView* view =
  2942. web_contents()->GetRenderWidgetHostView();
  2943. if (!view)
  2944. return;
  2945. content::RenderWidgetHost* rwh = view->GetRenderWidgetHost();
  2946. blink::WebInputEvent::Type type =
  2947. gin::GetWebInputEventType(isolate, input_event);
  2948. if (blink::WebInputEvent::IsMouseEventType(type)) {
  2949. blink::WebMouseEvent mouse_event;
  2950. if (gin::ConvertFromV8(isolate, input_event, &mouse_event)) {
  2951. if (IsOffScreen()) {
  2952. GetOffScreenRenderWidgetHostView()->SendMouseEvent(mouse_event);
  2953. } else {
  2954. rwh->ForwardMouseEvent(mouse_event);
  2955. }
  2956. return;
  2957. }
  2958. } else if (blink::WebInputEvent::IsKeyboardEventType(type)) {
  2959. input::NativeWebKeyboardEvent keyboard_event(
  2960. blink::WebKeyboardEvent::Type::kRawKeyDown,
  2961. blink::WebInputEvent::Modifiers::kNoModifiers, ui::EventTimeForNow());
  2962. if (gin::ConvertFromV8(isolate, input_event, &keyboard_event)) {
  2963. // For backwards compatibility, convert `kKeyDown` to `kRawKeyDown`.
  2964. if (keyboard_event.GetType() == blink::WebKeyboardEvent::Type::kKeyDown)
  2965. keyboard_event.SetType(blink::WebKeyboardEvent::Type::kRawKeyDown);
  2966. rwh->ForwardKeyboardEvent(keyboard_event);
  2967. return;
  2968. }
  2969. } else if (type == blink::WebInputEvent::Type::kMouseWheel) {
  2970. blink::WebMouseWheelEvent mouse_wheel_event;
  2971. if (gin::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
  2972. if (IsOffScreen()) {
  2973. GetOffScreenRenderWidgetHostView()->SendMouseWheelEvent(
  2974. mouse_wheel_event);
  2975. } else {
  2976. // Chromium expects phase info in wheel events (and applies a
  2977. // DCHECK to verify it). See: https://crbug.com/756524.
  2978. mouse_wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
  2979. mouse_wheel_event.dispatch_type =
  2980. blink::WebInputEvent::DispatchType::kBlocking;
  2981. rwh->ForwardWheelEvent(mouse_wheel_event);
  2982. // Send a synthetic wheel event with phaseEnded to finish scrolling.
  2983. mouse_wheel_event.has_synthetic_phase = true;
  2984. mouse_wheel_event.delta_x = 0;
  2985. mouse_wheel_event.delta_y = 0;
  2986. mouse_wheel_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
  2987. mouse_wheel_event.dispatch_type =
  2988. blink::WebInputEvent::DispatchType::kEventNonBlocking;
  2989. rwh->ForwardWheelEvent(mouse_wheel_event);
  2990. }
  2991. return;
  2992. }
  2993. }
  2994. isolate->ThrowException(
  2995. v8::Exception::Error(gin::StringToV8(isolate, "Invalid event object")));
  2996. }
  2997. void WebContents::BeginFrameSubscription(gin::Arguments* args) {
  2998. bool only_dirty = false;
  2999. FrameSubscriber::FrameCaptureCallback callback;
  3000. if (args->Length() > 1) {
  3001. if (!args->GetNext(&only_dirty)) {
  3002. args->ThrowError();
  3003. return;
  3004. }
  3005. }
  3006. if (!args->GetNext(&callback)) {
  3007. args->ThrowError();
  3008. return;
  3009. }
  3010. frame_subscriber_ =
  3011. std::make_unique<FrameSubscriber>(web_contents(), callback, only_dirty);
  3012. }
  3013. void WebContents::EndFrameSubscription() {
  3014. frame_subscriber_.reset();
  3015. }
  3016. void WebContents::StartDrag(const gin_helper::Dictionary& item,
  3017. gin::Arguments* args) {
  3018. base::FilePath file;
  3019. std::vector<base::FilePath> files;
  3020. if (!item.Get("files", &files) && item.Get("file", &file)) {
  3021. files.push_back(file);
  3022. }
  3023. v8::Local<v8::Value> icon_value;
  3024. if (!item.Get("icon", &icon_value)) {
  3025. gin_helper::ErrorThrower(args->isolate())
  3026. .ThrowError("'icon' parameter is required");
  3027. return;
  3028. }
  3029. NativeImage* icon = nullptr;
  3030. if (!NativeImage::TryConvertNativeImage(args->isolate(), icon_value, &icon) ||
  3031. icon->image().IsEmpty()) {
  3032. return;
  3033. }
  3034. // Start dragging.
  3035. if (!files.empty()) {
  3036. base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
  3037. DragFileItems(files, icon->image(), web_contents()->GetNativeView());
  3038. } else {
  3039. gin_helper::ErrorThrower(args->isolate())
  3040. .ThrowError("Must specify either 'file' or 'files' option");
  3041. }
  3042. }
  3043. v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
  3044. gin_helper::Promise<gfx::Image> promise(args->isolate());
  3045. v8::Local<v8::Promise> handle = promise.GetHandle();
  3046. gfx::Rect rect;
  3047. args->GetNext(&rect);
  3048. bool stay_hidden = false;
  3049. bool stay_awake = false;
  3050. if (args && args->Length() == 2) {
  3051. gin_helper::Dictionary options;
  3052. if (args->GetNext(&options)) {
  3053. options.Get("stayHidden", &stay_hidden);
  3054. options.Get("stayAwake", &stay_awake);
  3055. }
  3056. }
  3057. auto* const view = web_contents()->GetRenderWidgetHostView();
  3058. if (!view || view->GetViewBounds().size().IsEmpty()) {
  3059. promise.Resolve(gfx::Image());
  3060. return handle;
  3061. }
  3062. if (!view->IsSurfaceAvailableForCopy()) {
  3063. promise.RejectWithErrorMessage(
  3064. "Current display surface not available for capture");
  3065. return handle;
  3066. }
  3067. auto capture_handle = web_contents()->IncrementCapturerCount(
  3068. rect.size(), stay_hidden, stay_awake, /*is_activity=*/true);
  3069. // Capture full page if user doesn't specify a |rect|.
  3070. const gfx::Size view_size =
  3071. rect.IsEmpty() ? view->GetViewBounds().size() : rect.size();
  3072. // By default, the requested bitmap size is the view size in screen
  3073. // coordinates. However, if there's more pixel detail available on the
  3074. // current system, increase the requested bitmap size to capture it all.
  3075. gfx::Size bitmap_size = view_size;
  3076. const gfx::NativeView native_view = view->GetNativeView();
  3077. const float scale = display::Screen::GetScreen()
  3078. ->GetDisplayNearestView(native_view)
  3079. .device_scale_factor();
  3080. if (scale > 1.0f)
  3081. bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
  3082. view->CopyFromSurface(gfx::Rect(rect.origin(), view_size), bitmap_size,
  3083. base::BindOnce(&OnCapturePageDone, std::move(promise),
  3084. std::move(capture_handle)));
  3085. return handle;
  3086. }
  3087. bool WebContents::IsBeingCaptured() {
  3088. return web_contents()->IsBeingCaptured();
  3089. }
  3090. void WebContents::OnCursorChanged(const ui::Cursor& cursor) {
  3091. if (cursor.type() == ui::mojom::CursorType::kCustom) {
  3092. Emit("cursor-changed", CursorTypeToString(cursor.type()),
  3093. gfx::Image::CreateFrom1xBitmap(cursor.custom_bitmap()),
  3094. cursor.image_scale_factor(),
  3095. gfx::Size(cursor.custom_bitmap().width(),
  3096. cursor.custom_bitmap().height()),
  3097. cursor.custom_hotspot());
  3098. } else {
  3099. Emit("cursor-changed", CursorTypeToString(cursor.type()));
  3100. }
  3101. }
  3102. void WebContents::AttachToIframe(content::WebContents* embedder_web_contents,
  3103. int embedder_frame_id) {
  3104. attached_ = true;
  3105. if (guest_delegate_)
  3106. guest_delegate_->AttachToIframe(embedder_web_contents, embedder_frame_id);
  3107. }
  3108. bool WebContents::IsOffScreen() const {
  3109. return type_ == Type::kOffScreen;
  3110. }
  3111. void WebContents::OnPaint(const gfx::Rect& dirty_rect,
  3112. const SkBitmap& bitmap,
  3113. const OffscreenSharedTexture& tex) {
  3114. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  3115. v8::HandleScope handle_scope(isolate);
  3116. gin::Handle<gin_helper::internal::Event> event =
  3117. gin_helper::internal::Event::New(isolate);
  3118. v8::Local<v8::Object> event_object = event.ToV8().As<v8::Object>();
  3119. gin_helper::Dictionary dict(isolate, event_object);
  3120. if (offscreen_use_shared_texture_) {
  3121. dict.Set("texture", tex);
  3122. }
  3123. EmitWithoutEvent("paint", event, dirty_rect,
  3124. gfx::Image::CreateFrom1xBitmap(bitmap));
  3125. }
  3126. void WebContents::StartPainting() {
  3127. auto* osr_wcv = GetOffScreenWebContentsView();
  3128. if (osr_wcv)
  3129. osr_wcv->SetPainting(true);
  3130. }
  3131. void WebContents::StopPainting() {
  3132. auto* osr_wcv = GetOffScreenWebContentsView();
  3133. if (osr_wcv)
  3134. osr_wcv->SetPainting(false);
  3135. }
  3136. bool WebContents::IsPainting() const {
  3137. auto* osr_wcv = GetOffScreenWebContentsView();
  3138. return osr_wcv && osr_wcv->IsPainting();
  3139. }
  3140. void WebContents::SetFrameRate(int frame_rate) {
  3141. auto* osr_wcv = GetOffScreenWebContentsView();
  3142. if (osr_wcv)
  3143. osr_wcv->SetFrameRate(frame_rate);
  3144. }
  3145. int WebContents::GetFrameRate() const {
  3146. auto* osr_wcv = GetOffScreenWebContentsView();
  3147. return osr_wcv ? osr_wcv->GetFrameRate() : 0;
  3148. }
  3149. void WebContents::Invalidate() {
  3150. if (IsOffScreen()) {
  3151. auto* osr_rwhv = GetOffScreenRenderWidgetHostView();
  3152. if (osr_rwhv)
  3153. osr_rwhv->Invalidate();
  3154. } else {
  3155. auto* const window = owner_window();
  3156. if (window)
  3157. window->Invalidate();
  3158. }
  3159. }
  3160. gfx::Size WebContents::GetSizeForNewRenderView(content::WebContents* wc) {
  3161. if (IsOffScreen() && wc == web_contents()) {
  3162. auto* relay = NativeWindowRelay::FromWebContents(web_contents());
  3163. if (relay) {
  3164. auto* owner_window = relay->GetNativeWindow();
  3165. return owner_window ? owner_window->GetSize() : gfx::Size();
  3166. }
  3167. }
  3168. return {};
  3169. }
  3170. void WebContents::SetZoomLevel(double level) {
  3171. zoom_controller_->SetZoomLevel(level);
  3172. }
  3173. double WebContents::GetZoomLevel() const {
  3174. return zoom_controller_->GetZoomLevel();
  3175. }
  3176. void WebContents::SetZoomFactor(gin_helper::ErrorThrower thrower,
  3177. double factor) {
  3178. if (factor < std::numeric_limits<double>::epsilon()) {
  3179. thrower.ThrowError("'zoomFactor' must be a double greater than 0.0");
  3180. return;
  3181. }
  3182. auto level = blink::ZoomFactorToZoomLevel(factor);
  3183. SetZoomLevel(level);
  3184. }
  3185. double WebContents::GetZoomFactor() const {
  3186. auto level = GetZoomLevel();
  3187. return blink::ZoomLevelToZoomFactor(level);
  3188. }
  3189. void WebContents::SetTemporaryZoomLevel(double level) {
  3190. zoom_controller_->SetTemporaryZoomLevel(level);
  3191. }
  3192. std::optional<PreloadScript> WebContents::GetPreloadScript() const {
  3193. if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
  3194. if (auto preload = web_preferences->GetPreloadPath()) {
  3195. auto preload_script = PreloadScript{
  3196. "", PreloadScript::ScriptType::kWebFrame, preload.value()};
  3197. return preload_script;
  3198. }
  3199. }
  3200. return std::nullopt;
  3201. }
  3202. v8::Local<v8::Value> WebContents::GetLastWebPreferences(
  3203. v8::Isolate* isolate) const {
  3204. auto* web_preferences = WebContentsPreferences::From(web_contents());
  3205. if (!web_preferences)
  3206. return v8::Null(isolate);
  3207. return gin::ConvertToV8(isolate, *web_preferences->last_preference());
  3208. }
  3209. v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow(
  3210. v8::Isolate* isolate) const {
  3211. if (owner_window())
  3212. return BrowserWindow::From(isolate, owner_window());
  3213. else
  3214. return v8::Null(isolate);
  3215. }
  3216. v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
  3217. return v8::Local<v8::Value>::New(isolate, session_);
  3218. }
  3219. content::WebContents* WebContents::HostWebContents() const {
  3220. if (!embedder_)
  3221. return nullptr;
  3222. return embedder_->web_contents();
  3223. }
  3224. void WebContents::SetEmbedder(const WebContents* embedder) {
  3225. if (embedder) {
  3226. NativeWindow* owner_window = nullptr;
  3227. auto* relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
  3228. if (relay) {
  3229. owner_window = relay->GetNativeWindow();
  3230. }
  3231. if (owner_window)
  3232. SetOwnerWindow(owner_window);
  3233. content::RenderWidgetHostView* rwhv =
  3234. web_contents()->GetRenderWidgetHostView();
  3235. if (rwhv) {
  3236. rwhv->Hide();
  3237. rwhv->Show();
  3238. }
  3239. }
  3240. }
  3241. void WebContents::SetDevToolsWebContents(const WebContents* devtools) {
  3242. if (inspectable_web_contents_)
  3243. inspectable_web_contents_->SetDevToolsWebContents(devtools->web_contents());
  3244. }
  3245. v8::Local<v8::Value> WebContents::GetNativeView(v8::Isolate* isolate) const {
  3246. gfx::NativeView ptr = web_contents()->GetNativeView();
  3247. auto buffer = node::Buffer::Copy(isolate, reinterpret_cast<char*>(&ptr),
  3248. sizeof(gfx::NativeView));
  3249. if (buffer.IsEmpty())
  3250. return v8::Null(isolate);
  3251. else
  3252. return buffer.ToLocalChecked();
  3253. }
  3254. v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
  3255. if (devtools_web_contents_.IsEmpty())
  3256. return v8::Null(isolate);
  3257. else
  3258. return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
  3259. }
  3260. v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
  3261. if (debugger_.IsEmpty()) {
  3262. auto handle = electron::api::Debugger::Create(isolate, web_contents());
  3263. debugger_.Reset(isolate, handle.ToV8());
  3264. }
  3265. return v8::Local<v8::Value>::New(isolate, debugger_);
  3266. }
  3267. content::RenderFrameHost* WebContents::MainFrame() {
  3268. return web_contents()->GetPrimaryMainFrame();
  3269. }
  3270. content::RenderFrameHost* WebContents::Opener() {
  3271. return web_contents()->GetOpener();
  3272. }
  3273. void WebContents::NotifyUserActivation() {
  3274. content::RenderFrameHost* frame = web_contents()->GetPrimaryMainFrame();
  3275. if (frame)
  3276. frame->NotifyUserActivation(
  3277. blink::mojom::UserActivationNotificationType::kInteraction);
  3278. }
  3279. void WebContents::SetImageAnimationPolicy(const std::string& new_policy) {
  3280. auto* web_preferences = WebContentsPreferences::From(web_contents());
  3281. web_preferences->SetImageAnimationPolicy(new_policy);
  3282. web_contents()->OnWebPreferencesChanged();
  3283. }
  3284. void WebContents::SetBackgroundColor(std::optional<SkColor> maybe_color) {
  3285. SkColor color = maybe_color.value_or((is_guest() && guest_transparent_) ||
  3286. type_ == Type::kBrowserView
  3287. ? SK_ColorTRANSPARENT
  3288. : SK_ColorWHITE);
  3289. bool is_opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
  3290. web_contents()->SetPageBaseBackgroundColor(color);
  3291. content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
  3292. if (!rfh)
  3293. return;
  3294. content::RenderWidgetHostView* rwhv = rfh->GetView();
  3295. if (rwhv) {
  3296. // RenderWidgetHostView doesn't allow setting an alpha that's not 0 or
  3297. // 255.
  3298. rwhv->SetBackgroundColor(is_opaque ? color : SK_ColorTRANSPARENT);
  3299. static_cast<content::RenderWidgetHostViewBase*>(rwhv)
  3300. ->SetContentBackgroundColor(color);
  3301. }
  3302. }
  3303. void WebContents::PDFReadyToPrint() {
  3304. Emit("-pdf-ready-to-print");
  3305. }
  3306. void WebContents::OnInputEvent(const content::RenderWidgetHost& rfh,
  3307. const blink::WebInputEvent& event) {
  3308. Emit("input-event", event);
  3309. }
  3310. void WebContents::RunJavaScriptDialog(content::WebContents* web_contents,
  3311. content::RenderFrameHost* rfh,
  3312. content::JavaScriptDialogType dialog_type,
  3313. const std::u16string& message_text,
  3314. const std::u16string& default_prompt_text,
  3315. DialogClosedCallback callback,
  3316. bool* did_suppress_message) {
  3317. CHECK_EQ(web_contents, this->web_contents());
  3318. auto* isolate = JavascriptEnvironment::GetIsolate();
  3319. v8::HandleScope scope(isolate);
  3320. auto info = gin::DataObjectBuilder(isolate)
  3321. .Set("frame", rfh)
  3322. .Set("dialogType", dialog_type)
  3323. .Set("messageText", message_text)
  3324. .Set("defaultPromptText", default_prompt_text)
  3325. .Build();
  3326. EmitWithoutEvent("-run-dialog", info, std::move(callback));
  3327. }
  3328. void WebContents::RunBeforeUnloadDialog(content::WebContents* web_contents,
  3329. content::RenderFrameHost* rfh,
  3330. bool is_reload,
  3331. DialogClosedCallback callback) {
  3332. // TODO: asyncify?
  3333. bool default_prevented = Emit("will-prevent-unload");
  3334. std::move(callback).Run(default_prevented, std::u16string());
  3335. }
  3336. void WebContents::CancelDialogs(content::WebContents* web_contents,
  3337. bool reset_state) {
  3338. auto* isolate = JavascriptEnvironment::GetIsolate();
  3339. v8::HandleScope scope(isolate);
  3340. EmitWithoutEvent(
  3341. "-cancel-dialogs",
  3342. gin::DataObjectBuilder(isolate).Set("resetState", reset_state).Build());
  3343. }
  3344. v8::Local<v8::Promise> WebContents::GetProcessMemoryInfo(v8::Isolate* isolate) {
  3345. gin_helper::Promise<gin_helper::Dictionary> promise(isolate);
  3346. v8::Local<v8::Promise> handle = promise.GetHandle();
  3347. auto* frame_host = web_contents()->GetPrimaryMainFrame();
  3348. if (!frame_host) {
  3349. promise.RejectWithErrorMessage("Failed to create memory dump");
  3350. return handle;
  3351. }
  3352. auto pid = frame_host->GetProcess()->GetProcess().Pid();
  3353. v8::Global<v8::Context> context(isolate, isolate->GetCurrentContext());
  3354. memory_instrumentation::MemoryInstrumentation::GetInstance()
  3355. ->RequestGlobalDumpForPid(
  3356. pid, std::vector<std::string>(),
  3357. base::BindOnce(&ElectronBindings::DidReceiveMemoryDump,
  3358. std::move(context), std::move(promise), pid));
  3359. return handle;
  3360. }
  3361. v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
  3362. v8::Isolate* isolate,
  3363. const base::FilePath& file_path) {
  3364. gin_helper::Promise<void> promise(isolate);
  3365. v8::Local<v8::Promise> handle = promise.GetHandle();
  3366. ScopedAllowBlockingForElectron allow_blocking;
  3367. uint32_t flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
  3368. // The snapshot file is passed to an untrusted process.
  3369. flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
  3370. base::File file(file_path, flags);
  3371. if (!file.IsValid()) {
  3372. promise.RejectWithErrorMessage(
  3373. "Failed to take heap snapshot with invalid file path " +
  3374. #if BUILDFLAG(IS_WIN)
  3375. base::WideToUTF8(file_path.value()));
  3376. #else
  3377. file_path.value());
  3378. #endif
  3379. return handle;
  3380. }
  3381. auto* frame_host = web_contents()->GetPrimaryMainFrame();
  3382. if (!frame_host) {
  3383. promise.RejectWithErrorMessage(
  3384. "Failed to take heap snapshot with invalid webContents main frame");
  3385. return handle;
  3386. }
  3387. if (!frame_host->IsRenderFrameLive()) {
  3388. promise.RejectWithErrorMessage(
  3389. "Failed to take heap snapshot with nonexistent render frame");
  3390. return handle;
  3391. }
  3392. // This dance with `base::Owned` is to ensure that the interface stays alive
  3393. // until the callback is called. Otherwise it would be closed at the end of
  3394. // this function.
  3395. auto electron_renderer =
  3396. std::make_unique<mojo::Remote<mojom::ElectronRenderer>>();
  3397. frame_host->GetRemoteInterfaces()->GetInterface(
  3398. electron_renderer->BindNewPipeAndPassReceiver());
  3399. auto* raw_ptr = electron_renderer.get();
  3400. (*raw_ptr)->TakeHeapSnapshot(
  3401. mojo::WrapPlatformFile(base::ScopedPlatformFile(file.TakePlatformFile())),
  3402. base::BindOnce(
  3403. [](mojo::Remote<mojom::ElectronRenderer>* ep,
  3404. gin_helper::Promise<void> promise, bool success) {
  3405. if (success) {
  3406. promise.Resolve();
  3407. } else {
  3408. promise.RejectWithErrorMessage("Failed to take heap snapshot");
  3409. }
  3410. },
  3411. base::Owned(std::move(electron_renderer)), std::move(promise)));
  3412. return handle;
  3413. }
  3414. void WebContents::UpdatePreferredSize(content::WebContents* web_contents,
  3415. const gfx::Size& pref_size) {
  3416. Emit("preferred-size-changed", pref_size);
  3417. }
  3418. bool WebContents::CanOverscrollContent() {
  3419. return false;
  3420. }
  3421. std::unique_ptr<content::EyeDropper> WebContents::OpenEyeDropper(
  3422. content::RenderFrameHost* frame,
  3423. content::EyeDropperListener* listener) {
  3424. return ShowEyeDropper(frame, listener);
  3425. }
  3426. void WebContents::RunFileChooser(
  3427. content::RenderFrameHost* render_frame_host,
  3428. scoped_refptr<content::FileSelectListener> listener,
  3429. const blink::mojom::FileChooserParams& params) {
  3430. FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
  3431. params);
  3432. }
  3433. void WebContents::EnumerateDirectory(
  3434. content::WebContents* web_contents,
  3435. scoped_refptr<content::FileSelectListener> listener,
  3436. const base::FilePath& path) {
  3437. FileSelectHelper::EnumerateDirectory(web_contents, std::move(listener), path);
  3438. }
  3439. bool WebContents::IsFullscreenForTabOrPending(
  3440. const content::WebContents* source) {
  3441. if (!owner_window())
  3442. return is_html_fullscreen();
  3443. bool in_transition = owner_window()->fullscreen_transition_state() !=
  3444. NativeWindow::FullScreenTransitionState::kNone;
  3445. bool is_html_transition = owner_window()->fullscreen_transition_type() ==
  3446. NativeWindow::FullScreenTransitionType::kHTML;
  3447. return is_html_fullscreen() || (in_transition && is_html_transition);
  3448. }
  3449. content::FullscreenState WebContents::GetFullscreenState(
  3450. const content::WebContents* source) const {
  3451. // `const_cast` here because EAM does not have const getters
  3452. return const_cast<ExclusiveAccessManager*>(&exclusive_access_manager_)
  3453. ->fullscreen_controller()
  3454. ->GetFullscreenState(source);
  3455. }
  3456. bool WebContents::TakeFocus(content::WebContents* source, bool reverse) {
  3457. if (source && source->GetOutermostWebContents() == source) {
  3458. // If this is the outermost web contents and the user has tabbed or
  3459. // shift + tabbed through all the elements, reset the focus back to
  3460. // the first or last element so that it doesn't stay in the body.
  3461. source->FocusThroughTabTraversal(reverse);
  3462. return true;
  3463. }
  3464. return false;
  3465. }
  3466. content::PictureInPictureResult WebContents::EnterPictureInPicture(
  3467. content::WebContents* web_contents) {
  3468. return PictureInPictureWindowManager::GetInstance()
  3469. ->EnterVideoPictureInPicture(web_contents);
  3470. }
  3471. void WebContents::ExitPictureInPicture() {
  3472. PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture();
  3473. }
  3474. void WebContents::DevToolsSaveToFile(const std::string& url,
  3475. const std::string& content,
  3476. bool save_as,
  3477. bool is_base64) {
  3478. base::FilePath path;
  3479. auto it = saved_files_.find(url);
  3480. if (it != saved_files_.end() && !save_as) {
  3481. path = it->second;
  3482. } else {
  3483. file_dialog::DialogSettings settings;
  3484. settings.parent_window = owner_window();
  3485. settings.force_detached = offscreen_;
  3486. settings.title = url;
  3487. settings.default_path = base::FilePath::FromUTF8Unsafe(url);
  3488. if (!file_dialog::ShowSaveDialogSync(settings, &path)) {
  3489. inspectable_web_contents_->CallClientFunction(
  3490. "DevToolsAPI", "canceledSaveURL", base::Value(url));
  3491. return;
  3492. }
  3493. }
  3494. saved_files_[url] = path;
  3495. // Notify DevTools.
  3496. inspectable_web_contents_->CallClientFunction(
  3497. "DevToolsAPI", "savedURL", base::Value(url),
  3498. base::Value(path.AsUTF8Unsafe()));
  3499. file_task_runner_->PostTask(
  3500. FROM_HERE, base::BindOnce(&WriteToFile, path, content, is_base64));
  3501. }
  3502. void WebContents::DevToolsAppendToFile(const std::string& url,
  3503. const std::string& content) {
  3504. auto it = saved_files_.find(url);
  3505. if (it == saved_files_.end())
  3506. return;
  3507. // Notify DevTools.
  3508. inspectable_web_contents_->CallClientFunction("DevToolsAPI", "appendedToURL",
  3509. base::Value(url));
  3510. file_task_runner_->PostTask(
  3511. FROM_HERE, base::BindOnce(&AppendToFile, it->second, content));
  3512. }
  3513. void WebContents::DevToolsRequestFileSystems() {
  3514. auto file_system_paths = GetAddedFileSystemPaths(GetDevToolsWebContents());
  3515. if (file_system_paths.empty()) {
  3516. inspectable_web_contents_->CallClientFunction(
  3517. "DevToolsAPI", "fileSystemsLoaded", base::Value(base::Value::List()));
  3518. return;
  3519. }
  3520. std::vector<FileSystem> file_systems;
  3521. for (const auto& file_system_path : file_system_paths) {
  3522. base::FilePath path =
  3523. base::FilePath::FromUTF8Unsafe(file_system_path.first);
  3524. std::string file_system_id =
  3525. RegisterFileSystem(GetDevToolsWebContents(), path);
  3526. FileSystem file_system =
  3527. CreateFileSystemStruct(GetDevToolsWebContents(), file_system_id,
  3528. file_system_path.first, file_system_path.second);
  3529. file_systems.push_back(file_system);
  3530. }
  3531. base::Value::List file_system_value;
  3532. for (const auto& file_system : file_systems)
  3533. file_system_value.Append(CreateFileSystemValue(file_system));
  3534. inspectable_web_contents_->CallClientFunction(
  3535. "DevToolsAPI", "fileSystemsLoaded",
  3536. base::Value(std::move(file_system_value)));
  3537. }
  3538. void WebContents::DevToolsAddFileSystem(
  3539. const std::string& type,
  3540. const base::FilePath& file_system_path) {
  3541. base::FilePath path = file_system_path;
  3542. if (path.empty()) {
  3543. std::vector<base::FilePath> paths;
  3544. file_dialog::DialogSettings settings;
  3545. settings.parent_window = owner_window();
  3546. settings.force_detached = offscreen_;
  3547. settings.properties = file_dialog::OPEN_DIALOG_OPEN_DIRECTORY;
  3548. if (!file_dialog::ShowOpenDialogSync(settings, &paths))
  3549. return;
  3550. path = paths[0];
  3551. }
  3552. std::string file_system_id =
  3553. RegisterFileSystem(GetDevToolsWebContents(), path);
  3554. if (IsDevToolsFileSystemAdded(GetDevToolsWebContents(), path.AsUTF8Unsafe()))
  3555. return;
  3556. FileSystem file_system = CreateFileSystemStruct(
  3557. GetDevToolsWebContents(), file_system_id, path.AsUTF8Unsafe(), type);
  3558. base::Value::Dict file_system_value = CreateFileSystemValue(file_system);
  3559. auto* pref_service = GetPrefService(GetDevToolsWebContents());
  3560. ScopedDictPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
  3561. update->Set(path.AsUTF8Unsafe(), type);
  3562. std::string error = ""; // No error
  3563. inspectable_web_contents_->CallClientFunction(
  3564. "DevToolsAPI", "fileSystemAdded", base::Value(error),
  3565. base::Value(std::move(file_system_value)));
  3566. }
  3567. void WebContents::DevToolsRemoveFileSystem(
  3568. const base::FilePath& file_system_path) {
  3569. if (!inspectable_web_contents_)
  3570. return;
  3571. std::string path = file_system_path.AsUTF8Unsafe();
  3572. storage::IsolatedContext::GetInstance()->RevokeFileSystemByPath(
  3573. file_system_path);
  3574. auto* pref_service = GetPrefService(GetDevToolsWebContents());
  3575. ScopedDictPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
  3576. update->Remove(path);
  3577. inspectable_web_contents_->CallClientFunction(
  3578. "DevToolsAPI", "fileSystemRemoved", base::Value(path));
  3579. }
  3580. void WebContents::DevToolsIndexPath(
  3581. int request_id,
  3582. const std::string& file_system_path,
  3583. const std::string& excluded_folders_message) {
  3584. if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) {
  3585. OnDevToolsIndexingDone(request_id, file_system_path);
  3586. return;
  3587. }
  3588. if (devtools_indexing_jobs_.count(request_id) != 0)
  3589. return;
  3590. std::vector<std::string> excluded_folders;
  3591. std::optional<base::Value> parsed_excluded_folders =
  3592. base::JSONReader::Read(excluded_folders_message);
  3593. if (parsed_excluded_folders && parsed_excluded_folders->is_list()) {
  3594. for (const base::Value& folder_path : parsed_excluded_folders->GetList()) {
  3595. if (folder_path.is_string())
  3596. excluded_folders.push_back(folder_path.GetString());
  3597. }
  3598. }
  3599. devtools_indexing_jobs_[request_id] =
  3600. scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
  3601. devtools_file_system_indexer_->IndexPath(
  3602. file_system_path, excluded_folders,
  3603. base::BindRepeating(
  3604. &WebContents::OnDevToolsIndexingWorkCalculated,
  3605. weak_factory_.GetWeakPtr(), request_id, file_system_path),
  3606. base::BindRepeating(&WebContents::OnDevToolsIndexingWorked,
  3607. weak_factory_.GetWeakPtr(), request_id,
  3608. file_system_path),
  3609. base::BindRepeating(&WebContents::OnDevToolsIndexingDone,
  3610. weak_factory_.GetWeakPtr(), request_id,
  3611. file_system_path)));
  3612. }
  3613. void WebContents::DevToolsStopIndexing(int request_id) {
  3614. auto it = devtools_indexing_jobs_.find(request_id);
  3615. if (it == devtools_indexing_jobs_.end())
  3616. return;
  3617. it->second->Stop();
  3618. devtools_indexing_jobs_.erase(it);
  3619. }
  3620. void WebContents::DevToolsOpenInNewTab(const std::string& url) {
  3621. Emit("devtools-open-url", url);
  3622. }
  3623. void WebContents::DevToolsOpenSearchResultsInNewTab(const std::string& query) {
  3624. Emit("devtools-search-query", query);
  3625. }
  3626. void WebContents::DevToolsSearchInPath(int request_id,
  3627. const std::string& file_system_path,
  3628. const std::string& query) {
  3629. if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) {
  3630. OnDevToolsSearchCompleted(request_id, file_system_path,
  3631. std::vector<std::string>());
  3632. return;
  3633. }
  3634. devtools_file_system_indexer_->SearchInPath(
  3635. file_system_path, query,
  3636. base::BindRepeating(&WebContents::OnDevToolsSearchCompleted,
  3637. weak_factory_.GetWeakPtr(), request_id,
  3638. file_system_path));
  3639. }
  3640. void WebContents::DevToolsSetEyeDropperActive(bool active) {
  3641. auto* web_contents = GetWebContents();
  3642. if (!web_contents)
  3643. return;
  3644. if (active) {
  3645. eye_dropper_ = std::make_unique<DevToolsEyeDropper>(
  3646. web_contents, base::BindRepeating(&WebContents::ColorPickedInEyeDropper,
  3647. base::Unretained(this)));
  3648. } else {
  3649. eye_dropper_.reset();
  3650. }
  3651. }
  3652. void WebContents::ColorPickedInEyeDropper(int r, int g, int b, int a) {
  3653. base::Value::Dict color;
  3654. color.Set("r", r);
  3655. color.Set("g", g);
  3656. color.Set("b", b);
  3657. color.Set("a", a);
  3658. inspectable_web_contents_->CallClientFunction(
  3659. "DevToolsAPI", "eyeDropperPickedColor", base::Value(std::move(color)));
  3660. }
  3661. #if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC)
  3662. ui::ImageModel WebContents::GetDevToolsWindowIcon() {
  3663. return owner_window() ? owner_window()->GetWindowAppIcon() : ui::ImageModel{};
  3664. }
  3665. #endif
  3666. #if BUILDFLAG(IS_LINUX)
  3667. void WebContents::GetDevToolsWindowWMClass(std::string* name,
  3668. std::string* class_name) {
  3669. *class_name = Browser::Get()->GetName();
  3670. *name = base::ToLowerASCII(*class_name);
  3671. }
  3672. #endif
  3673. void WebContents::OnDevToolsIndexingWorkCalculated(
  3674. int request_id,
  3675. const std::string& file_system_path,
  3676. int total_work) {
  3677. inspectable_web_contents_->CallClientFunction(
  3678. "DevToolsAPI", "indexingTotalWorkCalculated", base::Value(request_id),
  3679. base::Value(file_system_path), base::Value(total_work));
  3680. }
  3681. void WebContents::OnDevToolsIndexingWorked(int request_id,
  3682. const std::string& file_system_path,
  3683. int worked) {
  3684. inspectable_web_contents_->CallClientFunction(
  3685. "DevToolsAPI", "indexingWorked", base::Value(request_id),
  3686. base::Value(file_system_path), base::Value(worked));
  3687. }
  3688. void WebContents::OnDevToolsIndexingDone(int request_id,
  3689. const std::string& file_system_path) {
  3690. devtools_indexing_jobs_.erase(request_id);
  3691. inspectable_web_contents_->CallClientFunction("DevToolsAPI", "indexingDone",
  3692. base::Value(request_id),
  3693. base::Value(file_system_path));
  3694. }
  3695. void WebContents::OnDevToolsSearchCompleted(
  3696. int request_id,
  3697. const std::string& file_system_path,
  3698. const std::vector<std::string>& file_paths) {
  3699. base::Value::List file_paths_value;
  3700. for (const auto& file_path : file_paths)
  3701. file_paths_value.Append(file_path);
  3702. inspectable_web_contents_->CallClientFunction(
  3703. "DevToolsAPI", "searchCompleted", base::Value(request_id),
  3704. base::Value(file_system_path), base::Value(std::move(file_paths_value)));
  3705. }
  3706. void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) {
  3707. // Window is already in fullscreen mode, save the state.
  3708. if (enter_fullscreen && owner_window()->IsFullscreen()) {
  3709. native_fullscreen_ = true;
  3710. UpdateHtmlApiFullscreen(true);
  3711. return;
  3712. }
  3713. // Exit html fullscreen state but not window's fullscreen mode.
  3714. if (!enter_fullscreen && native_fullscreen_) {
  3715. UpdateHtmlApiFullscreen(false);
  3716. return;
  3717. }
  3718. // Set fullscreen on window if allowed.
  3719. auto* web_preferences = WebContentsPreferences::From(GetWebContents());
  3720. bool html_fullscreenable =
  3721. web_preferences
  3722. ? !web_preferences->ShouldDisableHtmlFullscreenWindowResize()
  3723. : true;
  3724. if (html_fullscreenable)
  3725. owner_window_->SetFullScreen(enter_fullscreen);
  3726. UpdateHtmlApiFullscreen(enter_fullscreen);
  3727. native_fullscreen_ = false;
  3728. }
  3729. void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
  3730. if (fullscreen == is_html_fullscreen())
  3731. return;
  3732. html_fullscreen_ = fullscreen;
  3733. // Notify renderer of the html fullscreen change.
  3734. web_contents()
  3735. ->GetRenderViewHost()
  3736. ->GetWidget()
  3737. ->SynchronizeVisualProperties();
  3738. // The embedder WebContents is separated from the frame tree of webview, so
  3739. // we must manually sync their fullscreen states.
  3740. if (embedder_)
  3741. embedder_->SetHtmlApiFullscreen(fullscreen);
  3742. if (fullscreen) {
  3743. Emit("enter-html-full-screen");
  3744. owner_window_->NotifyWindowEnterHtmlFullScreen();
  3745. } else {
  3746. Emit("leave-html-full-screen");
  3747. owner_window_->NotifyWindowLeaveHtmlFullScreen();
  3748. }
  3749. // Make sure all child webviews quit html fullscreen.
  3750. if (!fullscreen && !is_guest()) {
  3751. auto* manager = WebViewManager::GetWebViewManager(web_contents());
  3752. manager->ForEachGuest(web_contents(), [&](content::WebContents* guest) {
  3753. WebContents* api_web_contents = WebContents::From(guest);
  3754. api_web_contents->SetHtmlApiFullscreen(false);
  3755. return false;
  3756. });
  3757. }
  3758. }
  3759. // static
  3760. void WebContents::FillObjectTemplate(v8::Isolate* isolate,
  3761. v8::Local<v8::ObjectTemplate> templ) {
  3762. gin::InvokerOptions options;
  3763. options.holder_is_first_argument = true;
  3764. options.holder_type = GetClassName();
  3765. templ->Set(
  3766. gin::StringToSymbol(isolate, "isDestroyed"),
  3767. gin::CreateFunctionTemplate(
  3768. isolate, base::BindRepeating(&gin_helper::Destroyable::IsDestroyed),
  3769. options));
  3770. // We use gin_helper::ObjectTemplateBuilder instead of
  3771. // gin::ObjectTemplateBuilder here to handle the fact that WebContents is
  3772. // destroyable.
  3773. gin_helper::ObjectTemplateBuilder(isolate, templ)
  3774. .SetMethod("destroy", &WebContents::Destroy)
  3775. .SetMethod("close", &WebContents::Close)
  3776. .SetMethod("getBackgroundThrottling",
  3777. &WebContents::GetBackgroundThrottling)
  3778. .SetMethod("setBackgroundThrottling",
  3779. &WebContents::SetBackgroundThrottling)
  3780. .SetMethod("getProcessId", &WebContents::GetProcessID)
  3781. .SetMethod("getOSProcessId", &WebContents::GetOSProcessID)
  3782. .SetMethod("equal", &WebContents::Equal)
  3783. .SetMethod("_loadURL", &WebContents::LoadURL)
  3784. .SetMethod("reload", &WebContents::Reload)
  3785. .SetMethod("reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
  3786. .SetMethod("downloadURL", &WebContents::DownloadURL)
  3787. .SetMethod("getURL", &WebContents::GetURL)
  3788. .SetMethod("getTitle", &WebContents::GetTitle)
  3789. .SetMethod("isLoading", &WebContents::IsLoading)
  3790. .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame)
  3791. .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
  3792. .SetMethod("stop", &WebContents::Stop)
  3793. .SetMethod("_canGoBack", &WebContents::CanGoBack)
  3794. .SetMethod("_goBack", &WebContents::GoBack)
  3795. .SetMethod("_canGoForward", &WebContents::CanGoForward)
  3796. .SetMethod("_goForward", &WebContents::GoForward)
  3797. .SetMethod("_canGoToOffset", &WebContents::CanGoToOffset)
  3798. .SetMethod("_goToOffset", &WebContents::GoToOffset)
  3799. .SetMethod("canGoToIndex", &WebContents::CanGoToIndex)
  3800. .SetMethod("_goToIndex", &WebContents::GoToIndex)
  3801. .SetMethod("_getActiveIndex", &WebContents::GetActiveIndex)
  3802. .SetMethod("_getNavigationEntryAtIndex",
  3803. &WebContents::GetNavigationEntryAtIndex)
  3804. .SetMethod("_historyLength", &WebContents::GetHistoryLength)
  3805. .SetMethod("_removeNavigationEntryAtIndex",
  3806. &WebContents::RemoveNavigationEntryAtIndex)
  3807. .SetMethod("_getHistory", &WebContents::GetHistory)
  3808. .SetMethod("_clearHistory", &WebContents::ClearHistory)
  3809. .SetMethod("_restoreHistory", &WebContents::RestoreHistory)
  3810. .SetMethod("isCrashed", &WebContents::IsCrashed)
  3811. .SetMethod("forcefullyCrashRenderer",
  3812. &WebContents::ForcefullyCrashRenderer)
  3813. .SetMethod("setUserAgent", &WebContents::SetUserAgent)
  3814. .SetMethod("getUserAgent", &WebContents::GetUserAgent)
  3815. .SetMethod("savePage", &WebContents::SavePage)
  3816. .SetMethod("openDevTools", &WebContents::OpenDevTools)
  3817. .SetMethod("closeDevTools", &WebContents::CloseDevTools)
  3818. .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
  3819. .SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused)
  3820. .SetMethod("getDevToolsTitle", &WebContents::GetDevToolsTitle)
  3821. .SetMethod("setDevToolsTitle", &WebContents::SetDevToolsTitle)
  3822. .SetMethod("enableDeviceEmulation", &WebContents::EnableDeviceEmulation)
  3823. .SetMethod("disableDeviceEmulation", &WebContents::DisableDeviceEmulation)
  3824. .SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
  3825. .SetMethod("inspectElement", &WebContents::InspectElement)
  3826. .SetMethod("setIgnoreMenuShortcuts", &WebContents::SetIgnoreMenuShortcuts)
  3827. .SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
  3828. .SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
  3829. .SetMethod("isCurrentlyAudible", &WebContents::IsCurrentlyAudible)
  3830. .SetMethod("undo", &WebContents::Undo)
  3831. .SetMethod("redo", &WebContents::Redo)
  3832. .SetMethod("cut", &WebContents::Cut)
  3833. .SetMethod("copy", &WebContents::Copy)
  3834. .SetMethod("centerSelection", &WebContents::CenterSelection)
  3835. .SetMethod("paste", &WebContents::Paste)
  3836. .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
  3837. .SetMethod("delete", &WebContents::Delete)
  3838. .SetMethod("selectAll", &WebContents::SelectAll)
  3839. .SetMethod("unselect", &WebContents::Unselect)
  3840. .SetMethod("scrollToTop", &WebContents::ScrollToTopOfDocument)
  3841. .SetMethod("scrollToBottom", &WebContents::ScrollToBottomOfDocument)
  3842. .SetMethod("adjustSelection",
  3843. &WebContents::AdjustSelectionByCharacterOffset)
  3844. .SetMethod("replace", &WebContents::Replace)
  3845. .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
  3846. .SetMethod("findInPage", &WebContents::FindInPage)
  3847. .SetMethod("stopFindInPage", &WebContents::StopFindInPage)
  3848. .SetMethod("focus", &WebContents::Focus)
  3849. .SetMethod("isFocused", &WebContents::IsFocused)
  3850. .SetMethod("sendInputEvent", &WebContents::SendInputEvent)
  3851. .SetMethod("beginFrameSubscription", &WebContents::BeginFrameSubscription)
  3852. .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
  3853. .SetMethod("startDrag", &WebContents::StartDrag)
  3854. .SetMethod("attachToIframe", &WebContents::AttachToIframe)
  3855. .SetMethod("detachFromOuterFrame", &WebContents::DetachFromOuterFrame)
  3856. .SetMethod("isOffscreen", &WebContents::IsOffScreen)
  3857. .SetMethod("startPainting", &WebContents::StartPainting)
  3858. .SetMethod("stopPainting", &WebContents::StopPainting)
  3859. .SetMethod("isPainting", &WebContents::IsPainting)
  3860. .SetMethod("setFrameRate", &WebContents::SetFrameRate)
  3861. .SetMethod("getFrameRate", &WebContents::GetFrameRate)
  3862. .SetMethod("invalidate", &WebContents::Invalidate)
  3863. .SetMethod("setZoomLevel", &WebContents::SetZoomLevel)
  3864. .SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
  3865. .SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
  3866. .SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
  3867. .SetMethod("getType", &WebContents::type)
  3868. .SetMethod("_getPreloadScript", &WebContents::GetPreloadScript)
  3869. .SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
  3870. .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
  3871. .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
  3872. .SetMethod("inspectSharedWorker", &WebContents::InspectSharedWorker)
  3873. .SetMethod("inspectSharedWorkerById",
  3874. &WebContents::InspectSharedWorkerById)
  3875. .SetMethod("getAllSharedWorkers", &WebContents::GetAllSharedWorkers)
  3876. #if BUILDFLAG(ENABLE_PRINTING)
  3877. .SetMethod("_print", &WebContents::Print)
  3878. .SetMethod("_printToPDF", &WebContents::PrintToPDF)
  3879. #endif
  3880. .SetMethod("_setNextChildWebPreferences",
  3881. &WebContents::SetNextChildWebPreferences)
  3882. .SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
  3883. .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
  3884. .SetMethod("showDefinitionForSelection",
  3885. &WebContents::ShowDefinitionForSelection)
  3886. .SetMethod("copyImageAt", &WebContents::CopyImageAt)
  3887. .SetMethod("capturePage", &WebContents::CapturePage)
  3888. .SetMethod("setEmbedder", &WebContents::SetEmbedder)
  3889. .SetMethod("setDevToolsWebContents", &WebContents::SetDevToolsWebContents)
  3890. .SetMethod("getNativeView", &WebContents::GetNativeView)
  3891. .SetMethod("isBeingCaptured", &WebContents::IsBeingCaptured)
  3892. .SetMethod("setWebRTCIPHandlingPolicy",
  3893. &WebContents::SetWebRTCIPHandlingPolicy)
  3894. .SetMethod("setWebRTCUDPPortRange", &WebContents::SetWebRTCUDPPortRange)
  3895. .SetMethod("getMediaSourceId", &WebContents::GetMediaSourceID)
  3896. .SetMethod("getWebRTCIPHandlingPolicy",
  3897. &WebContents::GetWebRTCIPHandlingPolicy)
  3898. .SetMethod("getWebRTCUDPPortRange", &WebContents::GetWebRTCUDPPortRange)
  3899. .SetMethod("takeHeapSnapshot", &WebContents::TakeHeapSnapshot)
  3900. .SetMethod("setImageAnimationPolicy",
  3901. &WebContents::SetImageAnimationPolicy)
  3902. .SetMethod("_getProcessMemoryInfo", &WebContents::GetProcessMemoryInfo)
  3903. .SetProperty("id", &WebContents::ID)
  3904. .SetProperty("session", &WebContents::Session)
  3905. .SetProperty("hostWebContents", &WebContents::HostWebContents)
  3906. .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
  3907. .SetProperty("debugger", &WebContents::Debugger)
  3908. .SetProperty("mainFrame", &WebContents::MainFrame)
  3909. .SetProperty("opener", &WebContents::Opener)
  3910. .SetMethod("_setOwnerWindow", &WebContents::SetOwnerBaseWindow)
  3911. .Build();
  3912. }
  3913. const char* WebContents::GetTypeName() {
  3914. return GetClassName();
  3915. }
  3916. void WebContents::WillBeDestroyed() {
  3917. ClearWeak();
  3918. }
  3919. ElectronBrowserContext* WebContents::GetBrowserContext() const {
  3920. return static_cast<ElectronBrowserContext*>(
  3921. web_contents()->GetBrowserContext());
  3922. }
  3923. // static
  3924. gin::Handle<WebContents> WebContents::New(
  3925. v8::Isolate* isolate,
  3926. const gin_helper::Dictionary& options) {
  3927. gin::Handle<WebContents> handle =
  3928. gin::CreateHandle(isolate, new WebContents(isolate, options));
  3929. v8::TryCatch try_catch(isolate);
  3930. gin_helper::CallMethod(isolate, handle.get(), "_init");
  3931. if (try_catch.HasCaught()) {
  3932. node::errors::TriggerUncaughtException(isolate, try_catch);
  3933. }
  3934. return handle;
  3935. }
  3936. // static
  3937. gin::Handle<WebContents> WebContents::CreateAndTake(
  3938. v8::Isolate* isolate,
  3939. std::unique_ptr<content::WebContents> web_contents,
  3940. Type type) {
  3941. gin::Handle<WebContents> handle = gin::CreateHandle(
  3942. isolate, new WebContents(isolate, std::move(web_contents), type));
  3943. v8::TryCatch try_catch(isolate);
  3944. gin_helper::CallMethod(isolate, handle.get(), "_init");
  3945. if (try_catch.HasCaught()) {
  3946. node::errors::TriggerUncaughtException(isolate, try_catch);
  3947. }
  3948. return handle;
  3949. }
  3950. // static
  3951. WebContents* WebContents::From(content::WebContents* web_contents) {
  3952. if (!web_contents)
  3953. return nullptr;
  3954. auto* data = static_cast<UserDataLink*>(
  3955. web_contents->GetUserData(kElectronApiWebContentsKey));
  3956. return data ? data->web_contents.get() : nullptr;
  3957. }
  3958. // static
  3959. gin::Handle<WebContents> WebContents::FromOrCreate(
  3960. v8::Isolate* isolate,
  3961. content::WebContents* web_contents) {
  3962. WebContents* api_web_contents = From(web_contents);
  3963. if (!api_web_contents) {
  3964. api_web_contents = new WebContents(isolate, web_contents);
  3965. v8::TryCatch try_catch(isolate);
  3966. gin_helper::CallMethod(isolate, api_web_contents, "_init");
  3967. if (try_catch.HasCaught()) {
  3968. node::errors::TriggerUncaughtException(isolate, try_catch);
  3969. }
  3970. }
  3971. return gin::CreateHandle(isolate, api_web_contents);
  3972. }
  3973. // static
  3974. gin::Handle<WebContents> WebContents::CreateFromWebPreferences(
  3975. v8::Isolate* isolate,
  3976. const gin_helper::Dictionary& web_preferences) {
  3977. // Check if webPreferences has |webContents| option.
  3978. gin::Handle<WebContents> web_contents;
  3979. if (web_preferences.GetHidden("webContents", &web_contents) &&
  3980. !web_contents.IsEmpty()) {
  3981. // Set webPreferences from options if using an existing webContents.
  3982. // These preferences will be used when the webContent launches new
  3983. // render processes.
  3984. auto* existing_preferences =
  3985. WebContentsPreferences::From(web_contents->web_contents());
  3986. gin_helper::Dictionary web_preferences_dict;
  3987. if (gin::ConvertFromV8(isolate, web_preferences.GetHandle(),
  3988. &web_preferences_dict)) {
  3989. existing_preferences->SetFromDictionary(web_preferences_dict);
  3990. web_contents->SetBackgroundColor(
  3991. existing_preferences->GetBackgroundColor());
  3992. }
  3993. } else {
  3994. // Create one if not.
  3995. web_contents = WebContents::New(isolate, web_preferences);
  3996. }
  3997. return web_contents;
  3998. }
  3999. // static
  4000. WebContents* WebContents::FromID(int32_t id) {
  4001. return GetAllWebContents().Lookup(id);
  4002. }
  4003. // static
  4004. std::list<WebContents*> WebContents::GetWebContentsList() {
  4005. std::list<WebContents*> list;
  4006. for (auto iter = base::IDMap<WebContents*>::iterator(&GetAllWebContents());
  4007. !iter.IsAtEnd(); iter.Advance()) {
  4008. list.push_back(iter.GetCurrentValue());
  4009. }
  4010. return list;
  4011. }
  4012. // static
  4013. void WebContents::SetDisableDraggableRegions(bool disable) {
  4014. g_disable_draggable_regions = disable;
  4015. }
  4016. // static
  4017. gin::WrapperInfo WebContents::kWrapperInfo = {gin::kEmbedderNativeGin};
  4018. } // namespace electron::api
  4019. namespace {
  4020. using electron::api::GetAllWebContents;
  4021. using electron::api::WebContents;
  4022. using electron::api::WebFrameMain;
  4023. gin::Handle<WebContents> WebContentsFromID(v8::Isolate* isolate, int32_t id) {
  4024. WebContents* contents = WebContents::FromID(id);
  4025. return contents ? gin::CreateHandle(isolate, contents)
  4026. : gin::Handle<WebContents>();
  4027. }
  4028. gin::Handle<WebContents> WebContentsFromFrame(v8::Isolate* isolate,
  4029. WebFrameMain* web_frame) {
  4030. content::RenderFrameHost* rfh = web_frame->render_frame_host();
  4031. content::WebContents* source = content::WebContents::FromRenderFrameHost(rfh);
  4032. WebContents* contents = WebContents::From(source);
  4033. return contents ? gin::CreateHandle(isolate, contents)
  4034. : gin::Handle<WebContents>();
  4035. }
  4036. gin::Handle<WebContents> WebContentsFromDevToolsTargetID(
  4037. v8::Isolate* isolate,
  4038. std::string target_id) {
  4039. auto agent_host = content::DevToolsAgentHost::GetForId(target_id);
  4040. WebContents* contents =
  4041. agent_host ? WebContents::From(agent_host->GetWebContents()) : nullptr;
  4042. return contents ? gin::CreateHandle(isolate, contents)
  4043. : gin::Handle<WebContents>();
  4044. }
  4045. std::vector<gin::Handle<WebContents>> GetAllWebContentsAsV8(
  4046. v8::Isolate* isolate) {
  4047. std::vector<gin::Handle<WebContents>> list;
  4048. for (auto iter = base::IDMap<WebContents*>::iterator(&GetAllWebContents());
  4049. !iter.IsAtEnd(); iter.Advance()) {
  4050. list.push_back(gin::CreateHandle(isolate, iter.GetCurrentValue()));
  4051. }
  4052. return list;
  4053. }
  4054. void Initialize(v8::Local<v8::Object> exports,
  4055. v8::Local<v8::Value> unused,
  4056. v8::Local<v8::Context> context,
  4057. void* priv) {
  4058. v8::Isolate* isolate = context->GetIsolate();
  4059. gin_helper::Dictionary dict(isolate, exports);
  4060. dict.Set("WebContents", WebContents::GetConstructor(context));
  4061. dict.SetMethod("fromId", &WebContentsFromID);
  4062. dict.SetMethod("fromFrame", &WebContentsFromFrame);
  4063. dict.SetMethod("fromDevToolsTargetId", &WebContentsFromDevToolsTargetID);
  4064. dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
  4065. }
  4066. } // namespace
  4067. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_web_contents, Initialize)