12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951 |
- // Engine/Source/Runtime/WebBrowser/Private/CEF/CEFWebBrowserWindow.cpp
- #include "CEF/CEFWebInterfaceBrowserWindow.h"
- #include "IWebInterfaceBrowserDialog.h"
- #include "UObject/Stack.h"
- #include "Framework/Application/SlateApplication.h"
- #include "Textures/SlateUpdatableTexture.h"
- #include "HAL/PlatformApplicationMisc.h"
- #include "Misc/CommandLine.h"
- #include "Misc/ConfigCacheIni.h"
- #include "WebInterfaceBrowserLog.h"
- #if WITH_CEF3
- #include "CEFInterfaceBrowserPopupFeatures.h"
- #include "CEFWebInterfaceBrowserDialog.h"
- #include "CEFInterfaceBrowserClosureTask.h"
- #include "CEFInterfaceJSScripting.h"
- #include "CEFInterfaceImeHandler.h"
- #include "CEFWebInterfaceBrowserWindowRHIHelper.h"
- #include "CEF3Utils.h"
- #include "Async/Async.h"
- #if PLATFORM_MAC
- // Needed for character code definitions
- #include <Carbon/Carbon.h>
- #include <AppKit/NSEvent.h>
- #endif
- #if PLATFORM_WINDOWS
- #include "Windows/WindowsCursor.h"
- typedef FWindowsCursor FPlatformCursor;
- #elif PLATFORM_MAC
- #include "Mac/MacCursor.h"
- #include "Mac/CocoaThread.h"
- #include "Mac/MacApplication.h"
- #include "Mac/MacCursor.h"
- typedef FMacCursor FPlatformCursor;
- #else
- #endif
- #if PLATFORM_LINUX
- // From ui/events/keycodes/keyboard_codes_posix.h.
- enum KeyboardCode {
- VKEY_BACK = 0x08,
- VKEY_TAB = 0x09,
- VKEY_BACKTAB = 0x0A,
- VKEY_CLEAR = 0x0C,
- VKEY_RETURN = 0x0D,
- VKEY_SHIFT = 0x10,
- VKEY_CONTROL = 0x11,
- VKEY_MENU = 0x12,
- VKEY_PAUSE = 0x13,
- VKEY_CAPITAL = 0x14,
- VKEY_KANA = 0x15,
- VKEY_HANGUL = 0x15,
- VKEY_JUNJA = 0x17,
- VKEY_FINAL = 0x18,
- VKEY_HANJA = 0x19,
- VKEY_KANJI = 0x19,
- VKEY_ESCAPE = 0x1B,
- VKEY_CONVERT = 0x1C,
- VKEY_NONCONVERT = 0x1D,
- VKEY_ACCEPT = 0x1E,
- VKEY_MODECHANGE = 0x1F,
- VKEY_SPACE = 0x20,
- VKEY_PRIOR = 0x21,
- VKEY_NEXT = 0x22,
- VKEY_END = 0x23,
- VKEY_HOME = 0x24,
- VKEY_LEFT = 0x25,
- VKEY_UP = 0x26,
- VKEY_RIGHT = 0x27,
- VKEY_DOWN = 0x28,
- VKEY_SELECT = 0x29,
- VKEY_PRINT = 0x2A,
- VKEY_EXECUTE = 0x2B,
- VKEY_SNAPSHOT = 0x2C,
- VKEY_INSERT = 0x2D,
- VKEY_DELETE = 0x2E,
- VKEY_HELP = 0x2F,
- VKEY_0 = 0x30,
- VKEY_1 = 0x31,
- VKEY_2 = 0x32,
- VKEY_3 = 0x33,
- VKEY_4 = 0x34,
- VKEY_5 = 0x35,
- VKEY_6 = 0x36,
- VKEY_7 = 0x37,
- VKEY_8 = 0x38,
- VKEY_9 = 0x39,
- VKEY_A = 0x41,
- VKEY_B = 0x42,
- VKEY_C = 0x43,
- VKEY_D = 0x44,
- VKEY_E = 0x45,
- VKEY_F = 0x46,
- VKEY_G = 0x47,
- VKEY_H = 0x48,
- VKEY_I = 0x49,
- VKEY_J = 0x4A,
- VKEY_K = 0x4B,
- VKEY_L = 0x4C,
- VKEY_M = 0x4D,
- VKEY_N = 0x4E,
- VKEY_O = 0x4F,
- VKEY_P = 0x50,
- VKEY_Q = 0x51,
- VKEY_R = 0x52,
- VKEY_S = 0x53,
- VKEY_T = 0x54,
- VKEY_U = 0x55,
- VKEY_V = 0x56,
- VKEY_W = 0x57,
- VKEY_X = 0x58,
- VKEY_Y = 0x59,
- VKEY_Z = 0x5A,
- VKEY_LWIN = 0x5B,
- VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
- VKEY_RWIN = 0x5C,
- VKEY_APPS = 0x5D,
- VKEY_SLEEP = 0x5F,
- VKEY_NUMPAD0 = 0x60,
- VKEY_NUMPAD1 = 0x61,
- VKEY_NUMPAD2 = 0x62,
- VKEY_NUMPAD3 = 0x63,
- VKEY_NUMPAD4 = 0x64,
- VKEY_NUMPAD5 = 0x65,
- VKEY_NUMPAD6 = 0x66,
- VKEY_NUMPAD7 = 0x67,
- VKEY_NUMPAD8 = 0x68,
- VKEY_NUMPAD9 = 0x69,
- VKEY_MULTIPLY = 0x6A,
- VKEY_ADD = 0x6B,
- VKEY_SEPARATOR = 0x6C,
- VKEY_SUBTRACT = 0x6D,
- VKEY_DECIMAL = 0x6E,
- VKEY_DIVIDE = 0x6F,
- VKEY_F1 = 0x70,
- VKEY_F2 = 0x71,
- VKEY_F3 = 0x72,
- VKEY_F4 = 0x73,
- VKEY_F5 = 0x74,
- VKEY_F6 = 0x75,
- VKEY_F7 = 0x76,
- VKEY_F8 = 0x77,
- VKEY_F9 = 0x78,
- VKEY_F10 = 0x79,
- VKEY_F11 = 0x7A,
- VKEY_F12 = 0x7B,
- VKEY_F13 = 0x7C,
- VKEY_F14 = 0x7D,
- VKEY_F15 = 0x7E,
- VKEY_F16 = 0x7F,
- VKEY_F17 = 0x80,
- VKEY_F18 = 0x81,
- VKEY_F19 = 0x82,
- VKEY_F20 = 0x83,
- VKEY_F21 = 0x84,
- VKEY_F22 = 0x85,
- VKEY_F23 = 0x86,
- VKEY_F24 = 0x87,
- VKEY_NUMLOCK = 0x90,
- VKEY_SCROLL = 0x91,
- VKEY_LSHIFT = 0xA0,
- VKEY_RSHIFT = 0xA1,
- VKEY_LCONTROL = 0xA2,
- VKEY_RCONTROL = 0xA3,
- VKEY_LMENU = 0xA4,
- VKEY_RMENU = 0xA5,
- VKEY_BROWSER_BACK = 0xA6,
- VKEY_BROWSER_FORWARD = 0xA7,
- VKEY_BROWSER_REFRESH = 0xA8,
- VKEY_BROWSER_STOP = 0xA9,
- VKEY_BROWSER_SEARCH = 0xAA,
- VKEY_BROWSER_FAVORITES = 0xAB,
- VKEY_BROWSER_HOME = 0xAC,
- VKEY_VOLUME_MUTE = 0xAD,
- VKEY_VOLUME_DOWN = 0xAE,
- VKEY_VOLUME_UP = 0xAF,
- VKEY_MEDIA_NEXT_TRACK = 0xB0,
- VKEY_MEDIA_PREV_TRACK = 0xB1,
- VKEY_MEDIA_STOP = 0xB2,
- VKEY_MEDIA_PLAY_PAUSE = 0xB3,
- VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
- VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
- VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
- VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
- VKEY_OEM_1 = 0xBA,
- VKEY_OEM_PLUS = 0xBB,
- VKEY_OEM_COMMA = 0xBC,
- VKEY_OEM_MINUS = 0xBD,
- VKEY_OEM_PERIOD = 0xBE,
- VKEY_OEM_2 = 0xBF,
- VKEY_OEM_3 = 0xC0,
- VKEY_OEM_4 = 0xDB,
- VKEY_OEM_5 = 0xDC,
- VKEY_OEM_6 = 0xDD,
- VKEY_OEM_7 = 0xDE,
- VKEY_OEM_8 = 0xDF,
- VKEY_OEM_102 = 0xE2,
- VKEY_OEM_103 = 0xE3, // GTV KEYCODE_MEDIA_REWIND
- VKEY_OEM_104 = 0xE4, // GTV KEYCODE_MEDIA_FAST_FORWARD
- VKEY_PROCESSKEY = 0xE5,
- VKEY_PACKET = 0xE7,
- VKEY_DBE_SBCSCHAR = 0xF3,
- VKEY_DBE_DBCSCHAR = 0xF4,
- VKEY_ATTN = 0xF6,
- VKEY_CRSEL = 0xF7,
- VKEY_EXSEL = 0xF8,
- VKEY_EREOF = 0xF9,
- VKEY_PLAY = 0xFA,
- VKEY_ZOOM = 0xFB,
- VKEY_NONAME = 0xFC,
- VKEY_PA1 = 0xFD,
- VKEY_OEM_CLEAR = 0xFE,
- VKEY_UNKNOWN = 0,
- // POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
- // and 0xE8 are unassigned.
- VKEY_WLAN = 0x97,
- VKEY_POWER = 0x98,
- VKEY_BRIGHTNESS_DOWN = 0xD8,
- VKEY_BRIGHTNESS_UP = 0xD9,
- VKEY_KBD_BRIGHTNESS_DOWN = 0xDA,
- VKEY_KBD_BRIGHTNESS_UP = 0xE8,
- // Windows does not have a specific key code for AltGr. We use the unused 0xE1
- // (VK_OEM_AX) code to represent AltGr, matching the behaviour of Firefox on
- // Linux.
- VKEY_ALTGR = 0xE1,
- // Windows does not have a specific key code for Compose. We use the unused
- // 0xE6 (VK_ICO_CLEAR) code to represent Compose.
- VKEY_COMPOSE = 0xE6,
- };
- #endif
- #if PLATFORM_MAC
- // enable buffered video so we don't DoS the OpenGL API with texture uploads causing a downstream crash on macOS
- #define USE_BUFFERED_VIDEO 1
- #else
- #define USE_BUFFERED_VIDEO 0
- #endif
- namespace {
- // Private helper class to post a callback to GetSource.
- class FWebInterfaceBrowserClosureVisitor
- : public CefStringVisitor
- {
- public:
- FWebInterfaceBrowserClosureVisitor(TFunction<void (const FString&)> InClosure)
- : Closure(InClosure)
- { }
- virtual void Visit(const CefString& String) override
- {
- Closure(FString(WCHAR_TO_TCHAR(String.ToWString().c_str())));
- }
- private:
- TFunction<void (const FString&)> Closure;
- IMPLEMENT_REFCOUNTING(FWebInterfaceBrowserClosureVisitor);
- };
- }
- // Private helper class to smooth out video buffering, using a ringbuffer
- // (cef sometimes submits multiple frames per engine frame)
- class FBrowserBufferedVideo
- {
- public:
- FBrowserBufferedVideo(uint32 NumFrames)
- : FrameWriteIndex(0)
- , FrameReadIndex(0)
- , FrameCountThisEngineTick(0)
- , FrameCount(0)
- , FrameNumberOfLastRender(-1)
- {
- Frames.SetNum(NumFrames);
- }
- ~FBrowserBufferedVideo()
- {
- }
- /**
- * Submits a frame to the video buffer
- * @return true if this is the first frame submitted this engine tick, or false otherwise
- */
- bool SubmitFrame(
- int32 InWidth,
- int32 InHeight,
- const void* Buffer,
- FIntRect Dirty)
- {
- check(IsInGameThread());
- check(Buffer != nullptr);
- const uint32 NumBytesPerPixel = 4;
- FFrame& Frame = Frames[FrameWriteIndex];
- // If the write buffer catches up to the read buffer, we need to release the read buffer and increment its index
- if (FrameWriteIndex == FrameReadIndex && FrameCount > 0)
- {
- Frame.ReleaseTextureData();
- FrameReadIndex = (FrameReadIndex + 1) % Frames.Num();
- }
- check(Frame.SlateTextureData == nullptr);
- Frame.SlateTextureData = new FSlateTextureData((uint8*)Buffer, InWidth, InHeight, NumBytesPerPixel);
- FrameWriteIndex = (FrameWriteIndex + 1) % Frames.Num();
- FrameCount = FMath::Min(Frames.Num(), FrameCount + 1);
- FrameCountThisEngineTick++;
- return FrameCountThisEngineTick == 1;
- }
- /**
- * Called once per frame to get the next frame's texturedata
- * @return The texture data. Can be nullptr if no frame is available
- */
- FSlateTextureData* GetNextFrameTextureData()
- {
- // Grab the next available frame if available. Ensure we don't grab more than one frame per engine tick
- check(IsInGameThread());
- FSlateTextureData* SlateTextureData = nullptr;
- if ( FrameCount > 0 )
- {
- // Grab the first frame we haven't submitted yet
- FFrame& Frame = Frames[FrameReadIndex];
- SlateTextureData = Frame.SlateTextureData;
-
- // Set this to NULL because the renderthread is taking ownership
- Frame.SlateTextureData = nullptr;
- FrameReadIndex = (FrameReadIndex + 1) % Frames.Num();
- FrameCount--;
- }
- FrameCountThisEngineTick = 0;
- return SlateTextureData;
- }
- private:
- struct FFrame
- {
- FFrame()
- : SlateTextureData(nullptr)
- {}
-
- ~FFrame()
- {
- ReleaseTextureData();
- }
- void ReleaseTextureData()
- {
- if (SlateTextureData)
- {
- delete SlateTextureData;
- }
- SlateTextureData = nullptr;
- }
- FSlateTextureData* SlateTextureData;
- };
- TArray<FFrame> Frames;
- // Read/write position in the ringbuffer
- int32 FrameWriteIndex;
- int32 FrameReadIndex;
- int32 FrameCountThisEngineTick;
- int32 FrameCount;
- int32 FrameNumberOfLastRender;
- };
- 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)
- : DocumentState(EWebInterfaceBrowserDocumentState::NoDocument)
- , InternalCefBrowser(InBrowser)
- , WebBrowserHandler(InHandler)
- , CurrentUrl(InUrl)
- , ViewportSize(FIntPoint::ZeroValue)
- , ViewportDPIScaleFactor(1.0f)
- , bIsClosing(false)
- , bIsInitialized(false)
- , ContentsToLoad(InContentsToLoad)
- , bShowErrorMessage(bInShowErrorMessage)
- , bThumbMouseButtonNavigation(bInThumbMouseButtonNavigation)
- , bUseTransparency(bInUseTransparency)
- , bUsingAcceleratedPaint(bInUsingAcceleratedPaint)
- , bUseNativeCursors(bInUseNativeCursors)
- , Cursor(EMouseCursor::Default)
- , bIsDisabled(false)
- , bIsHidden(false)
- , bTickedLastFrame(true)
- , bNeedsResize(false)
- , bDraggingWindow(false)
- , PreviousKeyDownEvent()
- , PreviousKeyUpEvent()
- , PreviousCharacterEvent()
- , bIgnoreKeyDownEvent(false)
- , bIgnoreKeyUpEvent(false)
- , bIgnoreCharacterEvent(false)
- , bMainHasFocus(false)
- , bPopupHasFocus(false)
- , bSupportsMouseWheel(true)
- , bRecoverFromRenderProcessCrash(false)
- , ErrorCode(0)
- , bDeferNavigations(false)
- #if PLATFORM_MAC
- , LastPaintedSharedHandle(nullptr)
- #endif
- , Scripting(new FCEFInterfaceJSScripting(InBrowser, bInJSBindingToLoweringEnabled))
- #if !PLATFORM_LINUX
- , Ime(new FCEFInterfaceImeHandler(InBrowser))
- #endif
- , RHIRenderHelper(nullptr)
- #if PLATFORM_WINDOWS || PLATFORM_MAC
- , bInDirectHwndMode(false)
- #endif
- {
- check(InBrowser.get() != nullptr);
- check(!bUsingAcceleratedPaint || CanSupportAcceleratedPaint()); // make sure if accelerated paint is selected we can support it
- UpdatableTextures[0] = nullptr;
- UpdatableTextures[1] = nullptr;
- if (!CreateInitialTextures())
- {
- ReleaseTextures();
- }
- #if PLATFORM_WINDOWS || PLATFORM_MAC
- if (InternalCefBrowser->GetHost()->GetWindowHandle() != nullptr)
- {
- bInDirectHwndMode = true;
- }
- #endif
- #if USE_BUFFERED_VIDEO
- BufferedVideo = TUniquePtr<FBrowserBufferedVideo>(new FBrowserBufferedVideo(4));
- #endif
- }
- void FCEFWebInterfaceBrowserWindow::ReleaseTextures()
- {
- for (int I = 0; I < 2; ++I)
- {
- if (UpdatableTextures[I] != nullptr)
- {
- FSlateUpdatableTexture* TextureToRelease = UpdatableTextures[I];
- AsyncTask(ENamedThreads::GameThread, [TextureToRelease]()
- {
- if (FSlateApplication::IsInitialized())
- {
- if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
- {
- Renderer->ReleaseUpdatableTexture(TextureToRelease);
- }
- }
- });
- UpdatableTextures[I] = nullptr;
- }
- }
- }
- bool FCEFWebInterfaceBrowserWindow::CreateInitialTextures()
- {
- if (FSlateApplication::IsInitialized())
- {
- if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
- {
- if (Renderer->HasLostDevice())
- {
- return false;
- }
- if (bUsingAcceleratedPaint)
- {
- if (FCEFWebInterfaceBrowserWindowRHIHelper::BUseRHIRenderer() && RHIRenderHelper == nullptr)
- {
- RHIRenderHelper = new FCEFWebInterfaceBrowserWindowRHIHelper;
- }
-
- // the accelerated paint path attaches to the texture at render time as we don't know its details until then
- UpdatableTextures[0] = nullptr;
- UpdatableTextures[1] = nullptr;
- return true;
- }
- // Create a transparent dummy texture for our buffers which will prevent slate from applying an
- // undesirable quad if it happens to ask for this buffer before we get a chance to paint to it.
- TArray<uint8> RawData;
- RawData.AddZeroed(4);
- UpdatableTextures[0] = Renderer->CreateUpdatableTexture(1, 1);
- if (Renderer->HasLostDevice())
- {
- return false;
- }
- UpdatableTextures[0]->UpdateTextureThreadSafeRaw(1, 1, RawData.GetData());
- if (Renderer->HasLostDevice())
- {
- return false;
- }
- UpdatableTextures[1] = Renderer->CreateUpdatableTexture(1, 1);
- if (Renderer->HasLostDevice())
- {
- return false;
- }
- UpdatableTextures[1]->UpdateTextureThreadSafeRaw(1, 1, RawData.GetData());
- if (Renderer->HasLostDevice())
- {
- return false;
- }
- return true;
- }
- }
- return false;
- }
- FCEFWebInterfaceBrowserWindow::~FCEFWebInterfaceBrowserWindow()
- {
- WebBrowserHandler->OnCreateWindow().Unbind();
- WebBrowserHandler->OnBeforePopup().Unbind();
- WebBrowserHandler->OnBeforeResourceLoad().Unbind();
- WebBrowserHandler->OnResourceLoadComplete().Unbind();
- WebBrowserHandler->OnConsoleMessage().Unbind();
- if (IsValid())
- {
- UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Closing browser during destruction, this may cause a later crash."), *CurrentUrl);
- CloseBrowser(true, false);
- }
- ReleaseTextures();
- BufferedVideo.Reset();
- if (RHIRenderHelper != nullptr)
- {
- delete RHIRenderHelper;
- }
- UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Deleting browser for Url=%s."), *CurrentUrl);
- }
- void FCEFWebInterfaceBrowserWindow::LoadURL(FString NewURL)
- {
- RequestNavigationInternal(NewURL, FString());
- }
- void FCEFWebInterfaceBrowserWindow::LoadString(FString Contents, FString DummyURL)
- {
- RequestNavigationInternal(DummyURL, Contents);
- }
- TSharedRef<SViewport> FCEFWebInterfaceBrowserWindow::CreateWidget()
- {
- TSharedRef<SViewport> BrowserWidgetRef =
- SNew(SViewport)
- .EnableGammaCorrection(false)
- .EnableBlending(bUseTransparency)
- .IgnoreTextureAlpha(!bUseTransparency)
- .RenderTransform(this, &FCEFWebInterfaceBrowserWindow::GetWebBrowserRenderTransform);
- #if !PLATFORM_LINUX
- Ime->CacheBrowserSlateInfo(BrowserWidgetRef);
- #endif
- return BrowserWidgetRef;
- }
- TOptional<FSlateRenderTransform> FCEFWebInterfaceBrowserWindow::GetWebBrowserRenderTransform() const
- {
- TOptional<FSlateRenderTransform> LocalRenderTransform = FSlateRenderTransform();
- if (bUsingAcceleratedPaint)
- {
- if (RHIRenderHelper != nullptr)
- {
- LocalRenderTransform = RHIRenderHelper->GetWebBrowserRenderTransform();
- }
- else
- {
- LocalRenderTransform = FSlateRenderTransform(Concatenate(FScale2D(1, -1), FVector2D(0, ViewportSize.Y)));
- }
- }
- return LocalRenderTransform;
- }
- bool FCEFWebInterfaceBrowserWindow::BlockInputInDirectHwndMode() const
- {
- #if PLATFORM_WINDOWS
- return bInDirectHwndMode;
- #elif PLATFORM_MAC
- return bInDirectHwndMode;
- #endif
- return false;
- }
- void FCEFWebInterfaceBrowserWindow::SetViewportSize(FIntPoint WindowSize, FIntPoint WindowPos)
- {
- // SetViewportSize is called from the browser viewport tick method, which means that since we are receiving ticks, we can mark the browser as visible.
- if (! bIsDisabled)
- {
- SetIsHidden(false);
- }
- bTickedLastFrame=true;
- float WindowDPIScaleFactor = 1.0f;
- if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
- {
- WindowDPIScaleFactor = ParentWindowPtr->GetNativeWindow()->GetDPIScaleFactor();
- }
- ViewportPos = WindowPos;
- // Ignore sizes that can't be seen as it forces CEF to re-render whole image
- if ((WindowSize.X > 0 && WindowSize.Y > 0 && ViewportSize != WindowSize) || WindowDPIScaleFactor != ViewportDPIScaleFactor)
- {
- bool bFirstSize = ViewportSize == FIntPoint::ZeroValue;
- ViewportSize = WindowSize;
- ViewportDPIScaleFactor = WindowDPIScaleFactor;
- if (IsValid())
- {
- #if PLATFORM_WINDOWS
- HWND NativeHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
- if (NativeHandle)
- {
- HWND Parent = ::GetParent(NativeHandle);
- // Position is in screen coordinates, so we'll need to get the parent window location first.
- RECT ParentRect = { 0, 0, 0, 0 };
- if (Parent)
- {
- ::GetWindowRect(Parent, &ParentRect);
- }
- FIntPoint WindowSizeScaled = (FVector2D(WindowSize) * WindowDPIScaleFactor).IntPoint();
- ::SetWindowPos(NativeHandle, 0, WindowPos.X - ParentRect.left, WindowPos.Y - ParentRect.top, WindowSizeScaled.X, WindowSizeScaled.Y, 0);
- }
- #elif PLATFORM_MAC
- CefWindowHandle NativeWindowHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
- if (NativeWindowHandle)
- {
- NSView* browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
- if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
- {
- NSWindow* parentWindow = (NSWindow*)ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle();
- const FVector2D CocoaPosition = FMacApplication::ConvertSlatePositionToCocoa(WindowPos.X, WindowPos.Y);
- NSRect parentFrame = [parentWindow frame];
- 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));
- Rect = [parentWindow frameRectForContentRect : Rect];
- [browserView setFrame : Rect] ;
- }
- }
- #endif
- if (bFirstSize)
- {
- InternalCefBrowser->GetHost()->WasResized();
- }
- else
- {
- bNeedsResize = true;
- }
- }
- }
- }
- FSlateShaderResource* FCEFWebInterfaceBrowserWindow::GetTexture(bool bIsPopup)
- {
- if (UpdatableTextures[bIsPopup?1:0] != nullptr)
- {
- return UpdatableTextures[bIsPopup?1:0]->GetSlateResource();
- }
- return nullptr;
- }
- bool FCEFWebInterfaceBrowserWindow::IsValid() const
- {
- return InternalCefBrowser.get() != nullptr;
- }
- bool FCEFWebInterfaceBrowserWindow::IsInitialized() const
- {
- return bIsInitialized;
- }
- bool FCEFWebInterfaceBrowserWindow::IsClosing() const
- {
- return bIsClosing;
- }
- EWebInterfaceBrowserDocumentState FCEFWebInterfaceBrowserWindow::GetDocumentLoadingState() const
- {
- return DocumentState;
- }
- FString FCEFWebInterfaceBrowserWindow::GetTitle() const
- {
- return Title;
- }
- FString FCEFWebInterfaceBrowserWindow::GetUrl() const
- {
- if (InternalCefBrowser != nullptr)
- {
- CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
- if (MainFrame != nullptr)
- {
- return CurrentUrl;
- }
- }
- return FString();
- }
- void FCEFWebInterfaceBrowserWindow::GetSource(TFunction<void (const FString&)> Callback) const
- {
- if (IsValid())
- {
- InternalCefBrowser->GetMainFrame()->GetSource(new FWebInterfaceBrowserClosureVisitor(Callback));
- }
- else
- {
- Callback(FString());
- }
- }
- void FCEFWebInterfaceBrowserWindow::PopulateCefKeyEvent(const FKeyEvent& InKeyEvent, CefKeyEvent& OutKeyEvent)
- {
- #if PLATFORM_MAC
- OutKeyEvent.native_key_code = InKeyEvent.GetKeyCode();
- FKey Key = InKeyEvent.GetKey();
- if (Key == EKeys::BackSpace)
- {
- OutKeyEvent.unmodified_character = kBackspaceCharCode;
- }
- else if (Key == EKeys::Tab)
- {
- OutKeyEvent.unmodified_character = kTabCharCode;
- }
- else if (Key == EKeys::Enter)
- {
- OutKeyEvent.unmodified_character = kReturnCharCode;
- }
- else if (Key == EKeys::Pause)
- {
- OutKeyEvent.unmodified_character = NSPauseFunctionKey;
- }
- else if (Key == EKeys::Escape)
- {
- OutKeyEvent.unmodified_character = kEscapeCharCode;
- }
- else if (Key == EKeys::PageUp)
- {
- OutKeyEvent.unmodified_character = NSPageUpFunctionKey;
- }
- else if (Key == EKeys::PageDown)
- {
- OutKeyEvent.unmodified_character = NSPageDownFunctionKey;
- }
- else if (Key == EKeys::End)
- {
- OutKeyEvent.unmodified_character = NSEndFunctionKey;
- }
- else if (Key == EKeys::Home)
- {
- OutKeyEvent.unmodified_character = NSHomeFunctionKey;
- }
- else if (Key == EKeys::Left)
- {
- OutKeyEvent.unmodified_character = NSLeftArrowFunctionKey;
- }
- else if (Key == EKeys::Up)
- {
- OutKeyEvent.unmodified_character = NSUpArrowFunctionKey;
- }
- else if (Key == EKeys::Right)
- {
- OutKeyEvent.unmodified_character = NSRightArrowFunctionKey;
- }
- else if (Key == EKeys::Down)
- {
- OutKeyEvent.unmodified_character = NSDownArrowFunctionKey;
- }
- else if (Key == EKeys::Insert)
- {
- OutKeyEvent.unmodified_character = NSInsertFunctionKey;
- }
- else if (Key == EKeys::Delete)
- {
- OutKeyEvent.unmodified_character = kDeleteCharCode;
- }
- else if (Key == EKeys::F1)
- {
- OutKeyEvent.unmodified_character = NSF1FunctionKey;
- }
- else if (Key == EKeys::F2)
- {
- OutKeyEvent.unmodified_character = NSF2FunctionKey;
- }
- else if (Key == EKeys::F3)
- {
- OutKeyEvent.unmodified_character = NSF3FunctionKey;
- }
- else if (Key == EKeys::F4)
- {
- OutKeyEvent.unmodified_character = NSF4FunctionKey;
- }
- else if (Key == EKeys::F5)
- {
- OutKeyEvent.unmodified_character = NSF5FunctionKey;
- }
- else if (Key == EKeys::F6)
- {
- OutKeyEvent.unmodified_character = NSF6FunctionKey;
- }
- else if (Key == EKeys::F7)
- {
- OutKeyEvent.unmodified_character = NSF7FunctionKey;
- }
- else if (Key == EKeys::F8)
- {
- OutKeyEvent.unmodified_character = NSF8FunctionKey;
- }
- else if (Key == EKeys::F9)
- {
- OutKeyEvent.unmodified_character = NSF9FunctionKey;
- }
- else if (Key == EKeys::F10)
- {
- OutKeyEvent.unmodified_character = NSF10FunctionKey;
- }
- else if (Key == EKeys::F11)
- {
- OutKeyEvent.unmodified_character = NSF11FunctionKey;
- }
- else if (Key == EKeys::F12)
- {
- OutKeyEvent.unmodified_character = NSF12FunctionKey;
- }
- else if (Key == EKeys::CapsLock)
- {
- OutKeyEvent.unmodified_character = 0;
- OutKeyEvent.native_key_code = kVK_CapsLock;
- }
- else if (Key.IsModifierKey())
- {
- // Setting both unmodified_character and character to 0 tells CEF that it needs to generate a NSFlagsChanged event instead of NSKeyDown/Up
- OutKeyEvent.unmodified_character = 0;
- // CEF expects modifier key codes as one of the Carbon kVK_* key codes.
- if (Key == EKeys::LeftCommand)
- {
- OutKeyEvent.native_key_code = kVK_Command;
- }
- else if (Key == EKeys::LeftShift)
- {
- OutKeyEvent.native_key_code = kVK_Shift;
- }
- else if (Key == EKeys::LeftAlt)
- {
- OutKeyEvent.native_key_code = kVK_Option;
- }
- else if (Key == EKeys::LeftControl)
- {
- OutKeyEvent.native_key_code = kVK_Control;
- }
- else if (Key == EKeys::RightCommand)
- {
- // 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
- OutKeyEvent.native_key_code = kVK_Command-1;
- }
- else if (Key == EKeys::RightShift)
- {
- OutKeyEvent.native_key_code = kVK_RightShift;
- }
- else if (Key == EKeys::RightAlt)
- {
- OutKeyEvent.native_key_code = kVK_RightOption;
- }
- else if (Key == EKeys::RightControl)
- {
- OutKeyEvent.native_key_code = kVK_RightControl;
- }
- }
- else
- {
- OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter();
- }
- OutKeyEvent.character = OutKeyEvent.unmodified_character;
- #elif PLATFORM_LINUX
- OutKeyEvent.native_key_code = InKeyEvent.GetKeyCode();
- FKey Key = InKeyEvent.GetKey();
- // helper macro so we can fill in all the A-Z, 0-9 keys
- #define LETTER_KEY_MACRO(val, vkey) else if(Key == EKeys::val) \
- { \
- OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter(); \
- OutKeyEvent.windows_key_code = vkey; \
- } \
- if (Key == EKeys::BackSpace)
- {
- OutKeyEvent.windows_key_code = VKEY_BACK;
- }
- else if (Key == EKeys::Tab)
- {
- OutKeyEvent.windows_key_code = VKEY_TAB;
- }
- else if (Key == EKeys::Enter)
- {
- OutKeyEvent.windows_key_code = VKEY_RETURN;
- }
- else if (Key == EKeys::Pause)
- {
- OutKeyEvent.windows_key_code = VKEY_PAUSE;
- }
- else if (Key == EKeys::Escape)
- {
- OutKeyEvent.windows_key_code = VKEY_ESCAPE;
- }
- else if (Key == EKeys::PageUp)
- {
- OutKeyEvent.windows_key_code = VKEY_PRIOR;
- }
- else if (Key == EKeys::PageDown)
- {
- OutKeyEvent.windows_key_code = VKEY_NEXT;
- }
- else if (Key == EKeys::End)
- {
- OutKeyEvent.windows_key_code = VKEY_END;
- }
- else if (Key == EKeys::Home)
- {
- OutKeyEvent.windows_key_code = VKEY_HOME;
- }
- else if (Key == EKeys::Left)
- {
- OutKeyEvent.windows_key_code = VKEY_LEFT;
- }
- else if (Key == EKeys::Up)
- {
- OutKeyEvent.windows_key_code = VKEY_UP;
- }
- else if (Key == EKeys::Right)
- {
- OutKeyEvent.windows_key_code = VKEY_RIGHT;
- }
- else if (Key == EKeys::Down)
- {
- OutKeyEvent.windows_key_code = VKEY_DOWN;
- }
- else if (Key == EKeys::Insert)
- {
- OutKeyEvent.windows_key_code = VKEY_INSERT;
- }
- else if (Key == EKeys::Delete)
- {
- OutKeyEvent.windows_key_code = VKEY_DELETE;
- }
- else if (Key == EKeys::F1)
- {
- OutKeyEvent.windows_key_code = VKEY_F1;
- }
- else if (Key == EKeys::F2)
- {
- OutKeyEvent.windows_key_code = VKEY_F2;
- }
- else if (Key == EKeys::F3)
- {
- OutKeyEvent.windows_key_code = VKEY_F3;
- }
- else if (Key == EKeys::F4)
- {
- OutKeyEvent.windows_key_code = VKEY_F4;
- }
- else if (Key == EKeys::F5)
- {
- OutKeyEvent.windows_key_code = VKEY_F5;
- }
- else if (Key == EKeys::F6)
- {
- OutKeyEvent.windows_key_code = VKEY_F6;
- }
- else if (Key == EKeys::F7)
- {
- OutKeyEvent.windows_key_code = VKEY_F7;
- }
- else if (Key == EKeys::F8)
- {
- OutKeyEvent.windows_key_code = VKEY_F8;
- }
- else if (Key == EKeys::F9)
- {
- OutKeyEvent.windows_key_code = VKEY_F9;
- }
- else if (Key == EKeys::F10)
- {
- OutKeyEvent.windows_key_code = VKEY_F10;
- }
- else if (Key == EKeys::F11)
- {
- OutKeyEvent.windows_key_code = VKEY_F11;
- }
- else if (Key == EKeys::F12)
- {
- OutKeyEvent.windows_key_code = VKEY_F12;
- }
- else if (Key == EKeys::CapsLock)
- {
- OutKeyEvent.windows_key_code = VKEY_CAPITAL;
- }
- else if (Key == EKeys::LeftCommand)
- {
- OutKeyEvent.windows_key_code = VKEY_MENU;
- }
- else if (Key == EKeys::LeftShift)
- {
- OutKeyEvent.windows_key_code = VKEY_SHIFT;
- }
- else if (Key == EKeys::LeftAlt)
- {
- OutKeyEvent.windows_key_code = VKEY_MENU;
- }
- else if (Key == EKeys::LeftControl)
- {
- OutKeyEvent.windows_key_code = VKEY_CONTROL;
- }
- else if (Key == EKeys::RightCommand)
- {
- OutKeyEvent.windows_key_code = VKEY_MENU;
- }
- else if (Key == EKeys::RightShift)
- {
- OutKeyEvent.windows_key_code = VKEY_SHIFT;
- }
- else if (Key == EKeys::RightAlt)
- {
- OutKeyEvent.windows_key_code = VKEY_MENU;
- }
- else if (Key == EKeys::RightControl)
- {
- OutKeyEvent.windows_key_code = VKEY_CONTROL;
- }
- else if(Key == EKeys::NumPadOne)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD1;
- }
- else if(Key == EKeys::NumPadTwo)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD2;
- }
- else if(Key == EKeys::NumPadThree)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD3;
- }
- else if(Key == EKeys::NumPadFour)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD4;
- }
- else if(Key == EKeys::NumPadFive)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD5;
- }
- else if(Key == EKeys::NumPadSix)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD6;
- }
- else if(Key == EKeys::NumPadSeven)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD7;
- }
- else if(Key == EKeys::NumPadEight)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD8;
- }
- else if(Key == EKeys::NumPadNine)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD9;
- }
- else if(Key == EKeys::NumPadZero)
- {
- OutKeyEvent.windows_key_code = VKEY_NUMPAD0;
- }
- LETTER_KEY_MACRO( A, VKEY_A)
- LETTER_KEY_MACRO( B, VKEY_B)
- LETTER_KEY_MACRO( C, VKEY_C)
- LETTER_KEY_MACRO( D, VKEY_D)
- LETTER_KEY_MACRO( E, VKEY_E)
- LETTER_KEY_MACRO( F, VKEY_F)
- LETTER_KEY_MACRO( G, VKEY_G)
- LETTER_KEY_MACRO( H, VKEY_H)
- LETTER_KEY_MACRO( I, VKEY_I)
- LETTER_KEY_MACRO( J, VKEY_J)
- LETTER_KEY_MACRO( K, VKEY_K)
- LETTER_KEY_MACRO( L, VKEY_L)
- LETTER_KEY_MACRO( M, VKEY_M)
- LETTER_KEY_MACRO( N, VKEY_N)
- LETTER_KEY_MACRO( O, VKEY_O)
- LETTER_KEY_MACRO( P, VKEY_P)
- LETTER_KEY_MACRO( Q, VKEY_Q)
- LETTER_KEY_MACRO( R, VKEY_R)
- LETTER_KEY_MACRO( S, VKEY_S)
- LETTER_KEY_MACRO( T, VKEY_T)
- LETTER_KEY_MACRO( U, VKEY_U)
- LETTER_KEY_MACRO( V, VKEY_V)
- LETTER_KEY_MACRO( W, VKEY_W)
- LETTER_KEY_MACRO( X, VKEY_X)
- LETTER_KEY_MACRO( Y, VKEY_Y)
- LETTER_KEY_MACRO( Z, VKEY_Z)
- LETTER_KEY_MACRO( Zero, VKEY_0)
- LETTER_KEY_MACRO( One, VKEY_1)
- LETTER_KEY_MACRO( Two, VKEY_2)
- LETTER_KEY_MACRO( Three, VKEY_3)
- LETTER_KEY_MACRO( Four, VKEY_4)
- LETTER_KEY_MACRO( Five, VKEY_5)
- LETTER_KEY_MACRO( Six, VKEY_6)
- LETTER_KEY_MACRO( Seven, VKEY_7)
- LETTER_KEY_MACRO( Eight, VKEY_8)
- LETTER_KEY_MACRO( Nine, VKEY_9)
- else
- {
- OutKeyEvent.unmodified_character = InKeyEvent.GetCharacter();
- OutKeyEvent.windows_key_code = VKEY_UNKNOWN;
- }
- #else
- OutKeyEvent.windows_key_code = InKeyEvent.GetKeyCode();
- #endif
- OutKeyEvent.modifiers = GetCefKeyboardModifiers(InKeyEvent);
- //UE_LOG(LogWebInterfaceBrowser, Log, TEXT("Modifiers: %i %i %i") , OutKeyEvent.unmodified_character, OutKeyEvent.windows_key_code, OutKeyEvent.modifiers);
- }
- #if PLATFORM_MAC
- bool _FilterSystemKeyChord(const FKeyEvent& InKeyEvent)
- {
- if(InKeyEvent.IsControlDown())
- {
- // Special case for Mac - make sure Cmd+~ is always passed back to the OS
- if (InKeyEvent.GetKey() == EKeys::Tilde)
- {
- return true;
- }
- // Special case for Mac - make sure Cmd+H is always ignored by CEF
- if (InKeyEvent.GetKey() == EKeys::H )
- {
- return true;
- }
- }
- return false;
- }
- #endif
- bool FCEFWebInterfaceBrowserWindow::OnKeyDown(const FKeyEvent& InKeyEvent)
- {
- if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreKeyDownEvent)
- {
- #if PLATFORM_MAC
- if(_FilterSystemKeyChord(InKeyEvent))
- return false;
- #endif
- PreviousKeyDownEvent = InKeyEvent;
- CefKeyEvent KeyEvent;
- PopulateCefKeyEvent(InKeyEvent, KeyEvent);
- KeyEvent.type = KEYEVENT_RAWKEYDOWN;
- InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
- return true;
- }
- return false;
- }
- bool FCEFWebInterfaceBrowserWindow::OnKeyUp(const FKeyEvent& InKeyEvent)
- {
- if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreKeyUpEvent)
- {
- #if PLATFORM_MAC
- if(_FilterSystemKeyChord(InKeyEvent))
- return false;
- #endif
- PreviousKeyUpEvent = InKeyEvent;
- CefKeyEvent KeyEvent;
- PopulateCefKeyEvent(InKeyEvent, KeyEvent);
- KeyEvent.type = KEYEVENT_KEYUP;
- InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
- return true;
- }
- return false;
- }
- bool FCEFWebInterfaceBrowserWindow::OnKeyChar(const FCharacterEvent& InCharacterEvent)
- {
- if (IsValid() && !BlockInputInDirectHwndMode() && !bIgnoreCharacterEvent)
- {
- PreviousCharacterEvent = InCharacterEvent;
- CefKeyEvent KeyEvent;
- #if PLATFORM_MAC || PLATFORM_LINUX
- KeyEvent.character = InCharacterEvent.GetCharacter();
- KeyEvent.windows_key_code = InCharacterEvent.GetCharacter();
- #else
- KeyEvent.windows_key_code = InCharacterEvent.GetCharacter();
- #endif
- KeyEvent.type = KEYEVENT_CHAR;
- KeyEvent.modifiers = GetCefInputModifiers(InCharacterEvent);
- #if PLATFORM_WINDOWS
- if (InCharacterEvent.IsAltDown() && InCharacterEvent.IsControlDown())
- {
- // For german and other keyboards with an AltGR state, windows sets alt and left control down
- // See OsrWindowWin::OnKeyEvent in
- //https://bitbucket.org/chromiumembedded/cef/raw/c4baba880e0b28ce82845275b328a12b2407e2f0/tests/cefclient/browser/osr_window_win.cc
- // from which the concept behind this check was taken
- HKL CurrentKBLayout = ::GetKeyboardLayout(0);
- SHORT ScanResult = ::VkKeyScanExW(InCharacterEvent.GetCharacter(), CurrentKBLayout);
- if (((ScanResult >> 8) & 0xFF) == (2 | 4))
- {
- // ctrl-alt pressed from this single character event so convert to AltGR
- KeyEvent.modifiers &= ~(EVENTFLAG_CONTROL_DOWN | EVENTFLAG_ALT_DOWN);
- KeyEvent.modifiers |= EVENTFLAG_ALTGR_DOWN;
- }
- }
- #endif
- InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
- return true;
- }
- return false;
- }
- FModifierKeysState FCEFWebInterfaceBrowserWindow::SlateModifiersFromCefModifiers(const CefKeyEvent& CefEvent)
- {
- return FModifierKeysState((CefEvent.modifiers & EVENTFLAG_SHIFT_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_SHIFT_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_CONTROL_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_CONTROL_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_ALT_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_ALT_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_COMMAND_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_COMMAND_DOWN) != 0,
- (CefEvent.modifiers & EVENTFLAG_CAPS_LOCK_ON) != 0);
- }
- /* This is an ugly hack to inject unhandled key events back into Slate.
- During processing of the initial keyboard event, we don't know whether it is handled by the Web browser or not.
- Not until after CEF calls OnKeyEvent in our CefKeyboardHandler implementation, which is after our own keyboard event handler
- has returned.
- 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
- the widget hierarchy this time around. */
- bool FCEFWebInterfaceBrowserWindow::OnUnhandledKeyEvent(const CefKeyEvent& CefEvent)
- {
- bool bWasHandled = false;
- if (IsValid())
- {
- CefWindowHandle NativeHandle = InternalCefBrowser->GetHost()->GetWindowHandle();
- switch (CefEvent.type)
- {
- case KEYEVENT_RAWKEYDOWN:
- case KEYEVENT_KEYDOWN:
- if (PreviousKeyDownEvent.IsSet())
- {
- bWasHandled = OnUnhandledKeyDown().IsBound() && OnUnhandledKeyDown().Execute(PreviousKeyDownEvent.GetValue());
- if (!bWasHandled)
- {
- // If the keydown handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
- bIgnoreKeyDownEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyDownEvent(PreviousKeyDownEvent.GetValue());
- bIgnoreKeyDownEvent = false;
- }
- PreviousKeyDownEvent.Reset();
- }
- else if (NativeHandle)
- {
- FKey const Key = FInputKeyManager::Get().GetKeyFromCodes(CefEvent.windows_key_code, 0);
- if (Key.IsValid())
- {
- FKeyEvent KeyEvent(Key, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false, 0, CefEvent.windows_key_code);
- bIgnoreKeyDownEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyDownEvent(KeyEvent);
- bIgnoreKeyDownEvent = false;
- }
- }
- break;
- case KEYEVENT_KEYUP:
- if (PreviousKeyUpEvent.IsSet())
- {
- bWasHandled = OnUnhandledKeyUp().IsBound() && OnUnhandledKeyUp().Execute(PreviousKeyUpEvent.GetValue());
- if (!bWasHandled)
- {
- // If the keyup handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
- bIgnoreKeyUpEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyUpEvent(PreviousKeyUpEvent.GetValue());
- bIgnoreKeyUpEvent = false;
- }
- PreviousKeyUpEvent.Reset();
- }
- else if (NativeHandle)
- {
- FKey const Key = FInputKeyManager::Get().GetKeyFromCodes(CefEvent.windows_key_code, 0);
- FKeyEvent KeyEvent(Key, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false, 0, CefEvent.windows_key_code);
- bIgnoreKeyUpEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyUpEvent(KeyEvent);
- bIgnoreKeyUpEvent = false;
- }
- break;
- case KEYEVENT_CHAR:
- if (PreviousCharacterEvent.IsSet())
- {
- bWasHandled = OnUnhandledKeyChar().IsBound() && OnUnhandledKeyChar().Execute(PreviousCharacterEvent.GetValue());
- if (!bWasHandled)
- {
- // If the keychar handler is not bound or if the handler returns false, indicating the key is unhandled, we bubble it up.
- bIgnoreCharacterEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyCharEvent(PreviousCharacterEvent.GetValue());
- bIgnoreCharacterEvent = false;
- }
- PreviousCharacterEvent.Reset();
- }
- else if (NativeHandle)
- {
- FCharacterEvent CharacterEvent(CefEvent.character, SlateModifiersFromCefModifiers(CefEvent), FSlateApplication::Get().GetUserIndexForKeyboard(), false);
- bIgnoreCharacterEvent = true;
- bWasHandled = FSlateApplication::Get().ProcessKeyCharEvent(CharacterEvent);
- bIgnoreCharacterEvent = false;
- }
- break;
- default:
- break;
- }
- }
- return bWasHandled;
- }
- bool FCEFWebInterfaceBrowserWindow::OnJSDialog(CefJSDialogHandler::JSDialogType DialogType, const CefString& MessageText, const CefString& DefaultPromptText, CefRefPtr<CefJSDialogCallback> Callback, bool& OutSuppressMessage)
- {
- bool Retval = false;
- if ( OnShowDialog().IsBound() )
- {
- TSharedPtr<IWebInterfaceBrowserDialog> Dialog(new FCEFWebInterfaceBrowserDialog(DialogType, MessageText, DefaultPromptText, Callback));
- EWebInterfaceBrowserDialogEventResponse EventResponse = OnShowDialog().Execute(TWeakPtr<IWebInterfaceBrowserDialog>(Dialog));
- switch (EventResponse)
- {
- case EWebInterfaceBrowserDialogEventResponse::Handled:
- Retval = true;
- break;
- case EWebInterfaceBrowserDialogEventResponse::Continue:
- if (DialogType == JSDIALOGTYPE_ALERT)
- {
- // Alert dialogs don't return a value, so treat Continue the same way as Ingore
- OutSuppressMessage = true;
- Retval = false;
- }
- else
- {
- Callback->Continue(true, DefaultPromptText);
- Retval = true;
- }
- break;
- case EWebInterfaceBrowserDialogEventResponse::Ignore:
- OutSuppressMessage = true;
- Retval = false;
- break;
- case EWebInterfaceBrowserDialogEventResponse::Unhandled:
- default:
- Retval = false;
- break;
- }
- }
- return Retval;
- }
- bool FCEFWebInterfaceBrowserWindow::OnBeforeUnloadDialog(const CefString& MessageText, bool IsReload, CefRefPtr<CefJSDialogCallback> Callback)
- {
- bool Retval = false;
- if ( OnShowDialog().IsBound() )
- {
- TSharedPtr<IWebInterfaceBrowserDialog> Dialog(new FCEFWebInterfaceBrowserDialog(MessageText, IsReload, Callback));
- EWebInterfaceBrowserDialogEventResponse EventResponse = OnShowDialog().Execute(TWeakPtr<IWebInterfaceBrowserDialog>(Dialog));
- switch (EventResponse)
- {
- case EWebInterfaceBrowserDialogEventResponse::Handled:
- Retval = true;
- break;
- case EWebInterfaceBrowserDialogEventResponse::Continue:
- Callback->Continue(true, CefString());
- Retval = true;
- break;
- case EWebInterfaceBrowserDialogEventResponse::Ignore:
- Callback->Continue(false, CefString());
- Retval = true;
- break;
- case EWebInterfaceBrowserDialogEventResponse::Unhandled:
- default:
- Retval = false;
- break;
- }
- }
- return Retval;
- }
- void FCEFWebInterfaceBrowserWindow::OnResetDialogState()
- {
- OnDismissAllDialogs().ExecuteIfBound();
- }
- void FCEFWebInterfaceBrowserWindow::OnRenderProcessTerminated(CefRequestHandler::TerminationStatus Status)
- {
- if(bRecoverFromRenderProcessCrash)
- {
- bRecoverFromRenderProcessCrash = false;
- NotifyDocumentError((int)ERR_FAILED); // Only attempt a single recovery at a time
- }
- bRecoverFromRenderProcessCrash = true;
- Reload();
- }
- FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if (IsValid() && !BlockInputInDirectHwndMode())
- {
- FKey Button = MouseEvent.GetEffectingButton();
- // CEF only supports left, right, and middle mouse buttons
- bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
- if(bIsCefSupportedButton)
- {
- CefBrowserHost::MouseButtonType Type =
- (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
- Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
- // If the click happened inside a drag region we enable window dragging which will start firing OnDragWindow events on mouse move
- if (Type == MBT_LEFT && IsInDragRegion(FIntPoint(Event.x, Event.y)))
- {
- bDraggingWindow = true;
- }
- InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false,1);
- Reply = FReply::Handled();
- }
- }
- return Reply;
- }
- FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if (IsValid() && !BlockInputInDirectHwndMode())
- {
- FKey Button = MouseEvent.GetEffectingButton();
- // CEF only supports left, right, and middle mouse buttons
- bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
- if(bIsCefSupportedButton)
- {
- CefBrowserHost::MouseButtonType Type =
- (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
- Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
- if (Type == MBT_LEFT)
- {
- bDraggingWindow = false;
- }
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
- InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, true, 1);
- Reply = FReply::Handled();
- }
- else if(Button == EKeys::ThumbMouseButton && bThumbMouseButtonNavigation)
- {
- if(CanGoBack())
- {
- GoBack();
- Reply = FReply::Handled();
- }
- }
- else if(Button == EKeys::ThumbMouseButton2 && bThumbMouseButtonNavigation)
- {
- if(CanGoForward())
- {
- GoForward();
- Reply = FReply::Handled();
- }
- }
- }
- return Reply;
- }
- FReply FCEFWebInterfaceBrowserWindow::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if (IsValid() && !BlockInputInDirectHwndMode())
- {
- FKey Button = MouseEvent.GetEffectingButton();
- // CEF only supports left, right, and middle mouse buttons
- bool bIsCefSupportedButton = (Button == EKeys::LeftMouseButton || Button == EKeys::RightMouseButton || Button == EKeys::MiddleMouseButton);
- if(bIsCefSupportedButton)
- {
- CefBrowserHost::MouseButtonType Type =
- (Button == EKeys::LeftMouseButton ? MBT_LEFT : (
- Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
- InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false, 2);
- Reply = FReply::Handled();
- }
- }
- return Reply;
- }
- FReply FCEFWebInterfaceBrowserWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if (IsValid() && !BlockInputInDirectHwndMode())
- {
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
- bool bEventConsumedByDragCallback = false;
- FIntRect test;
- if (bDraggingWindow && OnDragWindow().IsBound())
- {
- if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
- {
- bEventConsumedByDragCallback = OnDragWindow().Execute(MouseEvent);
- }
- else
- {
- bDraggingWindow = false;
- }
- }
- if (!bEventConsumedByDragCallback)
- {
- InternalCefBrowser->GetHost()->SendMouseMoveEvent(Event, false);
- }
-
- Reply = FReply::Handled();
- }
- return Reply;
- }
- void FCEFWebInterfaceBrowserWindow::OnMouseLeave(const FPointerEvent& MouseEvent)
- {
- // Ensure we clear any tooltips if the mouse leaves the window.
- SetToolTip(CefString());
- // 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
- CefMouseEvent DummyEvent;
- if (IsValid() && !BlockInputInDirectHwndMode())
- {
- InternalCefBrowser->GetHost()->SendMouseMoveEvent(DummyEvent, true);
- }
- }
- void FCEFWebInterfaceBrowserWindow::SetSupportsMouseWheel(bool bValue)
- {
- bSupportsMouseWheel = bValue;
- }
- bool FCEFWebInterfaceBrowserWindow::GetSupportsMouseWheel() const
- {
- return bSupportsMouseWheel;
- }
- FReply FCEFWebInterfaceBrowserWindow::OnTouchGesture(const FGeometry& MyGeometry, const FPointerEvent& GestureEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if(IsValid() && bSupportsMouseWheel && !BlockInputInDirectHwndMode())
- {
- const EGestureEvent GestureType = GestureEvent.GetGestureType();
- const FVector2D& GestureDelta = GestureEvent.GetGestureDelta();
- if ( GestureType == EGestureEvent::Scroll )
- {
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, GestureEvent, bIsPopup);
- InternalCefBrowser->GetHost()->SendMouseWheelEvent(Event, GestureDelta.X, GestureDelta.Y);
- Reply = FReply::Handled();
- }
- }
-
- return Reply;
- }
- FReply FCEFWebInterfaceBrowserWindow::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- FReply Reply = FReply::Unhandled();
- if(IsValid() && bSupportsMouseWheel && !BlockInputInDirectHwndMode())
- {
- #if PLATFORM_WINDOWS
- // The original delta is reduced so this should bring it back to what CEF expects
- // see WindowsApplication.cpp , case WM_MOUSEWHEEL:
- const float SpinFactor = 120.0f;
- #else
- // other OS's seem to want us to scale by "line height" here, so pick a magic number
- // 50 matches a single mouse wheel tick in movement as compared to Chrome
- const float SpinFactor = 50.0f;
- #endif
- const float TrueDelta = MouseEvent.GetWheelDelta() * SpinFactor;
- if (fabs(TrueDelta) > 0.001f)
- {
- CefMouseEvent Event = GetCefMouseEvent(MyGeometry, MouseEvent, bIsPopup);
- InternalCefBrowser->GetHost()->SendMouseWheelEvent(Event,
- MouseEvent.IsShiftDown() ? TrueDelta : 0,
- !MouseEvent.IsShiftDown() ? TrueDelta : 0);
- }
- Reply = FReply::Handled();
- }
- return Reply;
- }
- void FCEFWebInterfaceBrowserWindow::OnFocus(bool SetFocus, bool bIsPopup)
- {
- if (bIsPopup)
- {
- bPopupHasFocus = SetFocus;
- }
- else
- {
- bMainHasFocus = SetFocus;
- }
- #if !PLATFORM_LINUX
- Ime->SetFocus(!bPopupHasFocus && bMainHasFocus);
- #endif
- // Only notify focus if there is no popup menu with focus, as SendFocusEvent will dismiss any popup menus.
- if (IsValid() && !bPopupHasFocus)
- {
- InternalCefBrowser->GetHost()->SendFocusEvent(bMainHasFocus);
- }
- }
- void FCEFWebInterfaceBrowserWindow::OnCaptureLost()
- {
- if (IsValid())
- {
- InternalCefBrowser->GetHost()->SendCaptureLostEvent();
- }
- }
- bool FCEFWebInterfaceBrowserWindow::CanGoBack() const
- {
- if (IsValid())
- {
- return InternalCefBrowser->CanGoBack();
- }
- return false;
- }
- void FCEFWebInterfaceBrowserWindow::GoBack()
- {
- if (IsValid())
- {
- InternalCefBrowser->GoBack();
- }
- }
- bool FCEFWebInterfaceBrowserWindow::CanGoForward() const
- {
- if (IsValid())
- {
- return InternalCefBrowser->CanGoForward();
- }
- return false;
- }
- void FCEFWebInterfaceBrowserWindow::GoForward()
- {
- if (IsValid())
- {
- InternalCefBrowser->GoForward();
- }
- }
- bool FCEFWebInterfaceBrowserWindow::IsLoading() const
- {
- if (IsValid())
- {
- return InternalCefBrowser->IsLoading();
- }
- return false;
- }
- void FCEFWebInterfaceBrowserWindow::Reload()
- {
- if (IsValid())
- {
- InternalCefBrowser->Reload();
- }
- }
- void FCEFWebInterfaceBrowserWindow::StopLoad()
- {
- if (IsValid())
- {
- InternalCefBrowser->StopLoad();
- }
- }
- void FCEFWebInterfaceBrowserWindow::ExecuteJavascript(const FString& Script)
- {
- if (IsValid())
- {
- CefRefPtr<CefFrame> frame = InternalCefBrowser->GetMainFrame();
- frame->ExecuteJavaScript(TCHAR_TO_UTF8(*Script), frame->GetURL(), 0);
- }
- }
- void FCEFWebInterfaceBrowserWindow::CloseBrowser(bool bForce, bool bBlockTillClosed)
- {
- if (IsValid())
- {
- CefRefPtr<CefBrowserHost> Host = InternalCefBrowser->GetHost();
- #if PLATFORM_MAC
- CefWindowHandle NativeWindowHandle = Host->GetWindowHandle();
- if (NativeWindowHandle != nullptr)
- {
- NSView *browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
- if (browserView != nil)
- [browserView removeFromSuperview];
- }
- #endif
- // In case this is called from inside a CEF event handler, use CEF's task mechanism to
- // postpone the actual closing of the window until it is safe.
- CefPostTask(TID_UI, new FCEFInterfaceBrowserClosureTask(nullptr, [=]()
- {
- // if blocking till closed for the close here
- Host->CloseBrowser(bForce||bBlockTillClosed);
- }));
- if (bBlockTillClosed)
- {
- SetIsHidden(true); // hide the window as we close it
- float CloseWaitTimeout = 1.0f;
- // BUGBUG Alfred - I think 1 second should be enough wait, remove these config settings
- // if we don't end up having to tune timeouts in the field.
- GConfig->GetFloat(TEXT("Browser"), TEXT("CloseWaitTimeout"), CloseWaitTimeout, GEngineIni);
- if (IsEngineExitRequested())
- {
- // wait longer if the app is shutting down
- GConfig->GetFloat(TEXT("Browser"), TEXT("CloseWaitTimeoutAppExit"), CloseWaitTimeout, GEngineIni);
- }
- const double StartWaitAppTime = FPlatformTime::Seconds();
- while (InternalCefBrowser != nullptr)
- {
- if (FPlatformTime::Seconds() - StartWaitAppTime > CloseWaitTimeout )
- {
- UE_LOG(LogWebInterfaceBrowser, Error, TEXT("CloseBrowser - took more than %0.2f second to close. Abandoning wait..."), CloseWaitTimeout);
- break; // don't spin forever
- }
- FPlatformProcess::Sleep(0.01);
- // CEF needs the windows message pump run to be able to finish closing a browser, so run it manually here
- FSlateApplication::Get().PumpMessages();
- CefDoMessageLoopWork();
- }
- }
- }
- }
- CefRefPtr<CefBrowser> FCEFWebInterfaceBrowserWindow::GetCefBrowser()
- {
- return InternalCefBrowser;
- }
- void FCEFWebInterfaceBrowserWindow::SetTitle(const CefString& InTitle)
- {
- Title = WCHAR_TO_TCHAR(InTitle.ToWString().c_str());
- TitleChangedEvent.Broadcast(Title);
- }
- void FCEFWebInterfaceBrowserWindow::SetUrl(const CefString& Url)
- {
- CurrentUrl = WCHAR_TO_TCHAR(Url.ToWString().c_str());
- OnUrlChanged().Broadcast(CurrentUrl);
- }
- void FCEFWebInterfaceBrowserWindow::SetToolTip(const CefString& CefToolTip)
- {
- FString NewToolTipText = WCHAR_TO_TCHAR(CefToolTip.ToWString().c_str());
- if (ToolTipText != NewToolTipText)
- {
- ToolTipText = NewToolTipText;
- OnToolTip().Broadcast(ToolTipText);
- }
- }
- void FCEFWebInterfaceBrowserWindow::GetViewRect(CefRect& Rect)
- {
- if (ViewportSize == FIntPoint::ZeroValue)
- {
- Rect.width = 1; // CEF requires a minimum of a 1x1 window to correctly run
- Rect.height = 1;
- }
- else
- {
- // CEF requires a minimum of a 1px in each dimension to correctly run
- Rect.width = FMath::Max( ViewportSize.X, 1);
- Rect.height = FMath::Max( ViewportSize.Y, 1);
- }
- }
- int FCEFWebInterfaceBrowserWindow::GetLoadError()
- {
- return ErrorCode;
- }
- void FCEFWebInterfaceBrowserWindow::NotifyDocumentError(
- CefLoadHandler::ErrorCode InErrorCode,
- const CefString& ErrorText,
- const CefString& FailedUrl)
- {
- FString Url = WCHAR_TO_TCHAR(FailedUrl.ToWString().c_str());
- if (InErrorCode == ERR_ABORTED)
- {
- // 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.
- if (!PendingAbortUrl.IsEmpty() && PendingAbortUrl == Url)
- {
- PendingAbortUrl.Empty();
- bDeferNavigations = false;
- if (HasPendingNavigation())
- {
- ProcessPendingNavigation();
- }
- }
- return;
- }
-
- if (IsShowingErrorMessages())
- {
- // 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.
- FFormatNamedArguments Args;
- {
- Args.Add(TEXT("FailedUrl"), FText::FromString(Url));
- Args.Add(TEXT("ErrorText"), FText::FromString(WCHAR_TO_TCHAR(ErrorText.ToWString().c_str())));
- Args.Add(TEXT("ErrorCode"), FText::AsNumber((int)InErrorCode));
- }
- FText ErrorMsg = FText::Format(NSLOCTEXT("WebBrowserHandler", "WebBrowserLoadError", "Failed to load URL {FailedUrl} with error {ErrorText} ({ErrorCode})."), Args);
- FString ErrorHTML = TEXT("<html><body bgcolor=\"white\"><h2>") + ErrorMsg.ToString() + TEXT("</h2></body></html>");
- LoadString(ErrorHTML, Url);
- }
-
- NotifyDocumentError((int)InErrorCode);
- }
- void FCEFWebInterfaceBrowserWindow::NotifyDocumentError(int InErrorCode)
- {
- ErrorCode = InErrorCode;
- DocumentState = EWebInterfaceBrowserDocumentState::Error;
- DocumentStateChangedEvent.Broadcast(DocumentState);
- }
- void FCEFWebInterfaceBrowserWindow::NotifyDocumentLoadingStateChange(bool IsLoading)
- {
- if (! IsLoading)
- {
- bIsInitialized = true;
- if (bRecoverFromRenderProcessCrash)
- {
- bRecoverFromRenderProcessCrash = false;
- // Toggle hidden/visible state to get OnPaint calls from CEF.
- SetIsHidden(true);
- SetIsHidden(false);
- }
- // Compatibility with Android script bindings: dispatch a custom ue:ready event when the document is fully loaded
- ExecuteJavascript(TEXT("document.dispatchEvent(new CustomEvent('ue:ready', {details: window.ue}));"));
- }
- // Ignore a load completed notification if there was an error.
- // For load started, reset any errors from previous page load.
- if (IsLoading || DocumentState != EWebInterfaceBrowserDocumentState::Error)
- {
- ErrorCode = 0;
- DocumentState = IsLoading
- ? EWebInterfaceBrowserDocumentState::Loading
- : EWebInterfaceBrowserDocumentState::Completed;
- DocumentStateChangedEvent.Broadcast(DocumentState);
- }
- }
- FSlateRenderer* const FCEFWebInterfaceBrowserWindow::GetRenderer()
- {
- if (FSlateApplication::IsInitialized())
- {
- if (FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer())
- {
- if (!Renderer->HasLostDevice())
- {
- return Renderer;
- }
- }
- }
- ReleaseTextures();
- return nullptr;
- }
- void FCEFWebInterfaceBrowserWindow::HandleRenderingError()
- {
- // GetRenderer handles errors already
- GetRenderer();
- }
- void FCEFWebInterfaceBrowserWindow::OnPaint(CefRenderHandler::PaintElementType Type, const CefRenderHandler::RectList& DirtyRects, const void* Buffer, int Width, int Height)
- {
- bool bNeedsRedraw = false;
- if (bUsingAcceleratedPaint)
- {
- UE_LOG(LogWebInterfaceBrowser, Error, TEXT("Accelerated CEF rendering selected but OnPaint called. Disabling accelerated rendering for this browser window."));
- bUsingAcceleratedPaint = false;
- if (UpdatableTextures[Type] != nullptr)
- {
- if (FSlateRenderer* const Renderer = GetRenderer())
- {
- Renderer->ReleaseUpdatableTexture(UpdatableTextures[Type]);
- HandleRenderingError();
- UpdatableTextures[Type] = nullptr;
- }
- }
- }
- if (UpdatableTextures[Type] == nullptr)
- {
- if (FSlateRenderer* const Renderer = GetRenderer())
- {
- UpdatableTextures[Type] = Renderer->CreateUpdatableTexture(Width, Height);
- HandleRenderingError();
- }
- }
- if (UpdatableTextures[Type] != nullptr)
- {
- // 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
- // In case that should change in the future, we'll simply update the entire area if DirtyRects is not a single element.
- 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();
- if (Type == PET_VIEW && BufferedVideo.IsValid() )
- {
- // If we're using bufferedVideo, submit the frame to it
- bNeedsRedraw = BufferedVideo->SubmitFrame(Width, Height, Buffer, Dirty);
- }
- else
- {
- UpdatableTextures[Type]->UpdateTextureThreadSafeRaw(Width, Height, Buffer, Dirty);
- HandleRenderingError();
- if (Type == PET_POPUP && bShowPopupRequested)
- {
- bShowPopupRequested = false;
- bPopupHasFocus = true;
- const float DPIScale = FPlatformApplicationMisc::GetDPIScaleFactorAtPoint(PopupPosition.X, PopupPosition.Y);
- FIntPoint PopupSize = FIntPoint(Width / DPIScale, Height / DPIScale);
- FIntRect PopupRect = FIntRect(PopupPosition, PopupPosition + PopupSize);
- OnShowPopup().Broadcast(PopupRect);
- }
- bNeedsRedraw = true;
- }
- }
- bIsInitialized = true;
- if (bNeedsRedraw)
- {
- NeedsRedrawEvent.Broadcast();
- }
- }
- void FCEFWebInterfaceBrowserWindow::OnAcceleratedPaint(CefRenderHandler::PaintElementType Type, const CefRenderHandler::RectList& DirtyRects, void* SharedHandle)
- {
- bool bNeedsRedraw = false;
- if (!bUsingAcceleratedPaint)
- {
- UE_LOG(LogWebInterfaceBrowser, Error, TEXT("Accelerated CEF rendering NOT selected but OnAcceleratedPaint called. Enabling accelerated rendering for this browser window."));
- bUsingAcceleratedPaint = true;
- if (UpdatableTextures[Type] != nullptr)
- {
- if (FSlateRenderer* const Renderer = GetRenderer())
- {
- Renderer->ReleaseUpdatableTexture(UpdatableTextures[Type]);
- HandleRenderingError();
- UpdatableTextures[Type] = nullptr;
- }
- }
- }
- #if PLATFORM_MAC
- // an IOSurface backs the handle here and its texture is automatically updated if changed, so we only need to
- // update our texture if the backing handle itself changed
- if (LastPaintedSharedHandle == SharedHandle)
- return;
- LastPaintedSharedHandle = SharedHandle;
- #endif
- 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();
- if (UpdatableTextures[Type] == nullptr)
- {
- if (FSlateRenderer* const Renderer = GetRenderer())
- {
- if (RHIRenderHelper)
- {
- UpdatableTextures[Type] = RHIRenderHelper->CreateTexture(SharedHandle);
- }
- else
- {
- UpdatableTextures[Type] = Renderer->CreateSharedHandleTexture(SharedHandle);
- }
- Dirty = FIntRect(); // force a fully copy when we make a new texture
- HandleRenderingError();
- }
- }
- if (UpdatableTextures[Type] != nullptr)
- {
- #if PLATFORM_WINDOWS
- if (RHIRenderHelper)
- {
- RHIRenderHelper->UpdateSharedHandleTexture(SharedHandle, UpdatableTextures[Type], Dirty.Scale(ViewportDPIScaleFactor));
- }
- else
- {
- UpdatableTextures[Type]->UpdateTextureThreadSafeWithKeyedTextureHandle(SharedHandle, 1, 0, Dirty.Scale(ViewportDPIScaleFactor));
- }
- #else
- UpdatableTextures[Type]->UpdateTextureThreadSafeWithKeyedTextureHandle(SharedHandle, 1, 0, Dirty.Scale(ViewportDPIScaleFactor));
- #endif
- bNeedsRedraw = true;
- if (Type == PET_POPUP && bShowPopupRequested)
- {
- bShowPopupRequested = false;
- bPopupHasFocus = true;
- const float DPIScale = FPlatformApplicationMisc::GetDPIScaleFactorAtPoint(PopupPosition.X, PopupPosition.Y);
- FIntPoint PopupSize = FIntPoint(UpdatableTextures[Type]->GetSlateResource()->GetWidth() / DPIScale, UpdatableTextures[Type]->GetSlateResource()->GetHeight() / DPIScale);
- FIntRect PopupRect = FIntRect(PopupPosition, PopupPosition + PopupSize);
- OnShowPopup().Broadcast(PopupRect);
- }
- }
- bIsInitialized = true;
- if (bNeedsRedraw)
- {
- NeedsRedrawEvent.Broadcast();
- }
- }
- void FCEFWebInterfaceBrowserWindow::UpdateVideoBuffering()
- {
- if (BufferedVideo.IsValid() && UpdatableTextures[PET_VIEW] != nullptr )
- {
- FSlateTextureData* SlateTextureData = BufferedVideo->GetNextFrameTextureData();
- if (SlateTextureData != nullptr )
- {
- UpdatableTextures[PET_VIEW]->UpdateTextureThreadSafeWithTextureData(SlateTextureData);
- HandleRenderingError();
- }
- }
- }
- #if PLATFORM_WINDOWS
- bool FCEFWebInterfaceBrowserWindow::LoadCustomCEF3Cursor(cef_cursor_type_t Type)
- {
- // generated from the ui_unscaled_resources.h file in a CEF build
- #define IDC_PAN_EAST 25846
- #define IDC_PAN_MIDDLE 25847
- #define IDC_PAN_MIDDLE_HORIZONTAL 25848
- #define IDC_PAN_MIDDLE_VERTICAL 25849
- #define IDC_PAN_NORTH 25850
- #define IDC_PAN_NORTH_EAST 25851
- #define IDC_PAN_NORTH_WEST 25852
- #define IDC_PAN_SOUTH 25853
- #define IDC_PAN_SOUTH_EAST 25854
- #define IDC_PAN_SOUTH_WEST 25855
- #define IDC_PAN_WEST 25856
- HINSTANCE CEF3ModuleHandle = (HINSTANCE)CEF3Utils::GetCEF3ModuleHandle();
- if (CEF3ModuleHandle != nullptr)
- {
- HCURSOR customCursor = 0;
- switch (Type) {
- case CT_MIDDLE_PANNING_HORIZONTAL:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE_HORIZONTAL));
- break;
- case CT_MIDDLE_PANNING_VERTICAL:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE_VERTICAL));
- break;
- case CT_MIDDLEPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_MIDDLE));
- break;
- case CT_SOUTHPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH));
- break;
- case CT_NORTHPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH));
- break;
- case CT_EASTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_EAST));
- break;
- case CT_WESTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_WEST));
- break;
- case CT_NORTHEASTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH_EAST));
- break;
- case CT_NORTHWESTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_NORTH_WEST));
- break;
- case CT_SOUTHEASTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH_EAST));
- break;
- case CT_SOUTHWESTPANNING:
- customCursor = LoadCursor(CEF3ModuleHandle, MAKEINTRESOURCE(IDC_PAN_SOUTH_WEST));
- break;
- }
-
- if (customCursor)
- {
- TSharedPtr<ICursor> PlatformCursor = FSlateApplication::Get().GetPlatformCursor();
- if (PlatformCursor.IsValid())
- {
- PlatformCursor->SetTypeShape(EMouseCursor::Custom, (void*)customCursor);
- Cursor = EMouseCursor::Custom;
- ::SetCursor(customCursor);
- }
- return true;
- }
- }
- return false;
- }
- #endif
- bool FCEFWebInterfaceBrowserWindow::OnCursorChange(CefCursorHandle CefCursor, cef_cursor_type_t Type, const CefCursorInfo& CustomCursorInfo)
- {
- #if PLATFORM_WINDOWS || PLATFORM_MAC
- if (bUseNativeCursors)
- {
- switch (Type) {
- // Map the basic 3 cursor types directly to Slate types on all platforms
- case CT_NONE:
- Cursor = EMouseCursor::None;
- break;
- case CT_POINTER:
- Cursor = EMouseCursor::Default;
- break;
- case CT_IBEAM:
- Cursor = EMouseCursor::TextEditBeam;
- break;
- default:
- // Platform specific support for native cursor types
- {
- #if PLATFORM_WINDOWS
- // check if we have a cursor in libcef.dll we can use
- if (LoadCustomCEF3Cursor(Type))
- return true;
- #endif
- TSharedPtr<ICursor> PlatformCursor = FSlateApplication::Get().GetPlatformCursor();
- if (PlatformCursor.IsValid())
- {
- PlatformCursor->SetTypeShape(EMouseCursor::Custom, (void*)CefCursor);
- Cursor = EMouseCursor::Custom;
- }
- }
- break;
- }
- }
- else
- #endif
- switch (Type) {
- case CT_NONE:
- Cursor = EMouseCursor::None;
- break;
- case CT_POINTER:
- Cursor = EMouseCursor::Default;
- break;
- case CT_IBEAM:
- Cursor = EMouseCursor::TextEditBeam;
- break;
- case CT_VERTICALTEXT:
- Cursor = EMouseCursor::TextEditBeam;
- break;
- case CT_EASTRESIZE:
- case CT_WESTRESIZE:
- case CT_EASTWESTRESIZE:
- case CT_COLUMNRESIZE:
- Cursor = EMouseCursor::ResizeLeftRight;
- break;
- case CT_NORTHRESIZE:
- case CT_SOUTHRESIZE:
- case CT_NORTHSOUTHRESIZE:
- case CT_ROWRESIZE:
- Cursor = EMouseCursor::ResizeUpDown;
- break;
- case CT_NORTHWESTRESIZE:
- case CT_SOUTHEASTRESIZE:
- case CT_NORTHWESTSOUTHEASTRESIZE:
- Cursor = EMouseCursor::ResizeSouthEast;
- break;
- case CT_NORTHEASTRESIZE:
- case CT_SOUTHWESTRESIZE:
- case CT_NORTHEASTSOUTHWESTRESIZE:
- Cursor = EMouseCursor::ResizeSouthWest;
- break;
- case CT_MOVE:
- case CT_MIDDLEPANNING:
- case CT_EASTPANNING:
- case CT_NORTHPANNING:
- case CT_NORTHEASTPANNING:
- case CT_NORTHWESTPANNING:
- case CT_SOUTHPANNING:
- case CT_SOUTHEASTPANNING:
- case CT_SOUTHWESTPANNING:
- case CT_WESTPANNING:
- Cursor = EMouseCursor::CardinalCross;
- break;
- case CT_CROSS:
- Cursor = EMouseCursor::Crosshairs;
- break;
- case CT_HAND:
- Cursor = EMouseCursor::Hand;
- break;
- case CT_GRAB:
- Cursor = EMouseCursor::GrabHand;
- break;
- case CT_GRABBING:
- Cursor = EMouseCursor::GrabHandClosed;
- break;
- case CT_NOTALLOWED:
- case CT_NODROP:
- Cursor = EMouseCursor::SlashedCircle;
- break;
- default:
- Cursor = EMouseCursor::Default;
- break;
- }
- // Tell Slate to update the cursor now
- FSlateApplication::Get().QueryCursor();
- return false;
- }
- EWebInterfaceTransitionSource _TransitionTypeToSourceEnum(const CefRequest::TransitionType& Type)
- {
- CefRequest::TransitionType TransitionSource = (CefRequest::TransitionType)(Type & TT_SOURCE_MASK);
- switch (TransitionSource)
- {
- case TT_LINK: return EWebInterfaceTransitionSource::Link;
- case TT_EXPLICIT: return EWebInterfaceTransitionSource::Explicit;
- case TT_AUTO_SUBFRAME: return EWebInterfaceTransitionSource::AutoSubframe;
- case TT_FORM_SUBMIT: return EWebInterfaceTransitionSource::FormSubmit;
- case TT_RELOAD: return EWebInterfaceTransitionSource::Reload;
- default: return EWebInterfaceTransitionSource::Unknown;
- }
- return EWebInterfaceTransitionSource::Unknown;
- }
- EWebInterfaceTransitionSourceQualifier _TransitionTypeToSourceQualifierEnum(const CefRequest::TransitionType& Type)
- {
- CefRequest::TransitionType TransitionSourceQualifier = (CefRequest::TransitionType)(Type & TT_QUALIFIER_MASK);
- switch (TransitionSourceQualifier)
- {
- case TT_BLOCKED_FLAG: return EWebInterfaceTransitionSourceQualifier::Blocked;
- case TT_FORWARD_BACK_FLAG: return EWebInterfaceTransitionSourceQualifier::ForwardBack;
- case TT_CHAIN_START_FLAG: return EWebInterfaceTransitionSourceQualifier::ChainStart;
- case TT_CHAIN_END_FLAG: return EWebInterfaceTransitionSourceQualifier::ChainEnd;
- case TT_CLIENT_REDIRECT_FLAG: return EWebInterfaceTransitionSourceQualifier::ClientRedirect;
- case TT_SERVER_REDIRECT_FLAG: return EWebInterfaceTransitionSourceQualifier::ServerRedirect;
- default: return EWebInterfaceTransitionSourceQualifier::Unknown;
- }
- return EWebInterfaceTransitionSourceQualifier::Unknown;
- }
- bool FCEFWebInterfaceBrowserWindow::OnBeforeBrowse( CefRefPtr<CefBrowser> Browser, CefRefPtr<CefFrame> Frame, CefRefPtr<CefRequest> Request, bool user_gesture, bool bIsRedirect )
- {
- if (InternalCefBrowser != nullptr && InternalCefBrowser->IsSame(Browser))
- {
- CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
- if (MainFrame.get() != nullptr)
- {
- if(OnBeforeBrowse().IsBound())
- {
- FString Url = WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str());
- bool bIsMainFrame = Frame->IsMain();
- FWebNavigationRequest RequestDetails;
- RequestDetails.bIsRedirect = bIsRedirect;
- RequestDetails.bIsMainFrame = bIsMainFrame;
- RequestDetails.bIsExplicitTransition = Request->GetTransitionType() == TT_EXPLICIT;
- const CefRequest::TransitionType RequestTransitionType = Request->GetTransitionType();
- RequestDetails.TransitionSource = _TransitionTypeToSourceEnum(RequestTransitionType);
- RequestDetails.TransitionSourceQualifier = _TransitionTypeToSourceQualifierEnum(RequestTransitionType);
- RequestDetails.bIsExplicitTransition = RequestDetails.TransitionSource == EWebInterfaceTransitionSource::Explicit;
-
- if (bIsMainFrame)
- {
- // We need to defer all future navigations until we can determine if this current navigation is going to be handled or not
- bDeferNavigations = true;
- }
- bool bHandled = OnBeforeBrowse().Execute(Url, RequestDetails);
- if (bIsMainFrame)
- {
- // 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
- bDeferNavigations = bHandled && !bIsRedirect;
- if (bDeferNavigations)
- {
- PendingAbortUrl = Url;
- }
- else if (HasPendingNavigation())
- {
- ProcessPendingNavigation();
- }
- }
- return bHandled;
- }
- }
- }
- return false;
- }
- FString _URLRequestStatusToString(const CefResourceRequestHandler::URLRequestStatus& Status)
- {
- const static FString URLRequestStatus_Success(TEXT("SUCCESS"));
- const static FString URLRequestStatus_IoPending(TEXT("IO_PENDING"));
- const static FString URLRequestStatus_Canceled(TEXT("CANCELED"));
- const static FString URLRequestStatus_Failed(TEXT("FAILED"));
- const static FString URLRequestStatus_Unknown(TEXT("UNKNOWN"));
- FString StatusStr;
- switch (Status)
- {
- case CefResourceRequestHandler::URLRequestStatus::UR_SUCCESS:
- StatusStr = URLRequestStatus_Success;
- break;
- case CefResourceRequestHandler::URLRequestStatus::UR_IO_PENDING:
- StatusStr = URLRequestStatus_IoPending;
- break;
- case CefResourceRequestHandler::URLRequestStatus::UR_CANCELED:
- StatusStr = URLRequestStatus_Canceled;
- break;
- case CefResourceRequestHandler::URLRequestStatus::UR_FAILED:
- StatusStr = URLRequestStatus_Failed;
- break;
- case CefResourceRequestHandler::URLRequestStatus::UR_UNKNOWN:
- StatusStr = URLRequestStatus_Unknown;
- break;
- default:
- StatusStr = URLRequestStatus_Unknown;
- break;
- }
- return StatusStr;
- }
- void FCEFWebInterfaceBrowserWindow::HandleOnBeforeResourceLoad(const CefString& URL, CefRequest::ResourceType Type, FRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials)
- {
- BeforeResourceLoadDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(URL.ToWString().c_str()), _ResourceTypeToString(Type), AdditionalHeaders, AllowUserCredentials);
- }
- void FCEFWebInterfaceBrowserWindow::HandleOnResourceLoadComplete(const CefString& URL, CefRequest::ResourceType Type, CefResourceRequestHandler::URLRequestStatus Status, int64 ContentLength)
- {
- ResourceLoadCompleteDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(URL.ToWString().c_str()), _ResourceTypeToString(Type), _URLRequestStatusToString(Status), ContentLength);
- }
- EWebInterfaceBrowserConsoleLogSeverity CefLogSeverityToWebBrowser(cef_log_severity_t Level)
- {
- switch (Level)
- {
- case LOGSEVERITY_VERBOSE:
- return EWebInterfaceBrowserConsoleLogSeverity::Verbose;
- //case LOGSEVERITY_DEBUG: // same as LOGSEVERITY_VERBOSE
- // return Verbose;
- case LOGSEVERITY_INFO:
- return EWebInterfaceBrowserConsoleLogSeverity::Info;
- case LOGSEVERITY_WARNING:
- return EWebInterfaceBrowserConsoleLogSeverity::Warning;
- case LOGSEVERITY_ERROR:
- return EWebInterfaceBrowserConsoleLogSeverity::Error;
- case LOGSEVERITY_FATAL:
- return EWebInterfaceBrowserConsoleLogSeverity::Fatal;
- case LOGSEVERITY_DEFAULT:
- default:
- return EWebInterfaceBrowserConsoleLogSeverity::Default;
- }
- }
- void FCEFWebInterfaceBrowserWindow::HandleOnConsoleMessage(CefRefPtr<CefBrowser> Browser, cef_log_severity_t Level, const CefString& Message, const CefString& Source, int32 Line)
- {
- ConsoleMessageDelegate.ExecuteIfBound(WCHAR_TO_TCHAR(Message.ToWString().c_str()), WCHAR_TO_TCHAR(Source.ToWString().c_str()), Line, CefLogSeverityToWebBrowser(Level));
- }
- TOptional<FString> FCEFWebInterfaceBrowserWindow::GetResourceContent( CefRefPtr< CefFrame > Frame, CefRefPtr< CefRequest > Request)
- {
- if (ContentsToLoad.IsSet())
- {
- FString Contents = ContentsToLoad.GetValue();
- ContentsToLoad.Reset();
- return Contents;
- }
- if (OnLoadUrl().IsBound())
- {
- FString Method = WCHAR_TO_TCHAR(Request->GetMethod().ToWString().c_str());
- FString Url = WCHAR_TO_TCHAR(Request->GetURL().ToWString().c_str());
- FString Response;
- if ( OnLoadUrl().Execute(Method, Url, Response))
- {
- return Response;
- }
- }
- return TOptional<FString>();
- }
- int32 FCEFWebInterfaceBrowserWindow::GetCefKeyboardModifiers(const FKeyEvent& KeyEvent)
- {
- int32 Modifiers = GetCefInputModifiers(KeyEvent);
- const FKey Key = KeyEvent.GetKey();
- if (Key == EKeys::LeftAlt ||
- Key == EKeys::LeftCommand ||
- Key == EKeys::LeftControl ||
- Key == EKeys::LeftShift)
- {
- Modifiers |= EVENTFLAG_IS_LEFT;
- }
- if (Key == EKeys::RightAlt ||
- Key == EKeys::RightCommand ||
- Key == EKeys::RightControl ||
- Key == EKeys::RightShift)
- {
- Modifiers |= EVENTFLAG_IS_RIGHT;
- }
- if (Key == EKeys::NumPadZero ||
- Key == EKeys::NumPadOne ||
- Key == EKeys::NumPadTwo ||
- Key == EKeys::NumPadThree ||
- Key == EKeys::NumPadFour ||
- Key == EKeys::NumPadFive ||
- Key == EKeys::NumPadSix ||
- Key == EKeys::NumPadSeven ||
- Key == EKeys::NumPadEight ||
- Key == EKeys::NumPadNine)
- {
- Modifiers |= EVENTFLAG_IS_KEY_PAD;
- }
- return Modifiers;
- }
- int32 FCEFWebInterfaceBrowserWindow::GetCefMouseModifiers(const FPointerEvent& InMouseEvent)
- {
- int32 Modifiers = GetCefInputModifiers(InMouseEvent);
- if (InMouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
- {
- Modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
- }
- if (InMouseEvent.IsMouseButtonDown(EKeys::MiddleMouseButton))
- {
- Modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
- }
- if (InMouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
- {
- Modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
- }
- return Modifiers;
- }
- CefMouseEvent FCEFWebInterfaceBrowserWindow::GetCefMouseEvent(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bIsPopup)
- {
- CefMouseEvent Event;
- FGeometry MouseGeometry = MyGeometry;
- if (bUsingAcceleratedPaint)
- {
- // undo the texture flip if we are using accelerated rendering
- MouseGeometry = MyGeometry.MakeChild(FSlateRenderTransform(FScale2D(1, -1)));
- }
- float DPIScale = MouseGeometry.Scale;
- if (TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin())
- {
- DPIScale /= ParentWindowPtr->GetNativeWindow()->GetDPIScaleFactor();
- }
- FVector2D LocalPos = MouseGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()) * DPIScale;
- if (bIsPopup)
- {
- LocalPos += PopupPosition;
- }
- Event.x = LocalPos.X;
- Event.y = LocalPos.Y;
- Event.modifiers = GetCefMouseModifiers(MouseEvent);
- return Event;
- }
- int32 FCEFWebInterfaceBrowserWindow::GetCefInputModifiers(const FInputEvent& InputEvent)
- {
- int32 Modifiers = 0;
- if (InputEvent.IsShiftDown())
- {
- Modifiers |= EVENTFLAG_SHIFT_DOWN;
- }
- if (InputEvent.IsControlDown())
- {
- #if PLATFORM_MAC
- // Slate swaps the flags for Command and Control on OSX, so we need to swap them back for CEF
- Modifiers |= EVENTFLAG_COMMAND_DOWN;
- #else
- Modifiers |= EVENTFLAG_CONTROL_DOWN;
- #endif
- }
- if (InputEvent.IsAltDown())
- {
- Modifiers |= EVENTFLAG_ALT_DOWN;
- }
- if (InputEvent.IsCommandDown())
- {
- #if PLATFORM_MAC
- // Slate swaps the flags for Command and Control on OSX, so we need to swap them back for CEF
- Modifiers |= EVENTFLAG_CONTROL_DOWN;
- #else
- Modifiers |= EVENTFLAG_COMMAND_DOWN;
- #endif
- }
- if (InputEvent.AreCapsLocked())
- {
- Modifiers |= EVENTFLAG_CAPS_LOCK_ON;
- }
- return Modifiers;
- }
- bool FCEFWebInterfaceBrowserWindow::CanSupportAcceleratedPaint()
- {
- static bool DisableAcceleratedPaint = FParse::Param(FCommandLine::Get(), TEXT("nocefaccelpaint"));
- if (DisableAcceleratedPaint)
- {
- return false;
- }
- static bool ForceAcceleratedPaint = FParse::Param(FCommandLine::Get(), TEXT("forcecefaccelpaint"));
- if (ForceAcceleratedPaint)
- {
- return true;
- }
- // Use off screen rendering so we can integrate with our windows
- #if PLATFORM_LINUX
- return false;
- #elif PLATFORM_WINDOWS
- #if PLATFORM_64BITS
- static bool Windows10OrAbove = FWindowsPlatformMisc::VerifyWindowsVersion(10, 0); //Win10
- if (Windows10OrAbove == false)
- {
- return false;
- }
- // match the logic in GetStandardStandaloneRenderer() from StandaloneRenderer.cpp to check for the OGL slate renderer
- if (FParse::Param(FCommandLine::Get(), TEXT("opengl")))
- {
- return false;
- }
- return true;
- #else
- return false; // 32-bit windows doesn't have the accelerated rendering patches applied, it can be done if needed
- #endif
- #elif PLATFORM_MAC
- return false; // Needs RHI support for the CreateSharedHandleTexture call
- #else
- return false;
- #endif
- }
- void FCEFWebInterfaceBrowserWindow::UpdateCachedGeometry(const FGeometry& AllottedGeometry)
- {
- #if !PLATFORM_LINUX
- // Forward along the geometry for use by IME
- Ime->UpdateCachedGeometry(AllottedGeometry);
- #endif
- if (RHIRenderHelper)
- {
- RHIRenderHelper->UpdateCachedGeometry(AllottedGeometry);
- }
- }
- void FCEFWebInterfaceBrowserWindow::CheckTickActivity()
- {
- // Early out if we're currently hidden, not initialized or currently loading.
- if (bIsHidden || !IsValid() || IsLoading() || ViewportSize == FIntPoint::ZeroValue)
- {
- return;
- }
- // We clear the bTickedLastFrame flag here and set it on every Slate tick.
- // If it's still clear when we come back it means we're not getting ticks from slate.
- // Note: The BrowserSingleton object will not invoke this method if Slate itself is sleeping.
- // Therefore we can safely assume the widget is hidden in that case.
- if (!bTickedLastFrame)
- {
- SetIsHidden(true);
- }
- else if(bNeedsResize)
- {
- bNeedsResize = false;
- InternalCefBrowser->GetHost()->WasResized();
- }
- bTickedLastFrame = false;
- }
- void FCEFWebInterfaceBrowserWindow::RequestNavigationInternal(FString Url, FString Contents)
- {
- if (!IsValid())
- {
- return;
- }
- CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
- if (MainFrame.get() != nullptr)
- {
- ContentsToLoad = Contents.IsEmpty() ? TOptional<FString>() : Contents;
- PendingLoadUrl = Url;
- if (!bDeferNavigations)
- {
- ProcessPendingNavigation();
- }
- }
- }
- bool FCEFWebInterfaceBrowserWindow::HasPendingNavigation()
- {
- return !PendingLoadUrl.IsEmpty();
- }
- void FCEFWebInterfaceBrowserWindow::ProcessPendingNavigation()
- {
- if (!IsValid() || bDeferNavigations || !HasPendingNavigation())
- {
- return;
- }
- CefRefPtr<CefFrame> MainFrame = InternalCefBrowser->GetMainFrame();
- if (MainFrame.get() != nullptr)
- {
- CefString Url = TCHAR_TO_WCHAR(*PendingLoadUrl);
- PendingLoadUrl.Empty();
- #if PLATFORM_MAC
- if ([NSThread isMainThread])
- {
- MainFrame->LoadURL(Url);
- }
- else
- {
- MainThreadCall(^{
- MainFrame->LoadURL(Url);
- }, NSDefaultRunLoopMode, true);
- }
- #else
- MainFrame->LoadURL(Url);
- #endif
- }
- }
- void FCEFWebInterfaceBrowserWindow::SetIsHidden(bool bValue)
- {
- if( bIsHidden == bValue )
- {
- return;
- }
- bIsHidden = bValue;
- if ( IsValid() )
- {
- CefRefPtr<CefBrowserHost> BrowserHost = InternalCefBrowser->GetHost();
- #if PLATFORM_WINDOWS
- HWND NativeWindowHandle = BrowserHost->GetWindowHandle();
- if (NativeWindowHandle != nullptr)
- {
- // When rendering directly into a subwindow, we must hide the native window when fully obscured
- ::ShowWindow(NativeWindowHandle, bIsHidden ? SW_HIDE : SW_SHOW);
- if (bIsHidden )
- {
- TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
- if (::IsWindowEnabled(NativeWindowHandle) && ParentWindowPtr.IsValid())
- {
- ::SetFocus((HWND)ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle());
- }
- // when hidden also resize the window to 0x0 to further reduce resource usage. This copies the
- // behavior of the CefClient code, see browser_window_std_win.cc in the ::Hide() function. This code
- // is also required for the HTML5 visibility API to work
- SetWindowPos(NativeWindowHandle, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
- }
- else
- {
- // restore the window to its right size/position
- HWND Parent = ::GetParent(NativeWindowHandle);
- // Position is in screen coordinates, so we'll need to get the parent window location first.
- RECT ParentRect = { 0, 0, 0, 0 };
- if (Parent)
- {
- ::GetWindowRect(Parent, &ParentRect);
- }
- FIntPoint WindowSizeScaled = (FVector2D(ViewportSize) * ViewportDPIScaleFactor).IntPoint();
- ::SetWindowPos(NativeWindowHandle, 0, ViewportPos.X - ParentRect.left, ViewportPos.Y - ParentRect.top, WindowSizeScaled.X, WindowSizeScaled.Y, 0);
- }
- }
- else
- {
- #elif PLATFORM_MAC
- CefWindowHandle NativeWindowHandle = BrowserHost->GetWindowHandle();
- if (NativeWindowHandle != nullptr)
- {
- NSView *browserView = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(NativeWindowHandle);
- if(bIsHidden)
- {
- [browserView setHidden:YES];
- }
- else
- {
- [browserView setHidden:NO];
- }
-
- }
- else
- {
- #endif
- BrowserHost->WasHidden(bIsHidden);
- #if PLATFORM_WINDOWS || PLATFORM_MAC
- }
- #endif
- }
- }
- void FCEFWebInterfaceBrowserWindow::SetIsDisabled(bool bValue)
- {
- if (bIsDisabled == bValue)
- {
- return;
- }
- bIsDisabled = bValue;
- SetIsHidden(bIsDisabled);
- }
- TSharedPtr<SWindow> FCEFWebInterfaceBrowserWindow::GetParentWindow() const
- {
- TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
- return ParentWindowPtr;
- }
- void FCEFWebInterfaceBrowserWindow::SetParentWindow(TSharedPtr<SWindow> Window)
- {
- ParentWindow = Window;
- #if PLATFORM_WINDOWS
- if (IsValid())
- {
- CefRefPtr<CefBrowserHost> BrowserHost = InternalCefBrowser->GetHost();
- HWND NativeWindowHandle = BrowserHost->GetWindowHandle();
- if (NativeWindowHandle != nullptr)
- {
- TSharedPtr<SWindow> ParentWindowPtr = ParentWindow.Pin();
- void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindowPtr->GetNativeWindow().IsValid()) ? ParentWindowPtr->GetNativeWindow()->GetOSWindowHandle() : nullptr;
- if (ParentWindowHandle != nullptr)
- {
- // When rendering directly to a HWND update its parent windown
- ::SetParent(NativeWindowHandle, (HWND)ParentWindowHandle);
- }
- }
- }
- #endif
- }
- CefRefPtr<CefDictionaryValue> FCEFWebInterfaceBrowserWindow::GetProcessInfo()
- {
- CefRefPtr<CefDictionaryValue> Retval = nullptr;
- if (IsValid())
- {
- Retval = CefDictionaryValue::Create();
- Retval->SetInt("browser", InternalCefBrowser->GetIdentifier());
- Retval->SetDictionary("bindings", Scripting->GetPermanentBindings());
- }
- return Retval;
- }
- bool FCEFWebInterfaceBrowserWindow::OnProcessMessageReceived(CefRefPtr<CefBrowser> Browser, CefRefPtr<CefFrame> frame, CefProcessId SourceProcess, CefRefPtr<CefProcessMessage> Message)
- {
- bool bHandled = Scripting->OnProcessMessageReceived(Browser, SourceProcess, Message);
- if (!bHandled)
- {
- #if PLATFORM_MAC
- if (!bInDirectHwndMode) // IME is handled by the CEF control in direct render mode
- {
- bHandled = Ime->OnProcessMessageReceived(Browser, SourceProcess, Message);
- }
- #elif PLATFORM_WINDOWS
- bHandled = Ime->OnProcessMessageReceived(Browser, SourceProcess, Message);
- #endif
- }
-
- return bHandled;
- }
- void FCEFWebInterfaceBrowserWindow::BindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
- {
- Scripting->BindUObject(Name, Object, bIsPermanent);
- }
- void FCEFWebInterfaceBrowserWindow::UnbindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
- {
- Scripting->UnbindUObject(Name, Object, bIsPermanent);
- }
- void FCEFWebInterfaceBrowserWindow::BindInputMethodSystem(ITextInputMethodSystem* TextInputMethodSystem)
- {
- #if !PLATFORM_LINUX
- Ime->BindInputMethodSystem(TextInputMethodSystem);
- #endif
- }
- void FCEFWebInterfaceBrowserWindow::UnbindInputMethodSystem()
- {
- #if !PLATFORM_LINUX
- Ime->UnbindInputMethodSystem();
- #endif
- }
- void FCEFWebInterfaceBrowserWindow::OnBrowserClosing()
- {
- bIsClosing = true;
- }
- void FCEFWebInterfaceBrowserWindow::OnBrowserClosed()
- {
- if(OnCloseWindow().IsBound())
- {
- OnCloseWindow().Execute(TWeakPtr<IWebInterfaceBrowserWindow>(SharedThis(this)));
- }
- Scripting->UnbindCefBrowser();
- #if !PLATFORM_LINUX
- Ime->UnbindCefBrowser();
- #endif
- InternalCefBrowser = nullptr;
- }
- void FCEFWebInterfaceBrowserWindow::SetPopupMenuPosition(CefRect CefPopupSize)
- {
- // We only store the position, as the size will be provided ib the OnPaint call.
- PopupPosition = FIntPoint(CefPopupSize.x, CefPopupSize.y);
- }
- void FCEFWebInterfaceBrowserWindow:: ShowPopupMenu(bool bShow)
- {
- if (bShow)
- {
- bShowPopupRequested = true; // We have to delay showing the popup until we get the first OnPaint on it.
- }
- else
- {
- bPopupHasFocus = false;
- bShowPopupRequested = false;
- OnDismissPopup().Broadcast();
- }
- }
- void FCEFWebInterfaceBrowserWindow::OnImeCompositionRangeChanged(
- CefRefPtr<CefBrowser> Browser,
- const CefRange& SelectionRange,
- const CefRenderHandler::RectList& CharacterBounds)
- {
- if (InternalCefBrowser != nullptr && InternalCefBrowser->IsSame(Browser))
- {
- #if !PLATFORM_LINUX
- Ime->CEFCompositionRangeChanged(SelectionRange, CharacterBounds);
- #endif
- }
- }
- void FCEFWebInterfaceBrowserWindow::UpdateDragRegions(const TArray<FWebInterfaceBrowserDragRegion>& Regions)
- {
- DragRegions = Regions;
- }
- bool FCEFWebInterfaceBrowserWindow::IsInDragRegion(const FIntPoint& Point)
- {
- // Here we traverse the array of drag regions backwards because we assume the drag regions are z ordered such that
- // the end of the list contains the drag regions of the top most elements of the web page. We can stop checking
- // once we hit a region that contains our point.
- for (int32 Idx = DragRegions.Num() - 1; Idx >= 0; --Idx)
- {
- if (DragRegions[Idx].Rect.Contains(Point))
- {
- return DragRegions[Idx].bDraggable;
- }
- }
- return false;
- }
- #endif
|