CEFWebInterfaceBrowserWindow.cpp 82 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951
  1. // Engine/Source/Runtime/WebBrowser/Private/CEF/CEFWebBrowserWindow.cpp
  2. #include "CEF/CEFWebInterfaceBrowserWindow.h"
  3. #include "IWebInterfaceBrowserDialog.h"
  4. #include "UObject/Stack.h"
  5. #include "Framework/Application/SlateApplication.h"
  6. #include "Textures/SlateUpdatableTexture.h"
  7. #include "HAL/PlatformApplicationMisc.h"
  8. #include "Misc/CommandLine.h"
  9. #include "Misc/ConfigCacheIni.h"
  10. #include "WebInterfaceBrowserLog.h"
  11. #if WITH_CEF3
  12. #include "CEFInterfaceBrowserPopupFeatures.h"
  13. #include "CEFWebInterfaceBrowserDialog.h"
  14. #include "CEFInterfaceBrowserClosureTask.h"
  15. #include "CEFInterfaceJSScripting.h"
  16. #include "CEFInterfaceImeHandler.h"
  17. #include "CEFWebInterfaceBrowserWindowRHIHelper.h"
  18. #include "CEF3Utils.h"
  19. #include "Async/Async.h"
  20. #if PLATFORM_MAC
  21. // Needed for character code definitions
  22. #include <Carbon/Carbon.h>
  23. #include <AppKit/NSEvent.h>
  24. #endif
  25. #if PLATFORM_WINDOWS
  26. #include "Windows/WindowsCursor.h"
  27. typedef FWindowsCursor FPlatformCursor;
  28. #elif PLATFORM_MAC
  29. #include "Mac/MacCursor.h"
  30. #include "Mac/CocoaThread.h"
  31. #include "Mac/MacApplication.h"
  32. #include "Mac/MacCursor.h"
  33. typedef FMacCursor FPlatformCursor;
  34. #else
  35. #endif
  36. #if PLATFORM_LINUX
  37. // From ui/events/keycodes/keyboard_codes_posix.h.
  38. enum KeyboardCode {
  39. VKEY_BACK = 0x08,
  40. VKEY_TAB = 0x09,
  41. VKEY_BACKTAB = 0x0A,
  42. VKEY_CLEAR = 0x0C,
  43. VKEY_RETURN = 0x0D,
  44. VKEY_SHIFT = 0x10,
  45. VKEY_CONTROL = 0x11,
  46. VKEY_MENU = 0x12,
  47. VKEY_PAUSE = 0x13,
  48. VKEY_CAPITAL = 0x14,
  49. VKEY_KANA = 0x15,
  50. VKEY_HANGUL = 0x15,
  51. VKEY_JUNJA = 0x17,
  52. VKEY_FINAL = 0x18,
  53. VKEY_HANJA = 0x19,
  54. VKEY_KANJI = 0x19,
  55. VKEY_ESCAPE = 0x1B,
  56. VKEY_CONVERT = 0x1C,
  57. VKEY_NONCONVERT = 0x1D,
  58. VKEY_ACCEPT = 0x1E,
  59. VKEY_MODECHANGE = 0x1F,
  60. VKEY_SPACE = 0x20,
  61. VKEY_PRIOR = 0x21,
  62. VKEY_NEXT = 0x22,
  63. VKEY_END = 0x23,
  64. VKEY_HOME = 0x24,
  65. VKEY_LEFT = 0x25,
  66. VKEY_UP = 0x26,
  67. VKEY_RIGHT = 0x27,
  68. VKEY_DOWN = 0x28,
  69. VKEY_SELECT = 0x29,
  70. VKEY_PRINT = 0x2A,
  71. VKEY_EXECUTE = 0x2B,
  72. VKEY_SNAPSHOT = 0x2C,
  73. VKEY_INSERT = 0x2D,
  74. VKEY_DELETE = 0x2E,
  75. VKEY_HELP = 0x2F,
  76. VKEY_0 = 0x30,
  77. VKEY_1 = 0x31,
  78. VKEY_2 = 0x32,
  79. VKEY_3 = 0x33,
  80. VKEY_4 = 0x34,
  81. VKEY_5 = 0x35,
  82. VKEY_6 = 0x36,
  83. VKEY_7 = 0x37,
  84. VKEY_8 = 0x38,
  85. VKEY_9 = 0x39,
  86. VKEY_A = 0x41,
  87. VKEY_B = 0x42,
  88. VKEY_C = 0x43,
  89. VKEY_D = 0x44,
  90. VKEY_E = 0x45,
  91. VKEY_F = 0x46,
  92. VKEY_G = 0x47,
  93. VKEY_H = 0x48,
  94. VKEY_I = 0x49,
  95. VKEY_J = 0x4A,
  96. VKEY_K = 0x4B,
  97. VKEY_L = 0x4C,
  98. VKEY_M = 0x4D,
  99. VKEY_N = 0x4E,
  100. VKEY_O = 0x4F,
  101. VKEY_P = 0x50,
  102. VKEY_Q = 0x51,
  103. VKEY_R = 0x52,
  104. VKEY_S = 0x53,
  105. VKEY_T = 0x54,
  106. VKEY_U = 0x55,
  107. VKEY_V = 0x56,
  108. VKEY_W = 0x57,
  109. VKEY_X = 0x58,
  110. VKEY_Y = 0x59,
  111. VKEY_Z = 0x5A,
  112. VKEY_LWIN = 0x5B,
  113. VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
  114. VKEY_RWIN = 0x5C,
  115. VKEY_APPS = 0x5D,
  116. VKEY_SLEEP = 0x5F,
  117. VKEY_NUMPAD0 = 0x60,
  118. VKEY_NUMPAD1 = 0x61,
  119. VKEY_NUMPAD2 = 0x62,
  120. VKEY_NUMPAD3 = 0x63,
  121. VKEY_NUMPAD4 = 0x64,
  122. VKEY_NUMPAD5 = 0x65,
  123. VKEY_NUMPAD6 = 0x66,
  124. VKEY_NUMPAD7 = 0x67,
  125. VKEY_NUMPAD8 = 0x68,
  126. VKEY_NUMPAD9 = 0x69,
  127. VKEY_MULTIPLY = 0x6A,
  128. VKEY_ADD = 0x6B,
  129. VKEY_SEPARATOR = 0x6C,
  130. VKEY_SUBTRACT = 0x6D,
  131. VKEY_DECIMAL = 0x6E,
  132. VKEY_DIVIDE = 0x6F,
  133. VKEY_F1 = 0x70,
  134. VKEY_F2 = 0x71,
  135. VKEY_F3 = 0x72,
  136. VKEY_F4 = 0x73,
  137. VKEY_F5 = 0x74,
  138. VKEY_F6 = 0x75,
  139. VKEY_F7 = 0x76,
  140. VKEY_F8 = 0x77,
  141. VKEY_F9 = 0x78,
  142. VKEY_F10 = 0x79,
  143. VKEY_F11 = 0x7A,
  144. VKEY_F12 = 0x7B,
  145. VKEY_F13 = 0x7C,
  146. VKEY_F14 = 0x7D,
  147. VKEY_F15 = 0x7E,
  148. VKEY_F16 = 0x7F,
  149. VKEY_F17 = 0x80,
  150. VKEY_F18 = 0x81,
  151. VKEY_F19 = 0x82,
  152. VKEY_F20 = 0x83,
  153. VKEY_F21 = 0x84,
  154. VKEY_F22 = 0x85,
  155. VKEY_F23 = 0x86,
  156. VKEY_F24 = 0x87,
  157. VKEY_NUMLOCK = 0x90,
  158. VKEY_SCROLL = 0x91,
  159. VKEY_LSHIFT = 0xA0,
  160. VKEY_RSHIFT = 0xA1,
  161. VKEY_LCONTROL = 0xA2,
  162. VKEY_RCONTROL = 0xA3,
  163. VKEY_LMENU = 0xA4,
  164. VKEY_RMENU = 0xA5,
  165. VKEY_BROWSER_BACK = 0xA6,
  166. VKEY_BROWSER_FORWARD = 0xA7,
  167. VKEY_BROWSER_REFRESH = 0xA8,
  168. VKEY_BROWSER_STOP = 0xA9,
  169. VKEY_BROWSER_SEARCH = 0xAA,
  170. VKEY_BROWSER_FAVORITES = 0xAB,
  171. VKEY_BROWSER_HOME = 0xAC,
  172. VKEY_VOLUME_MUTE = 0xAD,
  173. VKEY_VOLUME_DOWN = 0xAE,
  174. VKEY_VOLUME_UP = 0xAF,
  175. VKEY_MEDIA_NEXT_TRACK = 0xB0,
  176. VKEY_MEDIA_PREV_TRACK = 0xB1,
  177. VKEY_MEDIA_STOP = 0xB2,
  178. VKEY_MEDIA_PLAY_PAUSE = 0xB3,
  179. VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
  180. VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
  181. VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
  182. VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
  183. VKEY_OEM_1 = 0xBA,
  184. VKEY_OEM_PLUS = 0xBB,
  185. VKEY_OEM_COMMA = 0xBC,
  186. VKEY_OEM_MINUS = 0xBD,
  187. VKEY_OEM_PERIOD = 0xBE,
  188. VKEY_OEM_2 = 0xBF,
  189. VKEY_OEM_3 = 0xC0,
  190. VKEY_OEM_4 = 0xDB,
  191. VKEY_OEM_5 = 0xDC,
  192. VKEY_OEM_6 = 0xDD,
  193. VKEY_OEM_7 = 0xDE,
  194. VKEY_OEM_8 = 0xDF,
  195. VKEY_OEM_102 = 0xE2,
  196. VKEY_OEM_103 = 0xE3, // GTV KEYCODE_MEDIA_REWIND
  197. VKEY_OEM_104 = 0xE4, // GTV KEYCODE_MEDIA_FAST_FORWARD
  198. VKEY_PROCESSKEY = 0xE5,
  199. VKEY_PACKET = 0xE7,
  200. VKEY_DBE_SBCSCHAR = 0xF3,
  201. VKEY_DBE_DBCSCHAR = 0xF4,
  202. VKEY_ATTN = 0xF6,
  203. VKEY_CRSEL = 0xF7,
  204. VKEY_EXSEL = 0xF8,
  205. VKEY_EREOF = 0xF9,
  206. VKEY_PLAY = 0xFA,
  207. VKEY_ZOOM = 0xFB,
  208. VKEY_NONAME = 0xFC,
  209. VKEY_PA1 = 0xFD,
  210. VKEY_OEM_CLEAR = 0xFE,
  211. VKEY_UNKNOWN = 0,
  212. // POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
  213. // and 0xE8 are unassigned.
  214. VKEY_WLAN = 0x97,
  215. VKEY_POWER = 0x98,
  216. VKEY_BRIGHTNESS_DOWN = 0xD8,
  217. VKEY_BRIGHTNESS_UP = 0xD9,
  218. VKEY_KBD_BRIGHTNESS_DOWN = 0xDA,
  219. VKEY_KBD_BRIGHTNESS_UP = 0xE8,
  220. // Windows does not have a specific key code for AltGr. We use the unused 0xE1
  221. // (VK_OEM_AX) code to represent AltGr, matching the behaviour of Firefox on
  222. // Linux.
  223. VKEY_ALTGR = 0xE1,
  224. // Windows does not have a specific key code for Compose. We use the unused
  225. // 0xE6 (VK_ICO_CLEAR) code to represent Compose.
  226. VKEY_COMPOSE = 0xE6,
  227. };
  228. #endif
  229. #if PLATFORM_MAC
  230. // enable buffered video so we don't DoS the OpenGL API with texture uploads causing a downstream crash on macOS
  231. #define USE_BUFFERED_VIDEO 1
  232. #else
  233. #define USE_BUFFERED_VIDEO 0
  234. #endif
  235. namespace {
  236. // Private helper class to post a callback to GetSource.
  237. class FWebInterfaceBrowserClosureVisitor
  238. : public CefStringVisitor
  239. {
  240. public:
  241. FWebInterfaceBrowserClosureVisitor(TFunction<void (const FString&)> InClosure)
  242. : Closure(InClosure)
  243. { }
  244. virtual void Visit(const CefString& String) override
  245. {
  246. Closure(FString(WCHAR_TO_TCHAR(String.ToWString().c_str())));
  247. }
  248. private:
  249. TFunction<void (const FString&)> Closure;
  250. IMPLEMENT_REFCOUNTING(FWebInterfaceBrowserClosureVisitor);
  251. };
  252. }
  253. // Private helper class to smooth out video buffering, using a ringbuffer
  254. // (cef sometimes submits multiple frames per engine frame)
  255. class FBrowserBufferedVideo
  256. {
  257. public:
  258. FBrowserBufferedVideo(uint32 NumFrames)
  259. : FrameWriteIndex(0)
  260. , FrameReadIndex(0)
  261. , FrameCountThisEngineTick(0)
  262. , FrameCount(0)
  263. , FrameNumberOfLastRender(-1)
  264. {
  265. Frames.SetNum(NumFrames);
  266. }
  267. ~FBrowserBufferedVideo()
  268. {
  269. }
  270. /**
  271. * Submits a frame to the video buffer
  272. * @return true if this is the first frame submitted this engine tick, or false otherwise
  273. */
  274. bool SubmitFrame(
  275. int32 InWidth,
  276. int32 InHeight,
  277. const void* Buffer,
  278. FIntRect Dirty)
  279. {
  280. check(IsInGameThread());
  281. check(Buffer != nullptr);
  282. const uint32 NumBytesPerPixel = 4;
  283. FFrame& Frame = Frames[FrameWriteIndex];
  284. // If the write buffer catches up to the read buffer, we need to release the read buffer and increment its index
  285. if (FrameWriteIndex == FrameReadIndex && FrameCount > 0)
  286. {
  287. Frame.ReleaseTextureData();
  288. FrameReadIndex = (FrameReadIndex + 1) % Frames.Num();
  289. }
  290. check(Frame.SlateTextureData == nullptr);
  291. Frame.SlateTextureData = new FSlateTextureData((uint8*)Buffer, InWidth, InHeight, NumBytesPerPixel);
  292. FrameWriteIndex = (FrameWriteIndex + 1) % Frames.Num();
  293. FrameCount = FMath::Min(Frames.Num(), FrameCount + 1);
  294. FrameCountThisEngineTick++;
  295. return FrameCountThisEngineTick == 1;
  296. }
  297. /**
  298. * Called once per frame to get the next frame's texturedata
  299. * @return The texture data. Can be nullptr if no frame is available
  300. */
  301. FSlateTextureData* GetNextFrameTextureData()
  302. {
  303. // Grab the next available frame if available. Ensure we don't grab more than one frame per engine tick
  304. check(IsInGameThread());
  305. FSlateTextureData* SlateTextureData = nullptr;
  306. if ( FrameCount > 0 )
  307. {
  308. // Grab the first frame we haven't submitted yet
  309. FFrame& Frame = Frames[FrameReadIndex];
  310. SlateTextureData = Frame.SlateTextureData;
  311. // Set this to NULL because the renderthread is taking ownership
  312. Frame.SlateTextureData = nullptr;
  313. FrameReadIndex = (FrameReadIndex + 1) % Frames.Num();
  314. FrameCount--;
  315. }
  316. FrameCountThisEngineTick = 0;
  317. return SlateTextureData;
  318. }
  319. private:
  320. struct FFrame
  321. {
  322. FFrame()
  323. : SlateTextureData(nullptr)
  324. {}
  325. ~FFrame()
  326. {
  327. ReleaseTextureData();
  328. }
  329. void ReleaseTextureData()
  330. {
  331. if (SlateTextureData)
  332. {
  333. delete SlateTextureData;
  334. }
  335. SlateTextureData = nullptr;
  336. }
  337. FSlateTextureData* SlateTextureData;
  338. };
  339. TArray<FFrame> Frames;
  340. // Read/write position in the ringbuffer
  341. int32 FrameWriteIndex;
  342. int32 FrameReadIndex;
  343. int32 FrameCountThisEngineTick;
  344. int32 FrameCount;
  345. int32 FrameNumberOfLastRender;
  346. };
  347. FCEFWebInterfaceBrowserWindow::FCEFWebInterfaceBrowserWindow(CefRefPtr<CefBrowser> InBrowser, CefRefPtr<FCEFInterfaceBrowserHandler> InHandler, FString InUrl, TOptional<FString> InContentsToLoad, bool bInShowErrorMessage, bool bInThumbMouseButtonNavigation, bool bInUseTransparency, bool bInUseNativeCursors, bool bInJSBindingToLoweringEnabled, bool bInUsingAcceleratedPaint)
  348. : DocumentState(EWebInterfaceBrowserDocumentState::NoDocument)
  349. , InternalCefBrowser(InBrowser)
  350. , WebBrowserHandler(InHandler)
  351. , CurrentUrl(InUrl)
  352. , ViewportSize(FIntPoint::ZeroValue)
  353. , ViewportDPIScaleFactor(1.0f)
  354. , bIsClosing(false)
  355. , bIsInitialized(false)
  356. , ContentsToLoad(InContentsToLoad)
  357. , bShowErrorMessage(bInShowErrorMessage)
  358. , bThumbMouseButtonNavigation(bInThumbMouseButtonNavigation)
  359. , bUseTransparency(bInUseTransparency)
  360. , bUsingAcceleratedPaint(bInUsingAcceleratedPaint)
  361. , bUseNativeCursors(bInUseNativeCursors)
  362. , Cursor(EMouseCursor::Default)
  363. , bIsDisabled(false)
  364. , bIsHidden(false)
  365. , bTickedLastFrame(true)
  366. , bNeedsResize(false)
  367. , bDraggingWindow(false)
  368. , PreviousKeyDownEvent()
  369. , PreviousKeyUpEvent()
  370. , PreviousCharacterEvent()
  371. , bIgnoreKeyDownEvent(false)
  372. , bIgnoreKeyUpEvent(false)
  373. , bIgnoreCharacterEvent(false)
  374. , bMainHasFocus(false)
  375. , bPopupHasFocus(false)
  376. , bSupportsMouseWheel(true)
  377. , bRecoverFromRenderProcessCrash(false)
  378. , ErrorCode(0)
  379. , bDeferNavigations(false)
  380. #if PLATFORM_MAC
  381. , LastPaintedSharedHandle(nullptr)
  382. #endif
  383. , Scripting(new FCEFInterfaceJSScripting(InBrowser, bInJSBindingToLoweringEnabled))
  384. #if !PLATFORM_LINUX
  385. , Ime(new FCEFInterfaceImeHandler(InBrowser))
  386. #endif
  387. , RHIRenderHelper(nullptr)
  388. #if PLATFORM_WINDOWS || PLATFORM_MAC
  389. , bInDirectHwndMode(false)
  390. #endif
  391. {
  392. check(InBrowser.get() != nullptr);
  393. check(!bUsingAcceleratedPaint || CanSupportAcceleratedPaint()); // make sure if accelerated paint is selected we can support it
  394. UpdatableTextures[0] = nullptr;
  395. UpdatableTextures[1] = nullptr;
  396. if (!CreateInitialTextures())
  397. {
  398. ReleaseTextures();
  399. }
  400. #if PLATFORM_WINDOWS || PLATFORM_MAC
  401. if (InternalCefBrowser->GetHost()->GetWindowHandle() != nullptr)
  402. {
  403. bInDirectHwndMode = true;
  404. }
  405. #endif
  406. #if USE_BUFFERED_VIDEO
  407. BufferedVideo = TUniquePtr<FBrowserBufferedVideo>(new FBrowserBufferedVideo(4));
  408. #endif
  409. }
  410. void FCEFWebInterfaceBrowserWindow::ReleaseTextures()
  411. {
  412. for (int I = 0; I < 2; ++I)
  413. {
  414. if (UpdatableTextures[I] != nullptr)
  415. {
  416. FSlateUpdatableTexture* TextureToRelease = UpdatableTextures[I];
  417. AsyncTask(ENamedThreads::GameThread, [TextureToRelease]()
  418. {
  419. if (FSlateApplication::IsInitialized())
  420. {
  421. if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
  422. {
  423. Renderer->ReleaseUpdatableTexture(TextureToRelease);
  424. }
  425. }
  426. });
  427. UpdatableTextures[I] = nullptr;
  428. }
  429. }
  430. }
  431. bool FCEFWebInterfaceBrowserWindow::CreateInitialTextures()
  432. {
  433. if (FSlateApplication::IsInitialized())
  434. {
  435. if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
  436. {
  437. if (Renderer->HasLostDevice())
  438. {
  439. return false;
  440. }
  441. if (bUsingAcceleratedPaint)
  442. {
  443. if (FCEFWebInterfaceBrowserWindowRHIHelper::BUseRHIRenderer() && RHIRenderHelper == nullptr)
  444. {
  445. RHIRenderHelper = new FCEFWebInterfaceBrowserWindowRHIHelper;
  446. }
  447. // the accelerated paint path attaches to the texture at render time as we don't know its details until then
  448. UpdatableTextures[0] = nullptr;
  449. UpdatableTextures[1] = nullptr;
  450. return true;
  451. }
  452. // Create a transparent dummy texture for our buffers which will prevent slate from applying an
  453. // undesirable quad if it happens to ask for this buffer before we get a chance to paint to it.
  454. TArray<uint8> RawData;
  455. RawData.AddZeroed(4);
  456. UpdatableTextures[0] = Renderer->CreateUpdatableTexture(1, 1);
  457. if (Renderer->HasLostDevice())
  458. {
  459. return false;
  460. }
  461. UpdatableTextures[0]->UpdateTextureThreadSafeRaw(1, 1, RawData.GetData());
  462. if (Renderer->HasLostDevice())
  463. {
  464. return false;
  465. }
  466. UpdatableTextures[1] = Renderer->CreateUpdatableTexture(1, 1);
  467. if (Renderer->HasLostDevice())
  468. {
  469. return false;
  470. }
  471. UpdatableTextures[1]->UpdateTextureThreadSafeRaw(1, 1, RawData.GetData());
  472. if (Renderer->HasLostDevice())
  473. {
  474. return false;
  475. }
  476. return true;
  477. }
  478. }
  479. return false;
  480. }
  481. FCEFWebInterfaceBrowserWindow::~FCEFWebInterfaceBrowserWindow()
  482. {
  483. WebBrowserHandler->OnCreateWindow().Unbind();
  484. WebBrowserHandler->OnBeforePopup().Unbind();
  485. WebBrowserHandler->OnBeforeResourceLoad().Unbind();
  486. WebBrowserHandler->OnResourceLoadComplete().Unbind();
  487. WebBrowserHandler->OnConsoleMessage().Unbind();
  488. if (IsValid())
  489. {
  490. UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Closing browser during destruction, this may cause a later crash."), *CurrentUrl);
  491. CloseBrowser(true, false);
  492. }
  493. ReleaseTextures();
  494. BufferedVideo.Reset();
  495. if (RHIRenderHelper != nullptr)
  496. {
  497. delete RHIRenderHelper;
  498. }
  499. UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Deleting browser for Url=%s."), *CurrentUrl);
  500. }
  501. void FCEFWebInterfaceBrowserWindow::LoadURL(FString NewURL)
  502. {
  503. RequestNavigationInternal(NewURL, FString());
  504. }
  505. void FCEFWebInterfaceBrowserWindow::LoadString(FString Contents, FString DummyURL)
  506. {
  507. RequestNavigationInternal(DummyURL, Contents);
  508. }
  509. TSharedRef<SViewport> FCEFWebInterfaceBrowserWindow::CreateWidget()
  510. {
  511. TSharedRef<SViewport> BrowserWidgetRef =
  512. SNew(SViewport)
  513. .EnableGammaCorrection(false)
  514. .EnableBlending(bUseTransparency)
  515. .IgnoreTextureAlpha(!bUseTransparency)
  516. .RenderTransform(this, &FCEFWebInterfaceBrowserWindow::GetWebBrowserRenderTransform);
  517. #if !PLATFORM_LINUX
  518. Ime->CacheBrowserSlateInfo(BrowserWidgetRef);
  519. #endif
  520. return BrowserWidgetRef;
  521. }
  522. TOptional<FSlateRenderTransform> FCEFWebInterfaceBrowserWindow::GetWebBrowserRenderTransform() const
  523. {
  524. TOptional<FSlateRenderTransform> LocalRenderTransform = FSlateRenderTransform();
  525. if (bUsingAcceleratedPaint)
  526. {
  527. if (RHIRenderHelper != nullptr)
  528. {
  529. LocalRenderTransform = RHIRenderHelper->GetWebBrowserRenderTransform();
  530. }
  531. else
  532. {
  533. LocalRenderTransform = FSlateRenderTransform(Concatenate(FScale2D(1, -1), FVector2D(0, ViewportSize.Y)));
  534. }
  535. }
  536. return LocalRenderTransform;
  537. }
  538. bool FCEFWebInterfaceBrowserWindow::BlockInputInDirectHwndMode() const
  539. {
  540. #if PLATFORM_WINDOWS
  541. return bInDirectHwndMode;
  542. #elif PLATFORM_MAC
  543. return bInDirectHwndMode;
  544. #endif
  545. return false;
  546. }
  547. void FCEFWebInterfaceBrowserWindow::SetViewportSize(FIntPoint WindowSize, FIntPoint WindowPos)
  548. {
  549. // SetViewportSize is called from the browser viewport tick method, which means that since we are receiving ticks, we can mark the browser as visible.
  550. if (! bIsDisabled)
  551. {
  552. SetIsHidden(false);
  553. }
  554. bTickedLastFrame=true;
  555. float WindowDPIScaleFactor = 1.0f;
  556. if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
  557. {
  558. WindowDPIScaleFactor = ParentWindowPtr->GetNativeWindow()->GetDPIScaleFactor();
  559. }
  560. ViewportPos = WindowPos;
  561. // Ignore sizes that can't be seen as it forces CEF to re-render whole image
  562. if ((WindowSize.X > 0 && WindowSize.Y > 0 && ViewportSize != WindowSize) || WindowDPIScaleFactor != ViewportDPIScaleFactor)
  563. {
  564. bool bFirstSize = ViewportSize == FIntPoint::ZeroValue;
  565. ViewportSize = WindowSize;
  566. ViewportDPIScaleFactor = WindowDPIScaleFactor;
  567. if (IsValid())
  568. {
  569. #if PLATFORM_WINDOWS
  570. HWND NativeHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
  571. if (NativeHandle)
  572. {
  573. HWND Parent = ::GetParent(NativeHandle);
  574. // Position is in screen coordinates, so we'll need to get the parent window location first.
  575. RECT ParentRect = { 0, 0, 0, 0 };
  576. if (Parent)
  577. {
  578. ::GetWindowRect(Parent, &ParentRect);
  579. }
  580. FIntPoint WindowSizeScaled = (FVector2D(WindowSize) * WindowDPIScaleFactor).IntPoint();
  581. ::SetWindowPos(NativeHandle, 0, WindowPos.X - ParentRect.left, WindowPos.Y - ParentRect.top, WindowSizeScaled.X, WindowSizeScaled.Y, 0);
  582. }
  583. #elif PLATFORM_MAC
  584. CefWindowHandle NativeWindowHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
  585. if (NativeWindowHandle)
  586. {
  587. NSView* browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
  588. if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
  589. {
  590. NSWindow* parentWindow = (NSWindow*)ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle();
  591. const FVector2D CocoaPosition = FMacApplication::ConvertSlatePositionToCocoa(WindowPos.X, WindowPos.Y);
  592. NSRect parentFrame = [parentWindow frame];
  593. NSRect Rect = NSMakeRect(CocoaPosition.X - parentFrame.origin.x, (CocoaPosition.Y - parentFrame.origin.y) - WindowSize.Y, FMath::Max(WindowSize.X, 1), FMath::Max(WindowSize.Y, 1));
  594. Rect = [parentWindow frameRectForContentRect : Rect];
  595. [browserView setFrame : Rect] ;
  596. }
  597. }
  598. #endif
  599. if (bFirstSize)
  600. {
  601. InternalCefBrowser->GetHost()->WasResized();
  602. }
  603. else
  604. {
  605. bNeedsResize = true;
  606. }
  607. }
  608. }
  609. }
  610. FSlateShaderResource* FCEFWebInterfaceBrowserWindow::GetTexture(bool bIsPopup)
  611. {
  612. if (UpdatableTextures[bIsPopup?1:0] != nullptr)
  613. {
  614. return UpdatableTextures[bIsPopup?1:0]->GetSlateResource();
  615. }
  616. return nullptr;
  617. }
  618. bool FCEFWebInterfaceBrowserWindow::IsValid() const
  619. {
  620. return InternalCefBrowser.get() != nullptr;
  621. }
  622. bool FCEFWebInterfaceBrowserWindow::IsInitialized() const
  623. {
  624. return bIsInitialized;
  625. }
  626. bool FCEFWebInterfaceBrowserWindow::IsClosing() const
  627. {
  628. return bIsClosing;
  629. }
  630. EWebInterfaceBrowserDocumentState FCEFWebInterfaceBrowserWindow::GetDocumentLoadingState() const
  631. {
  632. return DocumentState;
  633. }
  634. FString FCEFWebInterfaceBrowserWindow::GetTitle() const
  635. {
  636. return Title;
  637. }
  638. FString FCEFWebInterfaceBrowserWindow::GetUrl() const
  639. {
  640. if (InternalCefBrowser != nullptr)
  641. {
  642. CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
  643. if (MainFrame != nullptr)
  644. {
  645. return CurrentUrl;
  646. }
  647. }
  648. return FString();
  649. }
  650. void FCEFWebInterfaceBrowserWindow::GetSource(TFunction<void (const FString&)> Callback) const
  651. {
  652. if (IsValid())
  653. {
  654. InternalCefBrowser->GetMainFrame()->GetSource(new FWebInterfaceBrowserClosureVisitor(Callback));
  655. }
  656. else
  657. {
  658. Callback(FString());
  659. }
  660. }
  661. void FCEFWebInterfaceBrowserWindow::PopulateCefKeyEvent(const FKeyEvent& InKeyEvent, CefKeyEvent& OutKeyEvent)
  662. {
  663. #if PLATFORM_MAC
  664. OutKeyEvent.native_key_code = InKeyEvent.GetKeyCode();
  665. FKey Key = InKeyEvent.GetKey();
  666. if (Key == EKeys::BackSpace)
  667. {
  668. OutKeyEvent.unmodified_character = kBackspaceCharCode;
  669. }
  670. else if (Key == EKeys::Tab)
  671. {
  672. OutKeyEvent.unmodified_character = kTabCharCode;
  673. }
  674. else if (Key == EKeys::Enter)
  675. {
  676. OutKeyEvent.unmodified_character = kReturnCharCode;
  677. }
  678. else if (Key == EKeys::Pause)
  679. {
  680. OutKeyEvent.unmodified_character = NSPauseFunctionKey;
  681. }
  682. else if (Key == EKeys::Escape)
  683. {
  684. OutKeyEvent.unmodified_character = kEscapeCharCode;
  685. }
  686. else if (Key == EKeys::PageUp)
  687. {
  688. OutKeyEvent.unmodified_character = NSPageUpFunctionKey;
  689. }
  690. else if (Key == EKeys::PageDown)
  691. {
  692. OutKeyEvent.unmodified_character = NSPageDownFunctionKey;
  693. }
  694. else if (Key == EKeys::End)
  695. {
  696. OutKeyEvent.unmodified_character = NSEndFunctionKey;
  697. }
  698. else if (Key == EKeys::Home)
  699. {
  700. OutKeyEvent.unmodified_character = NSHomeFunctionKey;
  701. }
  702. else if (Key == EKeys::Left)
  703. {
  704. OutKeyEvent.unmodified_character = NSLeftArrowFunctionKey;
  705. }
  706. else if (Key == EKeys::Up)
  707. {
  708. OutKeyEvent.unmodified_character = NSUpArrowFunctionKey;
  709. }
  710. else if (Key == EKeys::Right)
  711. {
  712. OutKeyEvent.unmodified_character = NSRightArrowFunctionKey;
  713. }
  714. else if (Key == EKeys::Down)
  715. {
  716. OutKeyEvent.unmodified_character = NSDownArrowFunctionKey;
  717. }
  718. else if (Key == EKeys::Insert)
  719. {
  720. OutKeyEvent.unmodified_character = NSInsertFunctionKey;
  721. }
  722. else if (Key == EKeys::Delete)
  723. {
  724. OutKeyEvent.unmodified_character = kDeleteCharCode;
  725. }
  726. else if (Key == EKeys::F1)
  727. {
  728. OutKeyEvent.unmodified_character = NSF1FunctionKey;
  729. }
  730. else if (Key == EKeys::F2)
  731. {
  732. OutKeyEvent.unmodified_character = NSF2FunctionKey;
  733. }
  734. else if (Key == EKeys::F3)
  735. {
  736. OutKeyEvent.unmodified_character = NSF3FunctionKey;
  737. }
  738. else if (Key == EKeys::F4)
  739. {
  740. OutKeyEvent.unmodified_character = NSF4FunctionKey;
  741. }
  742. else if (Key == EKeys::F5)
  743. {
  744. OutKeyEvent.unmodified_character = NSF5FunctionKey;
  745. }
  746. else if (Key == EKeys::F6)
  747. {
  748. OutKeyEvent.unmodified_character = NSF6FunctionKey;
  749. }
  750. else if (Key == EKeys::F7)
  751. {
  752. OutKeyEvent.unmodified_character = NSF7FunctionKey;
  753. }
  754. else if (Key == EKeys::F8)
  755. {
  756. OutKeyEvent.unmodified_character = NSF8FunctionKey;
  757. }
  758. else if (Key == EKeys::F9)
  759. {
  760. OutKeyEvent.unmodified_character = NSF9FunctionKey;
  761. }
  762. else if (Key == EKeys::F10)
  763. {
  764. OutKeyEvent.unmodified_character = NSF10FunctionKey;
  765. }
  766. else if (Key == EKeys::F11)
  767. {
  768. OutKeyEvent.unmodified_character = NSF11FunctionKey;
  769. }
  770. else if (Key == EKeys::F12)
  771. {
  772. OutKeyEvent.unmodified_character = NSF12FunctionKey;
  773. }
  774. else if (Key == EKeys::CapsLock)
  775. {
  776. OutKeyEvent.unmodified_character = 0;
  777. OutKeyEvent.native_key_code = kVK_CapsLock;
  778. }
  779. else if (Key.IsModifierKey())
  780. {
  781. // Setting both unmodified_character and character to 0 tells CEF that it needs to generate a NSFlagsChanged event instead of NSKeyDown/Up
  782. OutKeyEvent.unmodified_character = 0;
  783. // CEF expects modifier key codes as one of the Carbon kVK_* key codes.
  784. if (Key == EKeys::LeftCommand)
  785. {
  786. OutKeyEvent.native_key_code = kVK_Command;
  787. }
  788. else if (Key == EKeys::LeftShift)
  789. {
  790. OutKeyEvent.native_key_code = kVK_Shift;
  791. }
  792. else if (Key == EKeys::LeftAlt)
  793. {
  794. OutKeyEvent.native_key_code = kVK_Option;
  795. }
  796. else if (Key == EKeys::LeftControl)
  797. {
  798. OutKeyEvent.native_key_code = kVK_Control;
  799. }
  800. else if (Key == EKeys::RightCommand)
  801. {
  802. // There isn't a separate code for the right hand command key defined, but CEF seems to use the unused value before the left command keycode
  803. OutKeyEvent.native_key_code = kVK_Command-1;
  804. }
  805. else if (Key == EKeys::RightShift)
  806. {
  807. OutKeyEvent.native_key_code = kVK_RightShift;
  808. }
  809. else if (Key == EKeys::RightAlt)
  810. {
  811. OutKeyEvent.native_key_code = kVK_RightOption;
  812. }
  813. else if (Key == EKeys::RightControl)
  814. {
  815. OutKeyEvent.native_key_code = kVK_RightControl;
  816. }
  817. }
  818. else
  819. {
  820. OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter();
  821. }
  822. OutKeyEvent.character = OutKeyEvent.unmodified_character;
  823. #elif PLATFORM_LINUX
  824. OutKeyEvent.native_key_code = InKeyEvent.GetKeyCode();
  825. FKey Key = InKeyEvent.GetKey();
  826. // helper macro so we can fill in all the A-Z, 0-9 keys
  827. #define LETTER_KEY_MACRO(val, vkey) else if(Key == EKeys::val) \
  828. { \
  829. OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter(); \
  830. OutKeyEvent.windows_key_code = vkey; \
  831. } \
  832. if (Key == EKeys::BackSpace)
  833. {
  834. OutKeyEvent.windows_key_code = VKEY_BACK;
  835. }
  836. else if (Key == EKeys::Tab)
  837. {
  838. OutKeyEvent.windows_key_code = VKEY_TAB;
  839. }
  840. else if (Key == EKeys::Enter)
  841. {
  842. OutKeyEvent.windows_key_code = VKEY_RETURN;
  843. }
  844. else if (Key == EKeys::Pause)
  845. {
  846. OutKeyEvent.windows_key_code = VKEY_PAUSE;
  847. }
  848. else if (Key == EKeys::Escape)
  849. {
  850. OutKeyEvent.windows_key_code = VKEY_ESCAPE;
  851. }
  852. else if (Key == EKeys::PageUp)
  853. {
  854. OutKeyEvent.windows_key_code = VKEY_PRIOR;
  855. }
  856. else if (Key == EKeys::PageDown)
  857. {
  858. OutKeyEvent.windows_key_code = VKEY_NEXT;
  859. }
  860. else if (Key == EKeys::End)
  861. {
  862. OutKeyEvent.windows_key_code = VKEY_END;
  863. }
  864. else if (Key == EKeys::Home)
  865. {
  866. OutKeyEvent.windows_key_code = VKEY_HOME;
  867. }
  868. else if (Key == EKeys::Left)
  869. {
  870. OutKeyEvent.windows_key_code = VKEY_LEFT;
  871. }
  872. else if (Key == EKeys::Up)
  873. {
  874. OutKeyEvent.windows_key_code = VKEY_UP;
  875. }
  876. else if (Key == EKeys::Right)
  877. {
  878. OutKeyEvent.windows_key_code = VKEY_RIGHT;
  879. }
  880. else if (Key == EKeys::Down)
  881. {
  882. OutKeyEvent.windows_key_code = VKEY_DOWN;
  883. }
  884. else if (Key == EKeys::Insert)
  885. {
  886. OutKeyEvent.windows_key_code = VKEY_INSERT;
  887. }
  888. else if (Key == EKeys::Delete)
  889. {
  890. OutKeyEvent.windows_key_code = VKEY_DELETE;
  891. }
  892. else if (Key == EKeys::F1)
  893. {
  894. OutKeyEvent.windows_key_code = VKEY_F1;
  895. }
  896. else if (Key == EKeys::F2)
  897. {
  898. OutKeyEvent.windows_key_code = VKEY_F2;
  899. }
  900. else if (Key == EKeys::F3)
  901. {
  902. OutKeyEvent.windows_key_code = VKEY_F3;
  903. }
  904. else if (Key == EKeys::F4)
  905. {
  906. OutKeyEvent.windows_key_code = VKEY_F4;
  907. }
  908. else if (Key == EKeys::F5)
  909. {
  910. OutKeyEvent.windows_key_code = VKEY_F5;
  911. }
  912. else if (Key == EKeys::F6)
  913. {
  914. OutKeyEvent.windows_key_code = VKEY_F6;
  915. }
  916. else if (Key == EKeys::F7)
  917. {
  918. OutKeyEvent.windows_key_code = VKEY_F7;
  919. }
  920. else if (Key == EKeys::F8)
  921. {
  922. OutKeyEvent.windows_key_code = VKEY_F8;
  923. }
  924. else if (Key == EKeys::F9)
  925. {
  926. OutKeyEvent.windows_key_code = VKEY_F9;
  927. }
  928. else if (Key == EKeys::F10)
  929. {
  930. OutKeyEvent.windows_key_code = VKEY_F10;
  931. }
  932. else if (Key == EKeys::F11)
  933. {
  934. OutKeyEvent.windows_key_code = VKEY_F11;
  935. }
  936. else if (Key == EKeys::F12)
  937. {
  938. OutKeyEvent.windows_key_code = VKEY_F12;
  939. }
  940. else if (Key == EKeys::CapsLock)
  941. {
  942. OutKeyEvent.windows_key_code = VKEY_CAPITAL;
  943. }
  944. else if (Key == EKeys::LeftCommand)
  945. {
  946. OutKeyEvent.windows_key_code = VKEY_MENU;
  947. }
  948. else if (Key == EKeys::LeftShift)
  949. {
  950. OutKeyEvent.windows_key_code = VKEY_SHIFT;
  951. }
  952. else if (Key == EKeys::LeftAlt)
  953. {
  954. OutKeyEvent.windows_key_code = VKEY_MENU;
  955. }
  956. else if (Key == EKeys::LeftControl)
  957. {
  958. OutKeyEvent.windows_key_code = VKEY_CONTROL;
  959. }
  960. else if (Key == EKeys::RightCommand)
  961. {
  962. OutKeyEvent.windows_key_code = VKEY_MENU;
  963. }
  964. else if (Key == EKeys::RightShift)
  965. {
  966. OutKeyEvent.windows_key_code = VKEY_SHIFT;
  967. }
  968. else if (Key == EKeys::RightAlt)
  969. {
  970. OutKeyEvent.windows_key_code = VKEY_MENU;
  971. }
  972. else if (Key == EKeys::RightControl)
  973. {
  974. OutKeyEvent.windows_key_code = VKEY_CONTROL;
  975. }
  976. else if(Key == EKeys::NumPadOne)
  977. {
  978. OutKeyEvent.windows_key_code = VKEY_NUMPAD1;
  979. }
  980. else if(Key == EKeys::NumPadTwo)
  981. {
  982. OutKeyEvent.windows_key_code = VKEY_NUMPAD2;
  983. }
  984. else if(Key == EKeys::NumPadThree)
  985. {
  986. OutKeyEvent.windows_key_code = VKEY_NUMPAD3;
  987. }
  988. else if(Key == EKeys::NumPadFour)
  989. {
  990. OutKeyEvent.windows_key_code = VKEY_NUMPAD4;
  991. }
  992. else if(Key == EKeys::NumPadFive)
  993. {
  994. OutKeyEvent.windows_key_code = VKEY_NUMPAD5;
  995. }
  996. else if(Key == EKeys::NumPadSix)
  997. {
  998. OutKeyEvent.windows_key_code = VKEY_NUMPAD6;
  999. }
  1000. else if(Key == EKeys::NumPadSeven)
  1001. {
  1002. OutKeyEvent.windows_key_code = VKEY_NUMPAD7;
  1003. }
  1004. else if(Key == EKeys::NumPadEight)
  1005. {
  1006. OutKeyEvent.windows_key_code = VKEY_NUMPAD8;
  1007. }
  1008. else if(Key == EKeys::NumPadNine)
  1009. {
  1010. OutKeyEvent.windows_key_code = VKEY_NUMPAD9;
  1011. }
  1012. else if(Key == EKeys::NumPadZero)
  1013. {
  1014. OutKeyEvent.windows_key_code = VKEY_NUMPAD0;
  1015. }
  1016. LETTER_KEY_MACRO( A, VKEY_A)
  1017. LETTER_KEY_MACRO( B, VKEY_B)
  1018. LETTER_KEY_MACRO( C, VKEY_C)
  1019. LETTER_KEY_MACRO( D, VKEY_D)
  1020. LETTER_KEY_MACRO( E, VKEY_E)
  1021. LETTER_KEY_MACRO( F, VKEY_F)
  1022. LETTER_KEY_MACRO( G, VKEY_G)
  1023. LETTER_KEY_MACRO( H, VKEY_H)
  1024. LETTER_KEY_MACRO( I, VKEY_I)
  1025. LETTER_KEY_MACRO( J, VKEY_J)
  1026. LETTER_KEY_MACRO( K, VKEY_K)
  1027. LETTER_KEY_MACRO( L, VKEY_L)
  1028. LETTER_KEY_MACRO( M, VKEY_M)
  1029. LETTER_KEY_MACRO( N, VKEY_N)
  1030. LETTER_KEY_MACRO( O, VKEY_O)
  1031. LETTER_KEY_MACRO( P, VKEY_P)
  1032. LETTER_KEY_MACRO( Q, VKEY_Q)
  1033. LETTER_KEY_MACRO( R, VKEY_R)
  1034. LETTER_KEY_MACRO( S, VKEY_S)
  1035. LETTER_KEY_MACRO( T, VKEY_T)
  1036. LETTER_KEY_MACRO( U, VKEY_U)
  1037. LETTER_KEY_MACRO( V, VKEY_V)
  1038. LETTER_KEY_MACRO( W, VKEY_W)
  1039. LETTER_KEY_MACRO( X, VKEY_X)
  1040. LETTER_KEY_MACRO( Y, VKEY_Y)
  1041. LETTER_KEY_MACRO( Z, VKEY_Z)
  1042. LETTER_KEY_MACRO( Zero, VKEY_0)
  1043. LETTER_KEY_MACRO( One, VKEY_1)
  1044. LETTER_KEY_MACRO( Two, VKEY_2)
  1045. LETTER_KEY_MACRO( Three, VKEY_3)
  1046. LETTER_KEY_MACRO( Four, VKEY_4)
  1047. LETTER_KEY_MACRO( Five, VKEY_5)
  1048. LETTER_KEY_MACRO( Six, VKEY_6)
  1049. LETTER_KEY_MACRO( Seven, VKEY_7)
  1050. LETTER_KEY_MACRO( Eight, VKEY_8)
  1051. LETTER_KEY_MACRO( Nine, VKEY_9)
  1052. else
  1053. {
  1054. OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter();
  1055. OutKeyEvent.windows_key_code = VKEY_UNKNOWN;
  1056. }
  1057. #else
  1058. OutKeyEvent.windows_key_code = InKeyEvent.GetKeyCode();
  1059. #endif
  1060. OutKeyEvent.modifiers = GetCefKeyboardModifiers(InKeyEvent);
  1061. //UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Modifiers: %i %i %i") , OutKeyEvent.unmodified_character, OutKeyEvent.windows_key_code, OutKeyEvent.modifiers);
  1062. }
  1063. #if PLATFORM_MAC
  1064. bool _FilterSystemKeyChord(const FKeyEvent& InKeyEvent)
  1065. {
  1066. if(InKeyEvent.IsControlDown())
  1067. {
  1068. // Special case for Mac - make sure Cmd+~ is always passed back to the OS
  1069. if (InKeyEvent.GetKey() == EKeys::Tilde)
  1070. {
  1071. return true;
  1072. }
  1073. // Special case for Mac - make sure Cmd+H is always ignored by CEF
  1074. if (InKeyEvent.GetKey() == EKeys::H )
  1075. {
  1076. return true;
  1077. }
  1078. }
  1079. return false;
  1080. }
  1081. #endif
  1082. bool FCEFWebInterfaceBrowserWindow::OnKeyDown(const FKeyEvent& InKeyEvent)
  1083. {
  1084. if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreKeyDownEvent)
  1085. {
  1086. #if PLATFORM_MAC
  1087. if(_FilterSystemKeyChord(InKeyEvent))
  1088. return false;
  1089. #endif
  1090. PreviousKeyDownEvent = InKeyEvent;
  1091. CefKeyEvent KeyEvent;
  1092. PopulateCefKeyEvent(InKeyEvent, KeyEvent);
  1093. KeyEvent.type = KEYEVENT_RAWKEYDOWN;
  1094. InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
  1095. return true;
  1096. }
  1097. return false;
  1098. }
  1099. bool FCEFWebInterfaceBrowserWindow::OnKeyUp(const FKeyEvent& InKeyEvent)
  1100. {
  1101. if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreKeyUpEvent)
  1102. {
  1103. #if PLATFORM_MAC
  1104. if(_FilterSystemKeyChord(InKeyEvent))
  1105. return false;
  1106. #endif
  1107. PreviousKeyUpEvent = InKeyEvent;
  1108. CefKeyEvent KeyEvent;
  1109. PopulateCefKeyEvent(InKeyEvent, KeyEvent);
  1110. KeyEvent.type = KEYEVENT_KEYUP;
  1111. InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
  1112. return true;
  1113. }
  1114. return false;
  1115. }
  1116. bool FCEFWebInterfaceBrowserWindow::OnKeyChar(const FCharacterEvent& InCharacterEvent)
  1117. {
  1118. if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreCharacterEvent)
  1119. {
  1120. PreviousCharacterEvent = InCharacterEvent;
  1121. CefKeyEvent KeyEvent;
  1122. #if PLATFORM_MAC || PLATFORM_LINUX
  1123. KeyEvent.character = InCharacterEvent.GetCharacter();
  1124. KeyEvent.windows_key_code = InCharacterEvent.GetCharacter();
  1125. #else
  1126. KeyEvent.windows_key_code = InCharacterEvent.GetCharacter();
  1127. #endif
  1128. KeyEvent.type = KEYEVENT_CHAR;
  1129. KeyEvent.modifiers = GetCefInputModifiers(InCharacterEvent);
  1130. #if PLATFORM_WINDOWS
  1131. if (InCharacterEvent.IsAltDown() && InCharacterEvent.IsControlDown())
  1132. {
  1133. // For german and other keyboards with an AltGR state, windows sets alt and left control down
  1134. // See OsrWindowWin::OnKeyEvent in
  1135. //https://bitbucket.org/chromiumembedded/cef/raw/c4baba880e0b28ce82845275b328a12b2407e2f0/tests/cefclient/browser/osr_window_win.cc
  1136. // from which the concept behind this check was taken
  1137. HKL CurrentKBLayout = ::GetKeyboardLayout(0);
  1138. SHORT ScanResult = ::VkKeyScanExW(InCharacterEvent.GetCharacter(), CurrentKBLayout);
  1139. if (((ScanResult >> 8) & 0xFF) == (2 | 4))
  1140. {
  1141. // ctrl-alt pressed from this single character event so convert to AltGR
  1142. KeyEvent.modifiers &= ~(EVENTFLAG_CONTROL_DOWN | EVENTFLAG_ALT_DOWN);
  1143. KeyEvent.modifiers |= EVENTFLAG_ALTGR_DOWN;
  1144. }
  1145. }
  1146. #endif
  1147. InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
  1148. return true;
  1149. }
  1150. return false;
  1151. }
  1152. FModifierKeysState FCEFWebInterfaceBrowserWindow::SlateModifiersFromCefModifiers(const CefKeyEvent& CefEvent)
  1153. {
  1154. return FModifierKeysState((CefEvent.modifiers & EVENTFLAG_SHIFT_DOWN) != 0,
  1155. (CefEvent.modifiers & EVENTFLAG_SHIFT_DOWN) != 0,
  1156. (CefEvent.modifiers & EVENTFLAG_CONTROL_DOWN) != 0,
  1157. (CefEvent.modifiers & EVENTFLAG_CONTROL_DOWN) != 0,
  1158. (CefEvent.modifiers & EVENTFLAG_ALT_DOWN) != 0,
  1159. (CefEvent.modifiers & EVENTFLAG_ALT_DOWN) != 0,
  1160. (CefEvent.modifiers & EVENTFLAG_COMMAND_DOWN) != 0,
  1161. (CefEvent.modifiers & EVENTFLAG_COMMAND_DOWN) != 0,
  1162. (CefEvent.modifiers & EVENTFLAG_CAPS_LOCK_ON) != 0);
  1163. }
  1164. /* This is an ugly hack to inject unhandled key events back into Slate.
  1165. During processing of the initial keyboard event, we don't know whether it is handled by the Web browser or not.
  1166. Not until after CEF calls OnKeyEvent in our CefKeyboardHandler implementation, which is after our own keyboard event handler
  1167. has returned.
  1168. The solution is to save a copy of the event and re-inject it into Slate while ensuring that we'll ignore it and bubble it up
  1169. the widget hierarchy this time around. */
  1170. bool FCEFWebInterfaceBrowserWindow::OnUnhandledKeyEvent(const CefKeyEvent& CefEvent)
  1171. {
  1172. bool bWasHandled = false;
  1173. if (IsValid())
  1174. {
  1175. CefWindowHandle NativeHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
  1176. switch (CefEvent.type)
  1177. {
  1178. case KEYEVENT_RAWKEYDOWN:
  1179. case KEYEVENT_KEYDOWN:
  1180. if (PreviousKeyDownEvent.IsSet())
  1181. {
  1182. bWasHandled = OnUnhandledKeyDown().IsBound() && OnUnhandledKeyDown().Execute(PreviousKeyDownEvent.GetValue());
  1183. if (!bWasHandled)
  1184. {
  1185. // If the keydown handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
  1186. bIgnoreKeyDownEvent = true;
  1187. bWasHandled = FSlateApplication::Get().ProcessKeyDownEvent(PreviousKeyDownEvent.GetValue());
  1188. bIgnoreKeyDownEvent = false;
  1189. }
  1190. PreviousKeyDownEvent.Reset();
  1191. }
  1192. else if (NativeHandle)
  1193. {
  1194. FKey const Key = FInputKeyManager::Get().GetKeyFromCodes(CefEvent.windows_key_code, 0);
  1195. if (Key.IsValid())
  1196. {
  1197. FKeyEvent KeyEvent(Key, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false, 0, CefEvent.windows_key_code);
  1198. bIgnoreKeyDownEvent = true;
  1199. bWasHandled = FSlateApplication::Get().ProcessKeyDownEvent(KeyEvent);
  1200. bIgnoreKeyDownEvent = false;
  1201. }
  1202. }
  1203. break;
  1204. case KEYEVENT_KEYUP:
  1205. if (PreviousKeyUpEvent.IsSet())
  1206. {
  1207. bWasHandled = OnUnhandledKeyUp().IsBound() && OnUnhandledKeyUp().Execute(PreviousKeyUpEvent.GetValue());
  1208. if (!bWasHandled)
  1209. {
  1210. // If the keyup handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
  1211. bIgnoreKeyUpEvent = true;
  1212. bWasHandled = FSlateApplication::Get().ProcessKeyUpEvent(PreviousKeyUpEvent.GetValue());
  1213. bIgnoreKeyUpEvent = false;
  1214. }
  1215. PreviousKeyUpEvent.Reset();
  1216. }
  1217. else if (NativeHandle)
  1218. {
  1219. FKey const Key = FInputKeyManager::Get().GetKeyFromCodes(CefEvent.windows_key_code, 0);
  1220. FKeyEvent KeyEvent(Key, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false, 0, CefEvent.windows_key_code);
  1221. bIgnoreKeyUpEvent = true;
  1222. bWasHandled = FSlateApplication::Get().ProcessKeyUpEvent(KeyEvent);
  1223. bIgnoreKeyUpEvent = false;
  1224. }
  1225. break;
  1226. case KEYEVENT_CHAR:
  1227. if (PreviousCharacterEvent.IsSet())
  1228. {
  1229. bWasHandled = OnUnhandledKeyChar().IsBound() && OnUnhandledKeyChar().Execute(PreviousCharacterEvent.GetValue());
  1230. if (!bWasHandled)
  1231. {
  1232. // If the keychar handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
  1233. bIgnoreCharacterEvent = true;
  1234. bWasHandled = FSlateApplication::Get().ProcessKeyCharEvent(PreviousCharacterEvent.GetValue());
  1235. bIgnoreCharacterEvent = false;
  1236. }
  1237. PreviousCharacterEvent.Reset();
  1238. }
  1239. else if (NativeHandle)
  1240. {
  1241. FCharacterEvent CharacterEvent(CefEvent.character, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false);
  1242. bIgnoreCharacterEvent = true;
  1243. bWasHandled = FSlateApplication::Get().ProcessKeyCharEvent(CharacterEvent);
  1244. bIgnoreCharacterEvent = false;
  1245. }
  1246. break;
  1247. default:
  1248. break;
  1249. }
  1250. }
  1251. return bWasHandled;
  1252. }
  1253. bool FCEFWebInterfaceBrowserWindow::OnJSDialog(CefJSDialogHandler::JSDialogType DialogType, const CefString& MessageText, const CefString& DefaultPromptText, CefRefPtr<CefJSDialogCallback> Callback, bool& OutSuppressMessage)
  1254. {
  1255. bool Retval = false;
  1256. if ( OnShowDialog().IsBound() )
  1257. {
  1258. TSharedPtr<IWebInterfaceBrowserDialog> Dialog(new FCEFWebInterfaceBrowserDialog(DialogType, MessageText, DefaultPromptText, Callback));
  1259. EWebInterfaceBrowserDialogEventResponse EventResponse = OnShowDialog().Execute(TWeakPtr<IWebInterfaceBrowserDialog>(Dialog));
  1260. switch (EventResponse)
  1261. {
  1262. case EWebInterfaceBrowserDialogEventResponse::Handled:
  1263. Retval = true;
  1264. break;
  1265. case EWebInterfaceBrowserDialogEventResponse::Continue:
  1266. if (DialogType == JSDIALOGTYPE_ALERT)
  1267. {
  1268. // Alert dialogs don't return a value, so treat Continue the same way as Ingore
  1269. OutSuppressMessage = true;
  1270. Retval = false;
  1271. }
  1272. else
  1273. {
  1274. Callback->Continue(true, DefaultPromptText);
  1275. Retval = true;
  1276. }
  1277. break;
  1278. case EWebInterfaceBrowserDialogEventResponse::Ignore:
  1279. OutSuppressMessage = true;
  1280. Retval = false;
  1281. break;
  1282. case EWebInterfaceBrowserDialogEventResponse::Unhandled:
  1283. default:
  1284. Retval = false;
  1285. break;
  1286. }
  1287. }
  1288. return Retval;
  1289. }
  1290. bool FCEFWebInterfaceBrowserWindow::OnBeforeUnloadDialog(const CefString& MessageText, bool IsReload, CefRefPtr<CefJSDialogCallback> Callback)
  1291. {
  1292. bool Retval = false;
  1293. if ( OnShowDialog().IsBound() )
  1294. {
  1295. TSharedPtr<IWebInterfaceBrowserDialog> Dialog(new FCEFWebInterfaceBrowserDialog(MessageText, IsReload, Callback));
  1296. EWebInterfaceBrowserDialogEventResponse EventResponse = OnShowDialog().Execute(TWeakPtr<IWebInterfaceBrowserDialog>(Dialog));
  1297. switch (EventResponse)
  1298. {
  1299. case EWebInterfaceBrowserDialogEventResponse::Handled:
  1300. Retval = true;
  1301. break;
  1302. case EWebInterfaceBrowserDialogEventResponse::Continue:
  1303. Callback->Continue(true, CefString());
  1304. Retval = true;
  1305. break;
  1306. case EWebInterfaceBrowserDialogEventResponse::Ignore:
  1307. Callback->Continue(false, CefString());
  1308. Retval = true;
  1309. break;
  1310. case EWebInterfaceBrowserDialogEventResponse::Unhandled:
  1311. default:
  1312. Retval = false;
  1313. break;
  1314. }
  1315. }
  1316. return Retval;
  1317. }
  1318. void FCEFWebInterfaceBrowserWindow::OnResetDialogState()
  1319. {
  1320. OnDismissAllDialogs().ExecuteIfBound();
  1321. }
  1322. void FCEFWebInterfaceBrowserWindow::OnRenderProcessTerminated(CefRequestHandler::TerminationStatus Status)
  1323. {
  1324. if(bRecoverFromRenderProcessCrash)
  1325. {
  1326. bRecoverFromRenderProcessCrash = false;
  1327. NotifyDocumentError((int)ERR_FAILED); // Only attempt a single recovery at a time
  1328. }
  1329. bRecoverFromRenderProcessCrash = true;
  1330. Reload();
  1331. }
  1332. FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  1333. {
  1334. FReply Reply = FReply::Unhandled();
  1335. if (IsValid() && !BlockInputInDirectHwndMode())
  1336. {
  1337. FKey Button = MouseEvent.GetEffectingButton();
  1338. // CEF only supports left, right, and middle mouse buttons
  1339. bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
  1340. if(bIsCefSupportedButton)
  1341. {
  1342. CefBrowserHost::MouseButtonType Type =
  1343. (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
  1344. Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
  1345. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
  1346. // If the click happened inside a drag region we enable window dragging which will start firing OnDragWindow events on mouse move
  1347. if (Type == MBT_LEFT && IsInDragRegion(FIntPoint(Event.x, Event.y)))
  1348. {
  1349. bDraggingWindow = true;
  1350. }
  1351. InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false,1);
  1352. Reply = FReply::Handled();
  1353. }
  1354. }
  1355. return Reply;
  1356. }
  1357. FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  1358. {
  1359. FReply Reply = FReply::Unhandled();
  1360. if (IsValid() && !BlockInputInDirectHwndMode())
  1361. {
  1362. FKey Button = MouseEvent.GetEffectingButton();
  1363. // CEF only supports left, right, and middle mouse buttons
  1364. bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
  1365. if(bIsCefSupportedButton)
  1366. {
  1367. CefBrowserHost::MouseButtonType Type =
  1368. (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
  1369. Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
  1370. if (Type == MBT_LEFT)
  1371. {
  1372. bDraggingWindow = false;
  1373. }
  1374. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
  1375. InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, true, 1);
  1376. Reply = FReply::Handled();
  1377. }
  1378. else if(Button == EKeys::ThumbMouseButton && bThumbMouseButtonNavigation)
  1379. {
  1380. if(CanGoBack())
  1381. {
  1382. GoBack();
  1383. Reply = FReply::Handled();
  1384. }
  1385. }
  1386. else if(Button == EKeys::ThumbMouseButton2 && bThumbMouseButtonNavigation)
  1387. {
  1388. if(CanGoForward())
  1389. {
  1390. GoForward();
  1391. Reply = FReply::Handled();
  1392. }
  1393. }
  1394. }
  1395. return Reply;
  1396. }
  1397. FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  1398. {
  1399. FReply Reply = FReply::Unhandled();
  1400. if (IsValid() && !BlockInputInDirectHwndMode())
  1401. {
  1402. FKey Button = MouseEvent.GetEffectingButton();
  1403. // CEF only supports left, right, and middle mouse buttons
  1404. bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
  1405. if(bIsCefSupportedButton)
  1406. {
  1407. CefBrowserHost::MouseButtonType Type =
  1408. (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
  1409. Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
  1410. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
  1411. InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false, 2);
  1412. Reply = FReply::Handled();
  1413. }
  1414. }
  1415. return Reply;
  1416. }
  1417. FReply FCEFWebInterfaceBrowserWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  1418. {
  1419. FReply Reply = FReply::Unhandled();
  1420. if (IsValid() && !BlockInputInDirectHwndMode())
  1421. {
  1422. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
  1423. bool bEventConsumedByDragCallback = false;
  1424. FIntRect test;
  1425. if (bDraggingWindow && OnDragWindow().IsBound())
  1426. {
  1427. if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
  1428. {
  1429. bEventConsumedByDragCallback = OnDragWindow().Execute(MouseEvent);
  1430. }
  1431. else
  1432. {
  1433. bDraggingWindow = false;
  1434. }
  1435. }
  1436. if (!bEventConsumedByDragCallback)
  1437. {
  1438. InternalCefBrowser->GetHost()->SendMouseMoveEvent(Event, false);
  1439. }
  1440. Reply = FReply::Handled();
  1441. }
  1442. return Reply;
  1443. }
  1444. void FCEFWebInterfaceBrowserWindow::OnMouseLeave(const FPointerEvent& MouseEvent)
  1445. {
  1446. // Ensure we clear any tooltips if the mouse leaves the window.
  1447. SetToolTip(CefString());
  1448. // We have no geometry here to convert our mouse event to local space so we just make a dummy event and set the moueLeave param to true
  1449. CefMouseEvent DummyEvent;
  1450. if (IsValid() && !BlockInputInDirectHwndMode())
  1451. {
  1452. InternalCefBrowser->GetHost()->SendMouseMoveEvent(DummyEvent, true);
  1453. }
  1454. }
  1455. void FCEFWebInterfaceBrowserWindow::SetSupportsMouseWheel(bool bValue)
  1456. {
  1457. bSupportsMouseWheel = bValue;
  1458. }
  1459. bool FCEFWebInterfaceBrowserWindow::GetSupportsMouseWheel() const
  1460. {
  1461. return bSupportsMouseWheel;
  1462. }
  1463. FReply FCEFWebInterfaceBrowserWindow::OnTouchGesture(const FGeometry& MyGeometry, const FPointerEvent& GestureEvent, bool bIsPopup)
  1464. {
  1465. FReply Reply = FReply::Unhandled();
  1466. if(IsValid() && bSupportsMouseWheel && !BlockInputInDirectHwndMode())
  1467. {
  1468. const EGestureEvent GestureType = GestureEvent.GetGestureType();
  1469. const FVector2D& GestureDelta = GestureEvent.GetGestureDelta();
  1470. if ( GestureType == EGestureEvent::Scroll )
  1471. {
  1472. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, GestureEvent, bIsPopup);
  1473. InternalCefBrowser->GetHost()->SendMouseWheelEvent(Event, GestureDelta.X, GestureDelta.Y);
  1474. Reply = FReply::Handled();
  1475. }
  1476. }
  1477. return Reply;
  1478. }
  1479. FReply FCEFWebInterfaceBrowserWindow::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  1480. {
  1481. FReply Reply = FReply::Unhandled();
  1482. if(IsValid() && bSupportsMouseWheel && !BlockInputInDirectHwndMode())
  1483. {
  1484. #if PLATFORM_WINDOWS
  1485. // The original delta is reduced so this should bring it back to what CEF expects
  1486. // see WindowsApplication.cpp , case WM_MOUSEWHEEL:
  1487. const float SpinFactor = 120.0f;
  1488. #else
  1489. // other OS's seem to want us to scale by "line height" here, so pick a magic number
  1490. // 50 matches a single mouse wheel tick in movement as compared to Chrome
  1491. const float SpinFactor = 50.0f;
  1492. #endif
  1493. const float TrueDelta = MouseEvent.GetWheelDelta() * SpinFactor;
  1494. if (fabs(TrueDelta) > 0.001f)
  1495. {
  1496. CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
  1497. InternalCefBrowser->GetHost()->SendMouseWheelEvent(Event,
  1498. MouseEvent.IsShiftDown() ? TrueDelta : 0,
  1499. !MouseEvent.IsShiftDown() ? TrueDelta : 0);
  1500. }
  1501. Reply = FReply::Handled();
  1502. }
  1503. return Reply;
  1504. }
  1505. void FCEFWebInterfaceBrowserWindow::OnFocus(bool SetFocus, bool bIsPopup)
  1506. {
  1507. if (bIsPopup)
  1508. {
  1509. bPopupHasFocus = SetFocus;
  1510. }
  1511. else
  1512. {
  1513. bMainHasFocus = SetFocus;
  1514. }
  1515. #if !PLATFORM_LINUX
  1516. Ime->SetFocus(!bPopupHasFocus && bMainHasFocus);
  1517. #endif
  1518. // Only notify focus if there is no popup menu with focus, as SendFocusEvent will dismiss any popup menus.
  1519. if (IsValid() && !bPopupHasFocus)
  1520. {
  1521. InternalCefBrowser->GetHost()->SendFocusEvent(bMainHasFocus);
  1522. }
  1523. }
  1524. void FCEFWebInterfaceBrowserWindow::OnCaptureLost()
  1525. {
  1526. if (IsValid())
  1527. {
  1528. InternalCefBrowser->GetHost()->SendCaptureLostEvent();
  1529. }
  1530. }
  1531. bool FCEFWebInterfaceBrowserWindow::CanGoBack() const
  1532. {
  1533. if (IsValid())
  1534. {
  1535. return InternalCefBrowser->CanGoBack();
  1536. }
  1537. return false;
  1538. }
  1539. void FCEFWebInterfaceBrowserWindow::GoBack()
  1540. {
  1541. if (IsValid())
  1542. {
  1543. InternalCefBrowser->GoBack();
  1544. }
  1545. }
  1546. bool FCEFWebInterfaceBrowserWindow::CanGoForward() const
  1547. {
  1548. if (IsValid())
  1549. {
  1550. return InternalCefBrowser->CanGoForward();
  1551. }
  1552. return false;
  1553. }
  1554. void FCEFWebInterfaceBrowserWindow::GoForward()
  1555. {
  1556. if (IsValid())
  1557. {
  1558. InternalCefBrowser->GoForward();
  1559. }
  1560. }
  1561. bool FCEFWebInterfaceBrowserWindow::IsLoading() const
  1562. {
  1563. if (IsValid())
  1564. {
  1565. return InternalCefBrowser->IsLoading();
  1566. }
  1567. return false;
  1568. }
  1569. void FCEFWebInterfaceBrowserWindow::Reload()
  1570. {
  1571. if (IsValid())
  1572. {
  1573. InternalCefBrowser->Reload();
  1574. }
  1575. }
  1576. void FCEFWebInterfaceBrowserWindow::StopLoad()
  1577. {
  1578. if (IsValid())
  1579. {
  1580. InternalCefBrowser->StopLoad();
  1581. }
  1582. }
  1583. void FCEFWebInterfaceBrowserWindow::ExecuteJavascript(const FString& Script)
  1584. {
  1585. if (IsValid())
  1586. {
  1587. CefRefPtr<CefFrame> frame = InternalCefBrowser->GetMainFrame();
  1588. frame->ExecuteJavaScript(TCHAR_TO_UTF8(*Script), frame->GetURL(), 0);
  1589. }
  1590. }
  1591. void FCEFWebInterfaceBrowserWindow::CloseBrowser(bool bForce, bool bBlockTillClosed)
  1592. {
  1593. if (IsValid())
  1594. {
  1595. CefRefPtr<CefBrowserHost> Host = InternalCefBrowser->GetHost();
  1596. #if PLATFORM_MAC
  1597. CefWindowHandle NativeWindowHandle = Host->GetWindowHandle();
  1598. if (NativeWindowHandle != nullptr)
  1599. {
  1600. NSView *browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
  1601. if (browserView != nil)
  1602. [browserView removeFromSuperview];
  1603. }
  1604. #endif
  1605. // In case this is called from inside a CEF event handler, use CEF's task mechanism to
  1606. // postpone the actual closing of the window until it is safe.
  1607. CefPostTask(TID_UI, new FCEFInterfaceBrowserClosureTask(nullptr, [=]()
  1608. {
  1609. // if blocking till closed for the close here
  1610. Host->CloseBrowser(bForce||bBlockTillClosed);
  1611. }));
  1612. if (bBlockTillClosed)
  1613. {
  1614. SetIsHidden(true); // hide the window as we close it
  1615. float CloseWaitTimeout = 1.0f;
  1616. // BUGBUG Alfred - I think 1 second should be enough wait, remove these config settings
  1617. // if we don't end up having to tune timeouts in the field.
  1618. GConfig->GetFloat(TEXT("Browser"), TEXT("CloseWaitTimeout"), CloseWaitTimeout, GEngineIni);
  1619. if (IsEngineExitRequested())
  1620. {
  1621. // wait longer if the app is shutting down
  1622. GConfig->GetFloat(TEXT("Browser"), TEXT("CloseWaitTimeoutAppExit"), CloseWaitTimeout, GEngineIni);
  1623. }
  1624. const double StartWaitAppTime = FPlatformTime::Seconds();
  1625. while (InternalCefBrowser != nullptr)
  1626. {
  1627. if (FPlatformTime::Seconds() - StartWaitAppTime > CloseWaitTimeout )
  1628. {
  1629. UE_LOG(LogWebInterfaceBrowser, Error, TEXT("CloseBrowser - took more than %0.2f second to close. Abandoning wait..."), CloseWaitTimeout);
  1630. break; // don't spin forever
  1631. }
  1632. FPlatformProcess::Sleep(0.01);
  1633. // CEF needs the windows message pump run to be able to finish closing a browser, so run it manually here
  1634. FSlateApplication::Get().PumpMessages();
  1635. CefDoMessageLoopWork();
  1636. }
  1637. }
  1638. }
  1639. }
  1640. CefRefPtr<CefBrowser> FCEFWebInterfaceBrowserWindow::GetCefBrowser()
  1641. {
  1642. return InternalCefBrowser;
  1643. }
  1644. void FCEFWebInterfaceBrowserWindow::SetTitle(const CefString& InTitle)
  1645. {
  1646. Title = WCHAR_TO_TCHAR(InTitle.ToWString().c_str());
  1647. TitleChangedEvent.Broadcast(Title);
  1648. }
  1649. void FCEFWebInterfaceBrowserWindow::SetUrl(const CefString& Url)
  1650. {
  1651. CurrentUrl = WCHAR_TO_TCHAR(Url.ToWString().c_str());
  1652. OnUrlChanged().Broadcast(CurrentUrl);
  1653. }
  1654. void FCEFWebInterfaceBrowserWindow::SetToolTip(const CefString& CefToolTip)
  1655. {
  1656. FString NewToolTipText = WCHAR_TO_TCHAR(CefToolTip.ToWString().c_str());
  1657. if (ToolTipText != NewToolTipText)
  1658. {
  1659. ToolTipText = NewToolTipText;
  1660. OnToolTip().Broadcast(ToolTipText);
  1661. }
  1662. }
  1663. void FCEFWebInterfaceBrowserWindow::GetViewRect(CefRect& Rect)
  1664. {
  1665. if (ViewportSize == FIntPoint::ZeroValue)
  1666. {
  1667. Rect.width = 1; // CEF requires a minimum of a 1x1 window to correctly run
  1668. Rect.height = 1;
  1669. }
  1670. else
  1671. {
  1672. // CEF requires a minimum of a 1px in each dimension to correctly run
  1673. Rect.width = FMath::Max( ViewportSize.X, 1);
  1674. Rect.height = FMath::Max( ViewportSize.Y, 1);
  1675. }
  1676. }
  1677. int FCEFWebInterfaceBrowserWindow::GetLoadError()
  1678. {
  1679. return ErrorCode;
  1680. }
  1681. void FCEFWebInterfaceBrowserWindow::NotifyDocumentError(
  1682. CefLoadHandler::ErrorCode InErrorCode,
  1683. const CefString& ErrorText,
  1684. const CefString& FailedUrl)
  1685. {
  1686. FString Url = WCHAR_TO_TCHAR(FailedUrl.ToWString().c_str());
  1687. if (InErrorCode == ERR_ABORTED)
  1688. {
  1689. // Aborting navigation is not an error case but we do need to wait for any existing navigations, handled via OnBeforeBrowse(), to fully abort before we can initiate a new navigation.
  1690. if (!PendingAbortUrl.IsEmpty() && PendingAbortUrl == Url)
  1691. {
  1692. PendingAbortUrl.Empty();
  1693. bDeferNavigations = false;
  1694. if (HasPendingNavigation())
  1695. {
  1696. ProcessPendingNavigation();
  1697. }
  1698. }
  1699. return;
  1700. }
  1701. if (IsShowingErrorMessages())
  1702. {
  1703. // Display a load error message. Note: The user's code will still have a chance to handle this error after this error message is displayed.
  1704. FFormatNamedArguments Args;
  1705. {
  1706. Args.Add(TEXT("FailedUrl"), FText::FromString(Url));
  1707. Args.Add(TEXT("ErrorText"), FText::FromString(WCHAR_TO_TCHAR(ErrorText.ToWString().c_str())));
  1708. Args.Add(TEXT("ErrorCode"), FText::AsNumber((int)InErrorCode));
  1709. }
  1710. FText ErrorMsg = FText::Format(NSLOCTEXT("WebBrowserHandler", "WebBrowserLoadError", "Failed to load URL {FailedUrl} with error {ErrorText} ({ErrorCode})."), Args);
  1711. FString ErrorHTML = TEXT("<html><body bgcolor=\"white\"><h2>") + ErrorMsg.ToString() + TEXT("</h2></body></html>");
  1712. LoadString(ErrorHTML, Url);
  1713. }
  1714. NotifyDocumentError((int)InErrorCode);
  1715. }
  1716. void FCEFWebInterfaceBrowserWindow::NotifyDocumentError(int InErrorCode)
  1717. {
  1718. ErrorCode = InErrorCode;
  1719. DocumentState = EWebInterfaceBrowserDocumentState::Error;
  1720. DocumentStateChangedEvent.Broadcast(DocumentState);
  1721. }
  1722. void FCEFWebInterfaceBrowserWindow::NotifyDocumentLoadingStateChange(bool IsLoading)
  1723. {
  1724. if (! IsLoading)
  1725. {
  1726. bIsInitialized = true;
  1727. if (bRecoverFromRenderProcessCrash)
  1728. {
  1729. bRecoverFromRenderProcessCrash = false;
  1730. // Toggle hidden/visible state to get OnPaint calls from CEF.
  1731. SetIsHidden(true);
  1732. SetIsHidden(false);
  1733. }
  1734. // Compatibility with Android script bindings: dispatch a custom ue:ready event when the document is fully loaded
  1735. ExecuteJavascript(TEXT("document.dispatchEvent(new CustomEvent('ue:ready', {details: window.ue}));"));
  1736. }
  1737. // Ignore a load completed notification if there was an error.
  1738. // For load started, reset any errors from previous page load.
  1739. if (IsLoading || DocumentState != EWebInterfaceBrowserDocumentState::Error)
  1740. {
  1741. ErrorCode = 0;
  1742. DocumentState = IsLoading
  1743. ? EWebInterfaceBrowserDocumentState::Loading
  1744. : EWebInterfaceBrowserDocumentState::Completed;
  1745. DocumentStateChangedEvent.Broadcast(DocumentState);
  1746. }
  1747. }
  1748. FSlateRenderer* const FCEFWebInterfaceBrowserWindow::GetRenderer()
  1749. {
  1750. if (FSlateApplication::IsInitialized())
  1751. {
  1752. if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
  1753. {
  1754. if (!Renderer->HasLostDevice())
  1755. {
  1756. return Renderer;
  1757. }
  1758. }
  1759. }
  1760. ReleaseTextures();
  1761. return nullptr;
  1762. }
  1763. void FCEFWebInterfaceBrowserWindow::HandleRenderingError()
  1764. {
  1765. // GetRenderer handles errors already
  1766. GetRenderer();
  1767. }
  1768. void FCEFWebInterfaceBrowserWindow::OnPaint(CefRenderHandler::PaintElementType Type, const CefRenderHandler::RectList& DirtyRects, const void* Buffer, int Width, int Height)
  1769. {
  1770. bool bNeedsRedraw = false;
  1771. if (bUsingAcceleratedPaint)
  1772. {
  1773. UE_LOG(LogWebInterfaceBrowser, Error, TEXT("Accelerated CEF rendering selected but OnPaint called. Disabling accelerated rendering for this browser window."));
  1774. bUsingAcceleratedPaint = false;
  1775. if (UpdatableTextures[Type] != nullptr)
  1776. {
  1777. if (FSlateRenderer* const Renderer = GetRenderer())
  1778. {
  1779. Renderer->ReleaseUpdatableTexture(UpdatableTextures[Type]);
  1780. HandleRenderingError();
  1781. UpdatableTextures[Type] = nullptr;
  1782. }
  1783. }
  1784. }
  1785. if (UpdatableTextures[Type] == nullptr)
  1786. {
  1787. if (FSlateRenderer* const Renderer = GetRenderer())
  1788. {
  1789. UpdatableTextures[Type] = Renderer->CreateUpdatableTexture(Width, Height);
  1790. HandleRenderingError();
  1791. }
  1792. }
  1793. if (UpdatableTextures[Type] != nullptr)
  1794. {
  1795. // Note that with more recent versions of CEF, the DirtyRects will always contain a single element, as it merges all dirty areas into a single rectangle before calling OnPaint
  1796. // In case that should change in the future, we'll simply update the entire area if DirtyRects is not a single element.
  1797. FIntRect Dirty = (DirtyRects.size() == 1) ? FIntRect(DirtyRects[0].x, DirtyRects[0].y, DirtyRects[0].x + DirtyRects[0].width, DirtyRects[0].y + DirtyRects[0].height) : FIntRect();
  1798. if (Type == PET_VIEW && BufferedVideo.IsValid() )
  1799. {
  1800. // If we're using bufferedVideo, submit the frame to it
  1801. bNeedsRedraw = BufferedVideo->SubmitFrame(Width, Height, Buffer, Dirty);
  1802. }
  1803. else
  1804. {
  1805. UpdatableTextures[Type]->UpdateTextureThreadSafeRaw(Width, Height, Buffer, Dirty);
  1806. HandleRenderingError();
  1807. if (Type == PET_POPUP && bShowPopupRequested)
  1808. {
  1809. bShowPopupRequested = false;
  1810. bPopupHasFocus = true;
  1811. const float DPIScale = FPlatformApplicationMisc::GetDPIScaleFactorAtPoint(PopupPosition.X, PopupPosition.Y);
  1812. FIntPoint PopupSize = FIntPoint(Width / DPIScale, Height / DPIScale);
  1813. FIntRect PopupRect = FIntRect(PopupPosition, PopupPosition + PopupSize);
  1814. OnShowPopup().Broadcast(PopupRect);
  1815. }
  1816. bNeedsRedraw = true;
  1817. }
  1818. }
  1819. bIsInitialized = true;
  1820. if (bNeedsRedraw)
  1821. {
  1822. NeedsRedrawEvent.Broadcast();
  1823. }
  1824. }
  1825. void FCEFWebInterfaceBrowserWindow::OnAcceleratedPaint(CefRenderHandler::PaintElementType Type, const CefRenderHandler::RectList& DirtyRects, void* SharedHandle)
  1826. {
  1827. bool bNeedsRedraw = false;
  1828. if (!bUsingAcceleratedPaint)
  1829. {
  1830. UE_LOG(LogWebInterfaceBrowser, Error, TEXT("Accelerated CEF rendering NOT selected but OnAcceleratedPaint called. Enabling accelerated rendering for this browser window."));
  1831. bUsingAcceleratedPaint = true;
  1832. if (UpdatableTextures[Type] != nullptr)
  1833. {
  1834. if (FSlateRenderer* const Renderer = GetRenderer())
  1835. {
  1836. Renderer->ReleaseUpdatableTexture(UpdatableTextures[Type]);
  1837. HandleRenderingError();
  1838. UpdatableTextures[Type] = nullptr;
  1839. }
  1840. }
  1841. }
  1842. #if PLATFORM_MAC
  1843. // an IOSurface backs the handle here and its texture is automatically updated if changed, so we only need to
  1844. // update our texture if the backing handle itself changed
  1845. if (LastPaintedSharedHandle == SharedHandle)
  1846. return;
  1847. LastPaintedSharedHandle = SharedHandle;
  1848. #endif
  1849. FIntRect Dirty = (DirtyRects.size() == 1) ? FIntRect(DirtyRects[0].x, DirtyRects[0].y, DirtyRects[0].x + DirtyRects[0].width, DirtyRects[0].y + DirtyRects[0].height) : FIntRect();
  1850. if (UpdatableTextures[Type] == nullptr)
  1851. {
  1852. if (FSlateRenderer* const Renderer = GetRenderer())
  1853. {
  1854. if (RHIRenderHelper)
  1855. {
  1856. UpdatableTextures[Type] = RHIRenderHelper->CreateTexture(SharedHandle);
  1857. }
  1858. else
  1859. {
  1860. UpdatableTextures[Type] = Renderer->CreateSharedHandleTexture(SharedHandle);
  1861. }
  1862. Dirty = FIntRect(); // force a fully copy when we make a new texture
  1863. HandleRenderingError();
  1864. }
  1865. }
  1866. if (UpdatableTextures[Type] != nullptr)
  1867. {
  1868. #if PLATFORM_WINDOWS
  1869. if (RHIRenderHelper)
  1870. {
  1871. RHIRenderHelper->UpdateSharedHandleTexture(SharedHandle, UpdatableTextures[Type], Dirty.Scale(ViewportDPIScaleFactor));
  1872. }
  1873. else
  1874. {
  1875. UpdatableTextures[Type]->UpdateTextureThreadSafeWithKeyedTextureHandle(SharedHandle, 1, 0, Dirty.Scale(ViewportDPIScaleFactor));
  1876. }
  1877. #else
  1878. UpdatableTextures[Type]->UpdateTextureThreadSafeWithKeyedTextureHandle(SharedHandle, 1, 0, Dirty.Scale(ViewportDPIScaleFactor));
  1879. #endif
  1880. bNeedsRedraw = true;
  1881. if (Type == PET_POPUP && bShowPopupRequested)
  1882. {
  1883. bShowPopupRequested = false;
  1884. bPopupHasFocus = true;
  1885. const float DPIScale = FPlatformApplicationMisc::GetDPIScaleFactorAtPoint(PopupPosition.X, PopupPosition.Y);
  1886. FIntPoint PopupSize = FIntPoint(UpdatableTextures[Type]->GetSlateResource()->GetWidth() / DPIScale, UpdatableTextures[Type]->GetSlateResource()->GetHeight() / DPIScale);
  1887. FIntRect PopupRect = FIntRect(PopupPosition, PopupPosition + PopupSize);
  1888. OnShowPopup().Broadcast(PopupRect);
  1889. }
  1890. }
  1891. bIsInitialized = true;
  1892. if (bNeedsRedraw)
  1893. {
  1894. NeedsRedrawEvent.Broadcast();
  1895. }
  1896. }
  1897. void FCEFWebInterfaceBrowserWindow::UpdateVideoBuffering()
  1898. {
  1899. if (BufferedVideo.IsValid() && UpdatableTextures[PET_VIEW] != nullptr )
  1900. {
  1901. FSlateTextureData* SlateTextureData = BufferedVideo->GetNextFrameTextureData();
  1902. if (SlateTextureData != nullptr )
  1903. {
  1904. UpdatableTextures[PET_VIEW]->UpdateTextureThreadSafeWithTextureData(SlateTextureData);
  1905. HandleRenderingError();
  1906. }
  1907. }
  1908. }
  1909. #if PLATFORM_WINDOWS
  1910. bool FCEFWebInterfaceBrowserWindow::LoadCustomCEF3Cursor(cef_cursor_type_t Type)
  1911. {
  1912. // generated from the ui_unscaled_resources.h file in a CEF build
  1913. #define IDC_PAN_EAST 25846
  1914. #define IDC_PAN_MIDDLE 25847
  1915. #define IDC_PAN_MIDDLE_HORIZONTAL 25848
  1916. #define IDC_PAN_MIDDLE_VERTICAL 25849
  1917. #define IDC_PAN_NORTH 25850
  1918. #define IDC_PAN_NORTH_EAST 25851
  1919. #define IDC_PAN_NORTH_WEST 25852
  1920. #define IDC_PAN_SOUTH 25853
  1921. #define IDC_PAN_SOUTH_EAST 25854
  1922. #define IDC_PAN_SOUTH_WEST 25855
  1923. #define IDC_PAN_WEST 25856
  1924. HINSTANCE CEF3ModuleHandle = (HINSTANCE)CEF3Utils::GetCEF3ModuleHandle();
  1925. if (CEF3ModuleHandle != nullptr)
  1926. {
  1927. HCURSOR customCursor = 0;
  1928. switch (Type) {
  1929. case CT_MIDDLE_PANNING_HORIZONTAL:
  1930. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE_HORIZONTAL));
  1931. break;
  1932. case CT_MIDDLE_PANNING_VERTICAL:
  1933. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE_VERTICAL));
  1934. break;
  1935. case CT_MIDDLEPANNING:
  1936. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE));
  1937. break;
  1938. case CT_SOUTHPANNING:
  1939. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH));
  1940. break;
  1941. case CT_NORTHPANNING:
  1942. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH));
  1943. break;
  1944. case CT_EASTPANNING:
  1945. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_EAST));
  1946. break;
  1947. case CT_WESTPANNING:
  1948. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_WEST));
  1949. break;
  1950. case CT_NORTHEASTPANNING:
  1951. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH_EAST));
  1952. break;
  1953. case CT_NORTHWESTPANNING:
  1954. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH_WEST));
  1955. break;
  1956. case CT_SOUTHEASTPANNING:
  1957. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH_EAST));
  1958. break;
  1959. case CT_SOUTHWESTPANNING:
  1960. customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH_WEST));
  1961. break;
  1962. }
  1963. if (customCursor)
  1964. {
  1965. TSharedPtr<ICursor> PlatformCursor = FSlateApplication::Get().GetPlatformCursor();
  1966. if (PlatformCursor.IsValid())
  1967. {
  1968. PlatformCursor->SetTypeShape(EMouseCursor::Custom, (void*)customCursor);
  1969. Cursor = EMouseCursor::Custom;
  1970. ::SetCursor(customCursor);
  1971. }
  1972. return true;
  1973. }
  1974. }
  1975. return false;
  1976. }
  1977. #endif
  1978. bool FCEFWebInterfaceBrowserWindow::OnCursorChange(CefCursorHandle CefCursor, cef_cursor_type_t Type, const CefCursorInfo& CustomCursorInfo)
  1979. {
  1980. #if PLATFORM_WINDOWS || PLATFORM_MAC
  1981. if (bUseNativeCursors)
  1982. {
  1983. switch (Type) {
  1984. // Map the basic 3 cursor types directly to Slate types on all platforms
  1985. case CT_NONE:
  1986. Cursor = EMouseCursor::None;
  1987. break;
  1988. case CT_POINTER:
  1989. Cursor = EMouseCursor::Default;
  1990. break;
  1991. case CT_IBEAM:
  1992. Cursor = EMouseCursor::TextEditBeam;
  1993. break;
  1994. default:
  1995. // Platform specific support for native cursor types
  1996. {
  1997. #if PLATFORM_WINDOWS
  1998. // check if we have a cursor in libcef.dll we can use
  1999. if (LoadCustomCEF3Cursor(Type))
  2000. return true;
  2001. #endif
  2002. TSharedPtr<ICursor> PlatformCursor = FSlateApplication::Get().GetPlatformCursor();
  2003. if (PlatformCursor.IsValid())
  2004. {
  2005. PlatformCursor->SetTypeShape(EMouseCursor::Custom, (void*)CefCursor);
  2006. Cursor = EMouseCursor::Custom;
  2007. }
  2008. }
  2009. break;
  2010. }
  2011. }
  2012. else
  2013. #endif
  2014. switch (Type) {
  2015. case CT_NONE:
  2016. Cursor = EMouseCursor::None;
  2017. break;
  2018. case CT_POINTER:
  2019. Cursor = EMouseCursor::Default;
  2020. break;
  2021. case CT_IBEAM:
  2022. Cursor = EMouseCursor::TextEditBeam;
  2023. break;
  2024. case CT_VERTICALTEXT:
  2025. Cursor = EMouseCursor::TextEditBeam;
  2026. break;
  2027. case CT_EASTRESIZE:
  2028. case CT_WESTRESIZE:
  2029. case CT_EASTWESTRESIZE:
  2030. case CT_COLUMNRESIZE:
  2031. Cursor = EMouseCursor::ResizeLeftRight;
  2032. break;
  2033. case CT_NORTHRESIZE:
  2034. case CT_SOUTHRESIZE:
  2035. case CT_NORTHSOUTHRESIZE:
  2036. case CT_ROWRESIZE:
  2037. Cursor = EMouseCursor::ResizeUpDown;
  2038. break;
  2039. case CT_NORTHWESTRESIZE:
  2040. case CT_SOUTHEASTRESIZE:
  2041. case CT_NORTHWESTSOUTHEASTRESIZE:
  2042. Cursor = EMouseCursor::ResizeSouthEast;
  2043. break;
  2044. case CT_NORTHEASTRESIZE:
  2045. case CT_SOUTHWESTRESIZE:
  2046. case CT_NORTHEASTSOUTHWESTRESIZE:
  2047. Cursor = EMouseCursor::ResizeSouthWest;
  2048. break;
  2049. case CT_MOVE:
  2050. case CT_MIDDLEPANNING:
  2051. case CT_EASTPANNING:
  2052. case CT_NORTHPANNING:
  2053. case CT_NORTHEASTPANNING:
  2054. case CT_NORTHWESTPANNING:
  2055. case CT_SOUTHPANNING:
  2056. case CT_SOUTHEASTPANNING:
  2057. case CT_SOUTHWESTPANNING:
  2058. case CT_WESTPANNING:
  2059. Cursor = EMouseCursor::CardinalCross;
  2060. break;
  2061. case CT_CROSS:
  2062. Cursor = EMouseCursor::Crosshairs;
  2063. break;
  2064. case CT_HAND:
  2065. Cursor = EMouseCursor::Hand;
  2066. break;
  2067. case CT_GRAB:
  2068. Cursor = EMouseCursor::GrabHand;
  2069. break;
  2070. case CT_GRABBING:
  2071. Cursor = EMouseCursor::GrabHandClosed;
  2072. break;
  2073. case CT_NOTALLOWED:
  2074. case CT_NODROP:
  2075. Cursor = EMouseCursor::SlashedCircle;
  2076. break;
  2077. default:
  2078. Cursor = EMouseCursor::Default;
  2079. break;
  2080. }
  2081. // Tell Slate to update the cursor now
  2082. FSlateApplication::Get().QueryCursor();
  2083. return false;
  2084. }
  2085. EWebInterfaceTransitionSource _TransitionTypeToSourceEnum(const CefRequest::TransitionType& Type)
  2086. {
  2087. CefRequest::TransitionType TransitionSource = (CefRequest::TransitionType)(Type & TT_SOURCE_MASK);
  2088. switch (TransitionSource)
  2089. {
  2090. case TT_LINK: return EWebInterfaceTransitionSource::Link;
  2091. case TT_EXPLICIT: return EWebInterfaceTransitionSource::Explicit;
  2092. case TT_AUTO_SUBFRAME: return EWebInterfaceTransitionSource::AutoSubframe;
  2093. case TT_FORM_SUBMIT: return EWebInterfaceTransitionSource::FormSubmit;
  2094. case TT_RELOAD: return EWebInterfaceTransitionSource::Reload;
  2095. default: return EWebInterfaceTransitionSource::Unknown;
  2096. }
  2097. return EWebInterfaceTransitionSource::Unknown;
  2098. }
  2099. EWebInterfaceTransitionSourceQualifier _TransitionTypeToSourceQualifierEnum(const CefRequest::TransitionType& Type)
  2100. {
  2101. CefRequest::TransitionType TransitionSourceQualifier = (CefRequest::TransitionType)(Type & TT_QUALIFIER_MASK);
  2102. switch (TransitionSourceQualifier)
  2103. {
  2104. case TT_BLOCKED_FLAG: return EWebInterfaceTransitionSourceQualifier::Blocked;
  2105. case TT_FORWARD_BACK_FLAG: return EWebInterfaceTransitionSourceQualifier::ForwardBack;
  2106. case TT_CHAIN_START_FLAG: return EWebInterfaceTransitionSourceQualifier::ChainStart;
  2107. case TT_CHAIN_END_FLAG: return EWebInterfaceTransitionSourceQualifier::ChainEnd;
  2108. case TT_CLIENT_REDIRECT_FLAG: return EWebInterfaceTransitionSourceQualifier::ClientRedirect;
  2109. case TT_SERVER_REDIRECT_FLAG: return EWebInterfaceTransitionSourceQualifier::ServerRedirect;
  2110. default: return EWebInterfaceTransitionSourceQualifier::Unknown;
  2111. }
  2112. return EWebInterfaceTransitionSourceQualifier::Unknown;
  2113. }
  2114. bool FCEFWebInterfaceBrowserWindow::OnBeforeBrowse( CefRefPtr<CefBrowser> Browser, CefRefPtr<CefFrame> Frame, CefRefPtr<CefRequest> Request, bool user_gesture, bool bIsRedirect )
  2115. {
  2116. if (InternalCefBrowser != nullptr && InternalCefBrowser->IsSame(Browser))
  2117. {
  2118. CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
  2119. if (MainFrame.get() != nullptr)
  2120. {
  2121. if(OnBeforeBrowse().IsBound())
  2122. {
  2123. FString Url = WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str());
  2124. bool bIsMainFrame = Frame->IsMain();
  2125. FWebNavigationRequest RequestDetails;
  2126. RequestDetails.bIsRedirect = bIsRedirect;
  2127. RequestDetails.bIsMainFrame = bIsMainFrame;
  2128. RequestDetails.bIsExplicitTransition = Request->GetTransitionType() == TT_EXPLICIT;
  2129. const CefRequest::TransitionType RequestTransitionType = Request->GetTransitionType();
  2130. RequestDetails.TransitionSource = _TransitionTypeToSourceEnum(RequestTransitionType);
  2131. RequestDetails.TransitionSourceQualifier = _TransitionTypeToSourceQualifierEnum(RequestTransitionType);
  2132. RequestDetails.bIsExplicitTransition = RequestDetails.TransitionSource == EWebInterfaceTransitionSource::Explicit;
  2133. if (bIsMainFrame)
  2134. {
  2135. // We need to defer all future navigations until we can determine if this current navigation is going to be handled or not
  2136. bDeferNavigations = true;
  2137. }
  2138. bool bHandled = OnBeforeBrowse().Execute(Url, RequestDetails);
  2139. if (bIsMainFrame)
  2140. {
  2141. // If the browse request is handled and this is the main frame we must defer LoadUrl() calls until the request is fully aborted in/after NotifyDocumentError
  2142. bDeferNavigations = bHandled && !bIsRedirect;
  2143. if (bDeferNavigations)
  2144. {
  2145. PendingAbortUrl = Url;
  2146. }
  2147. else if (HasPendingNavigation())
  2148. {
  2149. ProcessPendingNavigation();
  2150. }
  2151. }
  2152. return bHandled;
  2153. }
  2154. }
  2155. }
  2156. return false;
  2157. }
  2158. FString _URLRequestStatusToString(const CefResourceRequestHandler::URLRequestStatus& Status)
  2159. {
  2160. const static FString URLRequestStatus_Success(TEXT("SUCCESS"));
  2161. const static FString URLRequestStatus_IoPending(TEXT("IO_PENDING"));
  2162. const static FString URLRequestStatus_Canceled(TEXT("CANCELED"));
  2163. const static FString URLRequestStatus_Failed(TEXT("FAILED"));
  2164. const static FString URLRequestStatus_Unknown(TEXT("UNKNOWN"));
  2165. FString StatusStr;
  2166. switch (Status)
  2167. {
  2168. case CefResourceRequestHandler::URLRequestStatus::UR_SUCCESS:
  2169. StatusStr = URLRequestStatus_Success;
  2170. break;
  2171. case CefResourceRequestHandler::URLRequestStatus::UR_IO_PENDING:
  2172. StatusStr = URLRequestStatus_IoPending;
  2173. break;
  2174. case CefResourceRequestHandler::URLRequestStatus::UR_CANCELED:
  2175. StatusStr = URLRequestStatus_Canceled;
  2176. break;
  2177. case CefResourceRequestHandler::URLRequestStatus::UR_FAILED:
  2178. StatusStr = URLRequestStatus_Failed;
  2179. break;
  2180. case CefResourceRequestHandler::URLRequestStatus::UR_UNKNOWN:
  2181. StatusStr = URLRequestStatus_Unknown;
  2182. break;
  2183. default:
  2184. StatusStr = URLRequestStatus_Unknown;
  2185. break;
  2186. }
  2187. return StatusStr;
  2188. }
  2189. void FCEFWebInterfaceBrowserWindow::HandleOnBeforeResourceLoad(const CefString& URL, CefRequest::ResourceType Type, FRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials)
  2190. {
  2191. BeforeResourceLoadDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(URL.ToWString().c_str()), _ResourceTypeToString(Type), AdditionalHeaders, AllowUserCredentials);
  2192. }
  2193. void FCEFWebInterfaceBrowserWindow::HandleOnResourceLoadComplete(const CefString& URL, CefRequest::ResourceType Type, CefResourceRequestHandler::URLRequestStatus Status, int64 ContentLength)
  2194. {
  2195. ResourceLoadCompleteDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(URL.ToWString().c_str()), _ResourceTypeToString(Type), _URLRequestStatusToString(Status), ContentLength);
  2196. }
  2197. EWebInterfaceBrowserConsoleLogSeverity CefLogSeverityToWebBrowser(cef_log_severity_t Level)
  2198. {
  2199. switch (Level)
  2200. {
  2201. case LOGSEVERITY_VERBOSE:
  2202. return EWebInterfaceBrowserConsoleLogSeverity::Verbose;
  2203. //case LOGSEVERITY_DEBUG: // same as LOGSEVERITY_VERBOSE
  2204. // return Verbose;
  2205. case LOGSEVERITY_INFO:
  2206. return EWebInterfaceBrowserConsoleLogSeverity::Info;
  2207. case LOGSEVERITY_WARNING:
  2208. return EWebInterfaceBrowserConsoleLogSeverity::Warning;
  2209. case LOGSEVERITY_ERROR:
  2210. return EWebInterfaceBrowserConsoleLogSeverity::Error;
  2211. case LOGSEVERITY_FATAL:
  2212. return EWebInterfaceBrowserConsoleLogSeverity::Fatal;
  2213. case LOGSEVERITY_DEFAULT:
  2214. default:
  2215. return EWebInterfaceBrowserConsoleLogSeverity::Default;
  2216. }
  2217. }
  2218. void FCEFWebInterfaceBrowserWindow::HandleOnConsoleMessage(CefRefPtr<CefBrowser> Browser, cef_log_severity_t Level, const CefString& Message, const CefString& Source, int32 Line)
  2219. {
  2220. ConsoleMessageDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(Message.ToWString().c_str()), WCHAR_TO_TCHAR(Source.ToWString().c_str()), Line, CefLogSeverityToWebBrowser(Level));
  2221. }
  2222. TOptional<FString> FCEFWebInterfaceBrowserWindow::GetResourceContent( CefRefPtr< CefFrame > Frame, CefRefPtr< CefRequest > Request)
  2223. {
  2224. if (ContentsToLoad.IsSet())
  2225. {
  2226. FString Contents = ContentsToLoad.GetValue();
  2227. ContentsToLoad.Reset();
  2228. return Contents;
  2229. }
  2230. if (OnLoadUrl().IsBound())
  2231. {
  2232. FString Method = WCHAR_TO_TCHAR(Request->GetMethod().ToWString().c_str());
  2233. FString Url = WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str());
  2234. FString Response;
  2235. if ( OnLoadUrl().Execute(Method, Url, Response))
  2236. {
  2237. return Response;
  2238. }
  2239. }
  2240. return TOptional<FString>();
  2241. }
  2242. int32 FCEFWebInterfaceBrowserWindow::GetCefKeyboardModifiers(const FKeyEvent& KeyEvent)
  2243. {
  2244. int32 Modifiers = GetCefInputModifiers(KeyEvent);
  2245. const FKey Key = KeyEvent.GetKey();
  2246. if (Key == EKeys::LeftAlt ||
  2247. Key == EKeys::LeftCommand ||
  2248. Key == EKeys::LeftControl ||
  2249. Key == EKeys::LeftShift)
  2250. {
  2251. Modifiers |= EVENTFLAG_IS_LEFT;
  2252. }
  2253. if (Key == EKeys::RightAlt ||
  2254. Key == EKeys::RightCommand ||
  2255. Key == EKeys::RightControl ||
  2256. Key == EKeys::RightShift)
  2257. {
  2258. Modifiers |= EVENTFLAG_IS_RIGHT;
  2259. }
  2260. if (Key == EKeys::NumPadZero ||
  2261. Key == EKeys::NumPadOne ||
  2262. Key == EKeys::NumPadTwo ||
  2263. Key == EKeys::NumPadThree ||
  2264. Key == EKeys::NumPadFour ||
  2265. Key == EKeys::NumPadFive ||
  2266. Key == EKeys::NumPadSix ||
  2267. Key == EKeys::NumPadSeven ||
  2268. Key == EKeys::NumPadEight ||
  2269. Key == EKeys::NumPadNine)
  2270. {
  2271. Modifiers |= EVENTFLAG_IS_KEY_PAD;
  2272. }
  2273. return Modifiers;
  2274. }
  2275. int32 FCEFWebInterfaceBrowserWindow::GetCefMouseModifiers(const FPointerEvent& InMouseEvent)
  2276. {
  2277. int32 Modifiers = GetCefInputModifiers(InMouseEvent);
  2278. if (InMouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
  2279. {
  2280. Modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
  2281. }
  2282. if (InMouseEvent.IsMouseButtonDown(EKeys::MiddleMouseButton))
  2283. {
  2284. Modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
  2285. }
  2286. if (InMouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
  2287. {
  2288. Modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
  2289. }
  2290. return Modifiers;
  2291. }
  2292. CefMouseEvent FCEFWebInterfaceBrowserWindow::GetCefMouseEvent(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
  2293. {
  2294. CefMouseEvent Event;
  2295. FGeometry MouseGeometry = MyGeometry;
  2296. if (bUsingAcceleratedPaint)
  2297. {
  2298. // undo the texture flip if we are using accelerated rendering
  2299. MouseGeometry = MyGeometry.MakeChild(FSlateRenderTransform(FScale2D(1, -1)));
  2300. }
  2301. float DPIScale = MouseGeometry.Scale;
  2302. if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
  2303. {
  2304. DPIScale /= ParentWindowPtr->GetNativeWindow()->GetDPIScaleFactor();
  2305. }
  2306. FVector2D LocalPos = MouseGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()) * DPIScale;
  2307. if (bIsPopup)
  2308. {
  2309. LocalPos += PopupPosition;
  2310. }
  2311. Event.x = LocalPos.X;
  2312. Event.y = LocalPos.Y;
  2313. Event.modifiers = GetCefMouseModifiers(MouseEvent);
  2314. return Event;
  2315. }
  2316. int32 FCEFWebInterfaceBrowserWindow::GetCefInputModifiers(const FInputEvent& InputEvent)
  2317. {
  2318. int32 Modifiers = 0;
  2319. if (InputEvent.IsShiftDown())
  2320. {
  2321. Modifiers |= EVENTFLAG_SHIFT_DOWN;
  2322. }
  2323. if (InputEvent.IsControlDown())
  2324. {
  2325. #if PLATFORM_MAC
  2326. // Slate swaps the flags for Command and Control on OSX, so we need to swap them back for CEF
  2327. Modifiers |= EVENTFLAG_COMMAND_DOWN;
  2328. #else
  2329. Modifiers |= EVENTFLAG_CONTROL_DOWN;
  2330. #endif
  2331. }
  2332. if (InputEvent.IsAltDown())
  2333. {
  2334. Modifiers |= EVENTFLAG_ALT_DOWN;
  2335. }
  2336. if (InputEvent.IsCommandDown())
  2337. {
  2338. #if PLATFORM_MAC
  2339. // Slate swaps the flags for Command and Control on OSX, so we need to swap them back for CEF
  2340. Modifiers |= EVENTFLAG_CONTROL_DOWN;
  2341. #else
  2342. Modifiers |= EVENTFLAG_COMMAND_DOWN;
  2343. #endif
  2344. }
  2345. if (InputEvent.AreCapsLocked())
  2346. {
  2347. Modifiers |= EVENTFLAG_CAPS_LOCK_ON;
  2348. }
  2349. return Modifiers;
  2350. }
  2351. bool FCEFWebInterfaceBrowserWindow::CanSupportAcceleratedPaint()
  2352. {
  2353. static bool DisableAcceleratedPaint = FParse::Param(FCommandLine::Get(), TEXT("nocefaccelpaint"));
  2354. if (DisableAcceleratedPaint)
  2355. {
  2356. return false;
  2357. }
  2358. static bool ForceAcceleratedPaint = FParse::Param(FCommandLine::Get(), TEXT("forcecefaccelpaint"));
  2359. if (ForceAcceleratedPaint)
  2360. {
  2361. return true;
  2362. }
  2363. // Use off screen rendering so we can integrate with our windows
  2364. #if PLATFORM_LINUX
  2365. return false;
  2366. #elif PLATFORM_WINDOWS
  2367. #if PLATFORM_64BITS
  2368. static bool Windows10OrAbove = FWindowsPlatformMisc::VerifyWindowsVersion(10, 0); //Win10
  2369. if (Windows10OrAbove == false)
  2370. {
  2371. return false;
  2372. }
  2373. // match the logic in GetStandardStandaloneRenderer() from StandaloneRenderer.cpp to check for the OGL slate renderer
  2374. if (FParse::Param(FCommandLine::Get(), TEXT("opengl")))
  2375. {
  2376. return false;
  2377. }
  2378. return true;
  2379. #else
  2380. return false; // 32-bit windows doesn't have the accelerated rendering patches applied, it can be done if needed
  2381. #endif
  2382. #elif PLATFORM_MAC
  2383. return false; // Needs RHI support for the CreateSharedHandleTexture call
  2384. #else
  2385. return false;
  2386. #endif
  2387. }
  2388. void FCEFWebInterfaceBrowserWindow::UpdateCachedGeometry(const FGeometry& AllottedGeometry)
  2389. {
  2390. #if !PLATFORM_LINUX
  2391. // Forward along the geometry for use by IME
  2392. Ime->UpdateCachedGeometry(AllottedGeometry);
  2393. #endif
  2394. if (RHIRenderHelper)
  2395. {
  2396. RHIRenderHelper->UpdateCachedGeometry(AllottedGeometry);
  2397. }
  2398. }
  2399. void FCEFWebInterfaceBrowserWindow::CheckTickActivity()
  2400. {
  2401. // Early out if we're currently hidden, not initialized or currently loading.
  2402. if (bIsHidden || !IsValid() || IsLoading() || ViewportSize == FIntPoint::ZeroValue)
  2403. {
  2404. return;
  2405. }
  2406. // We clear the bTickedLastFrame flag here and set it on every Slate tick.
  2407. // If it's still clear when we come back it means we're not getting ticks from slate.
  2408. // Note: The BrowserSingleton object will not invoke this method if Slate itself is sleeping.
  2409. // Therefore we can safely assume the widget is hidden in that case.
  2410. if (!bTickedLastFrame)
  2411. {
  2412. SetIsHidden(true);
  2413. }
  2414. else if(bNeedsResize)
  2415. {
  2416. bNeedsResize = false;
  2417. InternalCefBrowser->GetHost()->WasResized();
  2418. }
  2419. bTickedLastFrame = false;
  2420. }
  2421. void FCEFWebInterfaceBrowserWindow::RequestNavigationInternal(FString Url, FString Contents)
  2422. {
  2423. if (!IsValid())
  2424. {
  2425. return;
  2426. }
  2427. CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
  2428. if (MainFrame.get() != nullptr)
  2429. {
  2430. ContentsToLoad = Contents.IsEmpty() ? TOptional<FString>() : Contents;
  2431. PendingLoadUrl = Url;
  2432. if (!bDeferNavigations)
  2433. {
  2434. ProcessPendingNavigation();
  2435. }
  2436. }
  2437. }
  2438. bool FCEFWebInterfaceBrowserWindow::HasPendingNavigation()
  2439. {
  2440. return !PendingLoadUrl.IsEmpty();
  2441. }
  2442. void FCEFWebInterfaceBrowserWindow::ProcessPendingNavigation()
  2443. {
  2444. if (!IsValid() || bDeferNavigations || !HasPendingNavigation())
  2445. {
  2446. return;
  2447. }
  2448. CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
  2449. if (MainFrame.get() != nullptr)
  2450. {
  2451. CefString Url = TCHAR_TO_WCHAR(*PendingLoadUrl);
  2452. PendingLoadUrl.Empty();
  2453. #if PLATFORM_MAC
  2454. if ([NSThread isMainThread])
  2455. {
  2456. MainFrame->LoadURL(Url);
  2457. }
  2458. else
  2459. {
  2460. MainThreadCall(^{
  2461. MainFrame->LoadURL(Url);
  2462. }, NSDefaultRunLoopMode, true);
  2463. }
  2464. #else
  2465. MainFrame->LoadURL(Url);
  2466. #endif
  2467. }
  2468. }
  2469. void FCEFWebInterfaceBrowserWindow::SetIsHidden(bool bValue)
  2470. {
  2471. if( bIsHidden == bValue )
  2472. {
  2473. return;
  2474. }
  2475. bIsHidden = bValue;
  2476. if ( IsValid() )
  2477. {
  2478. CefRefPtr<CefBrowserHost> BrowserHost = InternalCefBrowser->GetHost();
  2479. #if PLATFORM_WINDOWS
  2480. HWND NativeWindowHandle = BrowserHost->GetWindowHandle();
  2481. if (NativeWindowHandle != nullptr)
  2482. {
  2483. // When rendering directly into a subwindow, we must hide the native window when fully obscured
  2484. ::ShowWindow(NativeWindowHandle, bIsHidden ? SW_HIDE : SW_SHOW);
  2485. if (bIsHidden )
  2486. {
  2487. TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
  2488. if (::IsWindowEnabled(NativeWindowHandle) && ParentWindowPtr.IsValid())
  2489. {
  2490. ::SetFocus((HWND)ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle());
  2491. }
  2492. // when hidden also resize the window to 0x0 to further reduce resource usage. This copies the
  2493. // behavior of the CefClient code, see browser_window_std_win.cc in the ::Hide() function. This code
  2494. // is also required for the HTML5 visibility API to work
  2495. SetWindowPos(NativeWindowHandle, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  2496. }
  2497. else
  2498. {
  2499. // restore the window to its right size/position
  2500. HWND Parent = ::GetParent(NativeWindowHandle);
  2501. // Position is in screen coordinates, so we'll need to get the parent window location first.
  2502. RECT ParentRect = { 0, 0, 0, 0 };
  2503. if (Parent)
  2504. {
  2505. ::GetWindowRect(Parent, &ParentRect);
  2506. }
  2507. FIntPoint WindowSizeScaled = (FVector2D(ViewportSize) * ViewportDPIScaleFactor).IntPoint();
  2508. ::SetWindowPos(NativeWindowHandle, 0, ViewportPos.X - ParentRect.left, ViewportPos.Y - ParentRect.top, WindowSizeScaled.X, WindowSizeScaled.Y, 0);
  2509. }
  2510. }
  2511. else
  2512. {
  2513. #elif PLATFORM_MAC
  2514. CefWindowHandle NativeWindowHandle = BrowserHost->GetWindowHandle();
  2515. if (NativeWindowHandle != nullptr)
  2516. {
  2517. NSView *browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
  2518. if(bIsHidden)
  2519. {
  2520. [browserView setHidden:YES];
  2521. }
  2522. else
  2523. {
  2524. [browserView setHidden:NO];
  2525. }
  2526. }
  2527. else
  2528. {
  2529. #endif
  2530. BrowserHost->WasHidden(bIsHidden);
  2531. #if PLATFORM_WINDOWS || PLATFORM_MAC
  2532. }
  2533. #endif
  2534. }
  2535. }
  2536. void FCEFWebInterfaceBrowserWindow::SetIsDisabled(bool bValue)
  2537. {
  2538. if (bIsDisabled == bValue)
  2539. {
  2540. return;
  2541. }
  2542. bIsDisabled = bValue;
  2543. SetIsHidden(bIsDisabled);
  2544. }
  2545. TSharedPtr<SWindow> FCEFWebInterfaceBrowserWindow::GetParentWindow() const
  2546. {
  2547. TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
  2548. return ParentWindowPtr;
  2549. }
  2550. void FCEFWebInterfaceBrowserWindow::SetParentWindow(TSharedPtr<SWindow> Window)
  2551. {
  2552. ParentWindow = Window;
  2553. #if PLATFORM_WINDOWS
  2554. if (IsValid())
  2555. {
  2556. CefRefPtr<CefBrowserHost> BrowserHost = InternalCefBrowser->GetHost();
  2557. HWND NativeWindowHandle = BrowserHost->GetWindowHandle();
  2558. if (NativeWindowHandle != nullptr)
  2559. {
  2560. TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
  2561. void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindowPtr->GetNativeWindow().IsValid()) ? ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle() : nullptr;
  2562. if (ParentWindowHandle != nullptr)
  2563. {
  2564. // When rendering directly to a HWND update its parent windown
  2565. ::SetParent(NativeWindowHandle, (HWND)ParentWindowHandle);
  2566. }
  2567. }
  2568. }
  2569. #endif
  2570. }
  2571. CefRefPtr<CefDictionaryValue> FCEFWebInterfaceBrowserWindow::GetProcessInfo()
  2572. {
  2573. CefRefPtr<CefDictionaryValue> Retval = nullptr;
  2574. if (IsValid())
  2575. {
  2576. Retval = CefDictionaryValue::Create();
  2577. Retval->SetInt("browser", InternalCefBrowser->GetIdentifier());
  2578. Retval->SetDictionary("bindings", Scripting->GetPermanentBindings());
  2579. }
  2580. return Retval;
  2581. }
  2582. bool FCEFWebInterfaceBrowserWindow::OnProcessMessageReceived(CefRefPtr<CefBrowser> Browser, CefRefPtr<CefFrame> frame, CefProcessId SourceProcess, CefRefPtr<CefProcessMessage> Message)
  2583. {
  2584. bool bHandled = Scripting->OnProcessMessageReceived(Browser, SourceProcess, Message);
  2585. if (!bHandled)
  2586. {
  2587. #if PLATFORM_MAC
  2588. if (!bInDirectHwndMode) // IME is handled by the CEF control in direct render mode
  2589. {
  2590. bHandled = Ime->OnProcessMessageReceived(Browser, SourceProcess, Message);
  2591. }
  2592. #elif PLATFORM_WINDOWS
  2593. bHandled = Ime->OnProcessMessageReceived(Browser, SourceProcess, Message);
  2594. #endif
  2595. }
  2596. return bHandled;
  2597. }
  2598. void FCEFWebInterfaceBrowserWindow::BindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
  2599. {
  2600. Scripting->BindUObject(Name, Object, bIsPermanent);
  2601. }
  2602. void FCEFWebInterfaceBrowserWindow::UnbindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
  2603. {
  2604. Scripting->UnbindUObject(Name, Object, bIsPermanent);
  2605. }
  2606. void FCEFWebInterfaceBrowserWindow::BindInputMethodSystem(ITextInputMethodSystem* TextInputMethodSystem)
  2607. {
  2608. #if !PLATFORM_LINUX
  2609. Ime->BindInputMethodSystem(TextInputMethodSystem);
  2610. #endif
  2611. }
  2612. void FCEFWebInterfaceBrowserWindow::UnbindInputMethodSystem()
  2613. {
  2614. #if !PLATFORM_LINUX
  2615. Ime->UnbindInputMethodSystem();
  2616. #endif
  2617. }
  2618. void FCEFWebInterfaceBrowserWindow::OnBrowserClosing()
  2619. {
  2620. bIsClosing = true;
  2621. }
  2622. void FCEFWebInterfaceBrowserWindow::OnBrowserClosed()
  2623. {
  2624. if(OnCloseWindow().IsBound())
  2625. {
  2626. OnCloseWindow().Execute(TWeakPtr<IWebInterfaceBrowserWindow>(SharedThis(this)));
  2627. }
  2628. Scripting->UnbindCefBrowser();
  2629. #if !PLATFORM_LINUX
  2630. Ime->UnbindCefBrowser();
  2631. #endif
  2632. InternalCefBrowser = nullptr;
  2633. }
  2634. void FCEFWebInterfaceBrowserWindow::SetPopupMenuPosition(CefRect CefPopupSize)
  2635. {
  2636. // We only store the position, as the size will be provided ib the OnPaint call.
  2637. PopupPosition = FIntPoint(CefPopupSize.x, CefPopupSize.y);
  2638. }
  2639. void FCEFWebInterfaceBrowserWindow:: ShowPopupMenu(bool bShow)
  2640. {
  2641. if (bShow)
  2642. {
  2643. bShowPopupRequested = true; // We have to delay showing the popup until we get the first OnPaint on it.
  2644. }
  2645. else
  2646. {
  2647. bPopupHasFocus = false;
  2648. bShowPopupRequested = false;
  2649. OnDismissPopup().Broadcast();
  2650. }
  2651. }
  2652. void FCEFWebInterfaceBrowserWindow::OnImeCompositionRangeChanged(
  2653. CefRefPtr<CefBrowser> Browser,
  2654. const CefRange& SelectionRange,
  2655. const CefRenderHandler::RectList& CharacterBounds)
  2656. {
  2657. if (InternalCefBrowser != nullptr && InternalCefBrowser->IsSame(Browser))
  2658. {
  2659. #if !PLATFORM_LINUX
  2660. Ime->CEFCompositionRangeChanged(SelectionRange, CharacterBounds);
  2661. #endif
  2662. }
  2663. }
  2664. void FCEFWebInterfaceBrowserWindow::UpdateDragRegions(const TArray<FWebInterfaceBrowserDragRegion>& Regions)
  2665. {
  2666. DragRegions = Regions;
  2667. }
  2668. bool FCEFWebInterfaceBrowserWindow::IsInDragRegion(const FIntPoint& Point)
  2669. {
  2670. // Here we traverse the array of drag regions backwards because we assume the drag regions are z ordered such that
  2671. // the end of the list contains the drag regions of the top most elements of the web page. We can stop checking
  2672. // once we hit a region that contains our point.
  2673. for (int32 Idx = DragRegions.Num() - 1; Idx >= 0; --Idx)
  2674. {
  2675. if (DragRegions[Idx].Rect.Contains(Point))
  2676. {
  2677. return DragRegions[Idx].bDraggable;
  2678. }
  2679. }
  2680. return false;
  2681. }
  2682. #endif